amdgpu_kms.c revision 46845023
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);
28646845023Smrg			free(pAMDGPUEnt->busid);
28724b90cf4Smrg			free(pPriv->ptr);
28824b90cf4Smrg			pPriv->ptr = NULL;
289d6c0b56eSmrg		}
290d6c0b56eSmrg	}
291d6c0b56eSmrg
29224b90cf4Smrg	free(pEnt);
293d6c0b56eSmrg}
294d6c0b56eSmrg
29590f2b693SmrgBool amdgpu_window_has_variable_refresh(WindowPtr win) {
29690f2b693Smrg	struct amdgpu_window_priv *priv = get_window_priv(win);
29790f2b693Smrg
29890f2b693Smrg	return priv->variable_refresh;
29990f2b693Smrg}
30090f2b693Smrg
301d6c0b56eSmrgstatic void *amdgpuShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset,
302d6c0b56eSmrg				int mode, CARD32 * size, void *closure)
303d6c0b56eSmrg{
304d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
305d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
306d6c0b56eSmrg	int stride;
307d6c0b56eSmrg
308d6c0b56eSmrg	stride = (pScrn->displayWidth * pScrn->bitsPerPixel) / 8;
309d6c0b56eSmrg	*size = stride;
310d6c0b56eSmrg
311d6c0b56eSmrg	return ((uint8_t *) info->front_buffer->cpu_ptr + row * stride + offset);
312d6c0b56eSmrg}
313d6c0b56eSmrg
314d6c0b56eSmrgstatic void
315d6c0b56eSmrgamdgpuUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
316d6c0b56eSmrg{
317d6c0b56eSmrg	shadowUpdatePacked(pScreen, pBuf);
318d6c0b56eSmrg}
319d6c0b56eSmrg
320504d986fSmrgstatic Bool
321504d986fSmrgcallback_needs_flush(AMDGPUInfoPtr info, struct amdgpu_client_priv *client_priv)
322504d986fSmrg{
323504d986fSmrg	return (int)(client_priv->needs_flush - info->gpu_flushed) > 0;
324504d986fSmrg}
325504d986fSmrg
326504d986fSmrgstatic void
327504d986fSmrgamdgpu_event_callback(CallbackListPtr *list,
328504d986fSmrg		      pointer user_data, pointer call_data)
329504d986fSmrg{
330504d986fSmrg	EventInfoRec *eventinfo = call_data;
331504d986fSmrg	ScrnInfoPtr pScrn = user_data;
332504d986fSmrg	ScreenPtr pScreen = pScrn->pScreen;
333504d986fSmrg	struct amdgpu_client_priv *client_priv =
334504d986fSmrg		dixLookupScreenPrivate(&eventinfo->client->devPrivates,
335504d986fSmrg				       &amdgpu_client_private_key, pScreen);
336504d986fSmrg	struct amdgpu_client_priv *server_priv =
337504d986fSmrg		dixLookupScreenPrivate(&serverClient->devPrivates,
338504d986fSmrg				       &amdgpu_client_private_key, pScreen);
339504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
340504d986fSmrg	int i;
341504d986fSmrg
342504d986fSmrg	if (callback_needs_flush(info, client_priv) ||
343504d986fSmrg	    callback_needs_flush(info, server_priv))
344504d986fSmrg		return;
345504d986fSmrg
346504d986fSmrg	/* Don't let gpu_flushed get too far ahead of needs_flush, in order
347504d986fSmrg	 * to prevent false positives in callback_needs_flush()
348504d986fSmrg	 */
349504d986fSmrg	client_priv->needs_flush = info->gpu_flushed;
350504d986fSmrg	server_priv->needs_flush = info->gpu_flushed;
351504d986fSmrg
352504d986fSmrg	for (i = 0; i < eventinfo->count; i++) {
353504d986fSmrg		if (eventinfo->events[i].u.u.type == info->callback_event_type) {
354504d986fSmrg			client_priv->needs_flush++;
355504d986fSmrg			server_priv->needs_flush++;
356504d986fSmrg			return;
357504d986fSmrg		}
358504d986fSmrg	}
359504d986fSmrg}
360504d986fSmrg
361504d986fSmrgstatic void
362504d986fSmrgamdgpu_flush_callback(CallbackListPtr *list,
363504d986fSmrg		      pointer user_data, pointer call_data)
364504d986fSmrg{
365504d986fSmrg	ScrnInfoPtr pScrn = user_data;
366504d986fSmrg	ScreenPtr pScreen = pScrn->pScreen;
367504d986fSmrg	ClientPtr client = call_data ? call_data : serverClient;
368504d986fSmrg	struct amdgpu_client_priv *client_priv =
369504d986fSmrg		dixLookupScreenPrivate(&client->devPrivates,
370504d986fSmrg				       &amdgpu_client_private_key, pScreen);
371504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
372504d986fSmrg
373504d986fSmrg	if (pScrn->vtSema && callback_needs_flush(info, client_priv))
374504d986fSmrg		amdgpu_glamor_flush(pScrn);
375504d986fSmrg}
376504d986fSmrg
377d6c0b56eSmrgstatic Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen)
378d6c0b56eSmrg{
37911bf0794Smrg	ExtensionEntry *damage_ext;
380d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
381d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
382d6c0b56eSmrg	PixmapPtr pixmap;
383d6c0b56eSmrg
384d6c0b56eSmrg	pScreen->CreateScreenResources = info->CreateScreenResources;
385d6c0b56eSmrg	if (!(*pScreen->CreateScreenResources) (pScreen))
386d6c0b56eSmrg		return FALSE;
387d6c0b56eSmrg	pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS;
388d6c0b56eSmrg
389d6c0b56eSmrg	/* Set the RandR primary output if Xorg hasn't */
390504d986fSmrg	if (dixPrivateKeyRegistered(rrPrivKey)) {
391504d986fSmrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(pScreen);
392504d986fSmrg
39324b90cf4Smrg		if (!pScreen->isGPU && !rrScrPriv->primaryOutput) {
394504d986fSmrg			xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
395d6c0b56eSmrg
396504d986fSmrg			rrScrPriv->primaryOutput = xf86_config->output[0]->randr_output;
397504d986fSmrg			RROutputChanged(rrScrPriv->primaryOutput, FALSE);
398504d986fSmrg			rrScrPriv->layoutChanged = TRUE;
399504d986fSmrg		}
40090f2b693Smrg
40190f2b693Smrg		drmmode_uevent_init(pScrn, &info->drmmode);
402d6c0b56eSmrg	}
403d6c0b56eSmrg
40424b90cf4Smrg	if (!drmmode_set_desired_modes(pScrn, &info->drmmode, pScreen->isGPU))
405d6c0b56eSmrg		return FALSE;
406d6c0b56eSmrg
407d6c0b56eSmrg	if (info->shadow_fb) {
408d6c0b56eSmrg		pixmap = pScreen->GetScreenPixmap(pScreen);
409d6c0b56eSmrg
410d6c0b56eSmrg		if (!shadowAdd(pScreen, pixmap, amdgpuUpdatePacked,
411d6c0b56eSmrg			       amdgpuShadowWindow, 0, NULL))
412d6c0b56eSmrg			return FALSE;
413d6c0b56eSmrg	}
414d6c0b56eSmrg
415d6c0b56eSmrg	if (info->dri2.enabled || info->use_glamor) {
416d6c0b56eSmrg		if (info->front_buffer) {
417d6c0b56eSmrg			PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen);
418504d986fSmrg
419504d986fSmrg			if (!amdgpu_set_pixmap_bo(pPix, info->front_buffer))
420504d986fSmrg				return FALSE;
421d6c0b56eSmrg		}
422d6c0b56eSmrg	}
423d6c0b56eSmrg
424d6c0b56eSmrg	if (info->use_glamor)
425d6c0b56eSmrg		amdgpu_glamor_create_screen_resources(pScreen);
426d6c0b56eSmrg
427504d986fSmrg	info->callback_event_type = -1;
42824b90cf4Smrg	if (!pScreen->isGPU && (damage_ext = CheckExtension("DAMAGE"))) {
429504d986fSmrg		info->callback_event_type = damage_ext->eventBase + XDamageNotify;
430504d986fSmrg
431504d986fSmrg		if (!AddCallback(&FlushCallback, amdgpu_flush_callback, pScrn))
432504d986fSmrg			return FALSE;
433504d986fSmrg
434504d986fSmrg		if (!AddCallback(&EventCallback, amdgpu_event_callback, pScrn)) {
435504d986fSmrg			DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
436504d986fSmrg			return FALSE;
437504d986fSmrg		}
438504d986fSmrg
439504d986fSmrg		if (!dixRegisterScreenPrivateKey(&amdgpu_client_private_key, pScreen,
440504d986fSmrg						 PRIVATE_CLIENT, sizeof(struct amdgpu_client_priv))) {
441504d986fSmrg			DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
442504d986fSmrg			DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn);
443504d986fSmrg			return FALSE;
444504d986fSmrg		}
445504d986fSmrg	}
446504d986fSmrg
44790f2b693Smrg	if (info->vrr_support &&
44890f2b693Smrg	    !dixRegisterPrivateKey(&amdgpu_window_private_key,
44990f2b693Smrg				   PRIVATE_WINDOW,
45090f2b693Smrg				   sizeof(struct amdgpu_window_priv)))
45190f2b693Smrg		return FALSE;
45290f2b693Smrg
453d6c0b56eSmrg	return TRUE;
454d6c0b56eSmrg}
455d6c0b56eSmrg
456504d986fSmrgstatic Bool
457504d986fSmrgamdgpu_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents)
458504d986fSmrg{
45911bf0794Smrg	if (xf86_crtc->scrn->is_gpu) {
46011bf0794Smrg		extents->x1 -= xf86_crtc->x;
46111bf0794Smrg		extents->y1 -= xf86_crtc->y;
46211bf0794Smrg		extents->x2 -= xf86_crtc->x;
46311bf0794Smrg		extents->y2 -= xf86_crtc->y;
46424b90cf4Smrg	} else {
46511bf0794Smrg		extents->x1 -= xf86_crtc->filter_width >> 1;
46611bf0794Smrg		extents->x2 += xf86_crtc->filter_width >> 1;
46711bf0794Smrg		extents->y1 -= xf86_crtc->filter_height >> 1;
46811bf0794Smrg		extents->y2 += xf86_crtc->filter_height >> 1;
46911bf0794Smrg		pixman_f_transform_bounds(&xf86_crtc->f_framebuffer_to_crtc, extents);
47011bf0794Smrg	}
471504d986fSmrg
472504d986fSmrg	extents->x1 = max(extents->x1, 0);
473504d986fSmrg	extents->y1 = max(extents->y1, 0);
474504d986fSmrg	extents->x2 = min(extents->x2, xf86_crtc->mode.HDisplay);
475504d986fSmrg	extents->y2 = min(extents->y2, xf86_crtc->mode.VDisplay);
476504d986fSmrg
477504d986fSmrg	return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
478504d986fSmrg}
479504d986fSmrg
480504d986fSmrgstatic RegionPtr
481504d986fSmrgtransform_region(RegionPtr region, struct pict_f_transform *transform,
482504d986fSmrg		 int w, int h)
483504d986fSmrg{
484504d986fSmrg	BoxPtr boxes = RegionRects(region);
485504d986fSmrg	int nboxes = RegionNumRects(region);
486504d986fSmrg	xRectanglePtr rects = malloc(nboxes * sizeof(*rects));
487504d986fSmrg	RegionPtr transformed;
488504d986fSmrg	int nrects = 0;
489504d986fSmrg	BoxRec box;
490504d986fSmrg	int i;
491504d986fSmrg
492504d986fSmrg	for (i = 0; i < nboxes; i++) {
493504d986fSmrg		box.x1 = boxes[i].x1;
494504d986fSmrg		box.x2 = boxes[i].x2;
495504d986fSmrg		box.y1 = boxes[i].y1;
496504d986fSmrg		box.y2 = boxes[i].y2;
497504d986fSmrg		pixman_f_transform_bounds(transform, &box);
498504d986fSmrg
499504d986fSmrg		box.x1 = max(box.x1, 0);
500504d986fSmrg		box.y1 = max(box.y1, 0);
501504d986fSmrg		box.x2 = min(box.x2, w);
502504d986fSmrg		box.y2 = min(box.y2, h);
503504d986fSmrg		if (box.x1 >= box.x2 || box.y1 >= box.y2)
504504d986fSmrg			continue;
505504d986fSmrg
506504d986fSmrg		rects[nrects].x = box.x1;
507504d986fSmrg		rects[nrects].y = box.y1;
508504d986fSmrg		rects[nrects].width = box.x2 - box.x1;
509504d986fSmrg		rects[nrects].height = box.y2 - box.y1;
510504d986fSmrg		nrects++;
511504d986fSmrg	}
512504d986fSmrg
513504d986fSmrg	transformed = RegionFromRects(nrects, rects, CT_UNSORTED);
514504d986fSmrg	free(rects);
515504d986fSmrg	return transformed;
516504d986fSmrg}
517504d986fSmrg
518504d986fSmrgstatic void
519504d986fSmrgamdgpu_sync_scanout_pixmaps(xf86CrtcPtr xf86_crtc, RegionPtr new_region,
520504d986fSmrg							int scanout_id)
521504d986fSmrg{
522504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
52346845023Smrg	DrawablePtr dst = &drmmode_crtc->scanout[scanout_id]->drawable;
52446845023Smrg	DrawablePtr src = &drmmode_crtc->scanout[scanout_id ^ 1]->drawable;
525504d986fSmrg	RegionPtr last_region = &drmmode_crtc->scanout_last_region;
526504d986fSmrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
527504d986fSmrg	ScreenPtr pScreen = scrn->pScreen;
528504d986fSmrg	RegionRec remaining;
529504d986fSmrg	RegionPtr sync_region = NULL;
530504d986fSmrg	BoxRec extents;
531504d986fSmrg	GCPtr gc;
532504d986fSmrg
533504d986fSmrg	if (RegionNil(last_region))
534504d986fSmrg		return;
535504d986fSmrg
536504d986fSmrg	RegionNull(&remaining);
537504d986fSmrg	RegionSubtract(&remaining, last_region, new_region);
538504d986fSmrg	if (RegionNil(&remaining))
539504d986fSmrg		goto uninit;
540504d986fSmrg
541504d986fSmrg	extents = *RegionExtents(&remaining);
542504d986fSmrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents))
543504d986fSmrg		goto uninit;
544504d986fSmrg
545504d986fSmrg	if (xf86_crtc->driverIsPerformingTransform) {
546504d986fSmrg		sync_region = transform_region(&remaining,
547504d986fSmrg					       &xf86_crtc->f_framebuffer_to_crtc,
548504d986fSmrg					       dst->width, dst->height);
54924b90cf4Smrg	} else {
550504d986fSmrg		sync_region = RegionDuplicate(&remaining);
551504d986fSmrg		RegionTranslate(sync_region, -xf86_crtc->x, -xf86_crtc->y);
552504d986fSmrg	}
553504d986fSmrg
554504d986fSmrg	gc = GetScratchGC(dst->depth, pScreen);
555504d986fSmrg	if (gc) {
556504d986fSmrg		gc->funcs->ChangeClip(gc, CT_REGION, sync_region, 0);
55711bf0794Smrg		ValidateGC(dst, gc);
558504d986fSmrg		sync_region = NULL;
559504d986fSmrg		gc->ops->CopyArea(src, dst, gc, 0, 0, dst->width, dst->height, 0, 0);
560504d986fSmrg		FreeScratchGC(gc);
561504d986fSmrg	}
562504d986fSmrg
563504d986fSmrg uninit:
564504d986fSmrg	if (sync_region)
565504d986fSmrg		RegionDestroy(sync_region);
566504d986fSmrg	RegionUninit(&remaining);
567504d986fSmrg}
568504d986fSmrg
56924b90cf4Smrgstatic void
57024b90cf4Smrgamdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
57124b90cf4Smrg{
57224b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
57324b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
57490f2b693Smrg	struct drmmode_fb *fb = event_data;
57524b90cf4Smrg
57635d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
57790f2b693Smrg
57890f2b693Smrg	if (drmmode_crtc->flip_pending == fb) {
57990f2b693Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
58090f2b693Smrg				     NULL);
58190f2b693Smrg	}
58224b90cf4Smrg}
58324b90cf4Smrg
58424b90cf4Smrgstatic void
58524b90cf4Smrgamdgpu_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
58624b90cf4Smrg			    void *event_data)
58724b90cf4Smrg{
58824b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
58924b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
59090f2b693Smrg	struct drmmode_fb *fb = event_data;
59124b90cf4Smrg
59290f2b693Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb);
59324b90cf4Smrg	amdgpu_scanout_flip_abort(crtc, event_data);
59424b90cf4Smrg}
59524b90cf4Smrg
596504d986fSmrg
597504d986fSmrgstatic RegionPtr
598504d986fSmrgdirty_region(PixmapDirtyUpdatePtr dirty)
599d6c0b56eSmrg{
600504d986fSmrg	RegionPtr damageregion = DamageRegion(dirty->damage);
601504d986fSmrg	RegionPtr dstregion;
602504d986fSmrg
603504d986fSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
604504d986fSmrg	if (dirty->rotation != RR_Rotate_0) {
605504d986fSmrg		dstregion = transform_region(damageregion,
606504d986fSmrg					     &dirty->f_inverse,
60746845023Smrg					     dirty->secondary_dst->drawable.width,
60846845023Smrg					     dirty->secondary_dst->drawable.height);
609504d986fSmrg	} else
610504d986fSmrg#endif
611504d986fSmrg	{
612504d986fSmrg		RegionRec pixregion;
613504d986fSmrg
614504d986fSmrg		dstregion = RegionDuplicate(damageregion);
615504d986fSmrg		RegionTranslate(dstregion, -dirty->x, -dirty->y);
61646845023Smrg		PixmapRegionInit(&pixregion, dirty->secondary_dst);
617504d986fSmrg		RegionIntersect(dstregion, dstregion, &pixregion);
618504d986fSmrg		RegionUninit(&pixregion);
619504d986fSmrg	}
620504d986fSmrg
621504d986fSmrg	return dstregion;
622504d986fSmrg}
623504d986fSmrg
624504d986fSmrgstatic void
625504d986fSmrgredisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region)
626504d986fSmrg{
62724b90cf4Smrg	ScrnInfoPtr src_scrn =
62824b90cf4Smrg		xf86ScreenToScrn(amdgpu_dirty_src_drawable(dirty)->pScreen);
629504d986fSmrg
630504d986fSmrg	if (RegionNil(region))
631504d986fSmrg		goto out;
632504d986fSmrg
63346845023Smrg	if (dirty->secondary_dst->primary_pixmap)
63446845023Smrg		DamageRegionAppend(&dirty->secondary_dst->drawable, region);
635d6c0b56eSmrg
636d6c0b56eSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
637d6c0b56eSmrg	PixmapSyncDirtyHelper(dirty);
638d6c0b56eSmrg#else
639504d986fSmrg	PixmapSyncDirtyHelper(dirty, region);
640d6c0b56eSmrg#endif
641d6c0b56eSmrg
64224b90cf4Smrg	amdgpu_glamor_flush(src_scrn);
64346845023Smrg	if (dirty->secondary_dst->primary_pixmap)
64446845023Smrg		DamageRegionProcessPending(&dirty->secondary_dst->drawable);
645504d986fSmrg
646504d986fSmrgout:
647504d986fSmrg	DamageEmpty(dirty->damage);
648d6c0b56eSmrg}
649d6c0b56eSmrg
650504d986fSmrgstatic void
651504d986fSmrgamdgpu_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
652d6c0b56eSmrg{
653504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
654504d986fSmrg
65535d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
656504d986fSmrg}
657504d986fSmrg
658504d986fSmrgvoid
659504d986fSmrgamdgpu_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
660504d986fSmrg{
66146845023Smrg	ScreenPtr primary_screen = amdgpu_dirty_primary(dirty);
662d6c0b56eSmrg	PixmapDirtyUpdatePtr ent;
663504d986fSmrg	RegionPtr region;
664d6c0b56eSmrg
66546845023Smrg	xorg_list_for_each_entry(ent, &primary_screen->pixmap_dirty_list, ent) {
66646845023Smrg		if (!amdgpu_dirty_src_equals(dirty, ent->secondary_dst))
667504d986fSmrg			continue;
668d6c0b56eSmrg
669504d986fSmrg		region = dirty_region(ent);
670504d986fSmrg		redisplay_dirty(ent, region);
671504d986fSmrg		RegionDestroy(region);
672d6c0b56eSmrg	}
673d6c0b56eSmrg}
674504d986fSmrg
675504d986fSmrg
676504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP
677d6c0b56eSmrg
678d6c0b56eSmrgstatic Bool
67946845023Smrgprimary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
680d6c0b56eSmrg{
68146845023Smrg	ScreenPtr primary_screen = amdgpu_dirty_primary(dirty);
682504d986fSmrg
68346845023Smrg	return primary_screen->SyncSharedPixmap != NULL;
684504d986fSmrg}
685504d986fSmrg
686504d986fSmrgstatic Bool
68746845023Smrgsecondary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
688504d986fSmrg{
68946845023Smrg	ScreenPtr secondary_screen = dirty->secondary_dst->drawable.pScreen;
690504d986fSmrg
69146845023Smrg	return secondary_screen->SyncSharedPixmap != NULL;
692504d986fSmrg}
693504d986fSmrg
694504d986fSmrgstatic void
695504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
696504d986fSmrg{
69746845023Smrg	ScreenPtr primary_screen = amdgpu_dirty_primary(dirty);
698504d986fSmrg
69946845023Smrg	primary_screen->SyncSharedPixmap(dirty);
700504d986fSmrg}
701504d986fSmrg
702504d986fSmrg#else /* !HAS_SYNC_SHARED_PIXMAP */
703504d986fSmrg
704504d986fSmrgstatic Bool
70546845023Smrgprimary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
706504d986fSmrg{
70746845023Smrg	ScrnInfoPtr primary_scrn = xf86ScreenToScrn(amdgpu_dirty_primary(dirty));
708504d986fSmrg
70946845023Smrg	return primary_scrn->driverName == scrn->driverName;
710504d986fSmrg}
711504d986fSmrg
712504d986fSmrgstatic Bool
71346845023Smrgsecondary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
714504d986fSmrg{
71546845023Smrg	ScrnInfoPtr secondary_scrn = xf86ScreenToScrn(dirty->secondary_dst->drawable.pScreen);
716504d986fSmrg
71746845023Smrg	return secondary_scrn->driverName == scrn->driverName;
718504d986fSmrg}
719504d986fSmrg
720504d986fSmrgstatic void
721504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
722504d986fSmrg{
723504d986fSmrg	amdgpu_sync_shared_pixmap(dirty);
724504d986fSmrg}
725504d986fSmrg
726504d986fSmrg#endif /* HAS_SYNC_SHARED_PIXMAPS */
727504d986fSmrg
728504d986fSmrg
72911bf0794Smrgstatic xf86CrtcPtr
73011bf0794Smrgamdgpu_prime_dirty_to_crtc(PixmapDirtyUpdatePtr dirty)
73111bf0794Smrg{
73246845023Smrg	ScreenPtr screen = dirty->secondary_dst->drawable.pScreen;
73311bf0794Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
73411bf0794Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
73511bf0794Smrg	int c;
73611bf0794Smrg
73746845023Smrg	/* Find the CRTC which is scanning out from this secondary pixmap */
73811bf0794Smrg	for (c = 0; c < xf86_config->num_crtc; c++) {
73911bf0794Smrg		xf86CrtcPtr xf86_crtc = xf86_config->crtc[c];
74011bf0794Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
74111bf0794Smrg
74224b90cf4Smrg		if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap))
74311bf0794Smrg			return xf86_crtc;
74411bf0794Smrg	}
74511bf0794Smrg
74611bf0794Smrg	return NULL;
74711bf0794Smrg}
74811bf0794Smrg
749504d986fSmrgstatic Bool
750504d986fSmrgamdgpu_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id)
751504d986fSmrg{
752504d986fSmrg	ScrnInfoPtr scrn = crtc->scrn;
753504d986fSmrg	ScreenPtr screen = scrn->pScreen;
754504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
755504d986fSmrg	PixmapDirtyUpdatePtr dirty;
756504d986fSmrg	Bool ret = FALSE;
757504d986fSmrg
758504d986fSmrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
75924b90cf4Smrg		if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
760504d986fSmrg			RegionPtr region;
761504d986fSmrg
76246845023Smrg			if (primary_has_sync_shared_pixmap(scrn, dirty))
763504d986fSmrg				call_sync_shared_pixmap(dirty);
764504d986fSmrg
765504d986fSmrg			region = dirty_region(dirty);
766504d986fSmrg			if (RegionNil(region))
767504d986fSmrg				goto destroy;
768504d986fSmrg
76911bf0794Smrg			if (drmmode_crtc->tear_free) {
770504d986fSmrg				RegionTranslate(region, crtc->x, crtc->y);
771504d986fSmrg				amdgpu_sync_scanout_pixmaps(crtc, region, scanout_id);
772504d986fSmrg				amdgpu_glamor_flush(scrn);
773504d986fSmrg				RegionCopy(&drmmode_crtc->scanout_last_region, region);
774504d986fSmrg				RegionTranslate(region, -crtc->x, -crtc->y);
77546845023Smrg				dirty->secondary_dst = drmmode_crtc->scanout[scanout_id];
776504d986fSmrg			}
777504d986fSmrg
778504d986fSmrg			redisplay_dirty(dirty, region);
779504d986fSmrg			ret = TRUE;
780504d986fSmrg		destroy:
781504d986fSmrg			RegionDestroy(region);
782504d986fSmrg			break;
783504d986fSmrg		}
784d6c0b56eSmrg	}
785d6c0b56eSmrg
786504d986fSmrg	return ret;
787504d986fSmrg}
788504d986fSmrg
78911bf0794Smrgstatic void
790504d986fSmrgamdgpu_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
791504d986fSmrg				     void *event_data)
792504d986fSmrg{
793504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
794504d986fSmrg
795504d986fSmrg	amdgpu_prime_scanout_do_update(crtc, 0);
79635d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
797504d986fSmrg}
798504d986fSmrg
799504d986fSmrgstatic void
800504d986fSmrgamdgpu_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
801504d986fSmrg{
80246845023Smrg	ScreenPtr screen = dirty->secondary_dst->drawable.pScreen;
803504d986fSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
80490f2b693Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
80511bf0794Smrg	xf86CrtcPtr xf86_crtc = amdgpu_prime_dirty_to_crtc(dirty);
80611bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc;
807504d986fSmrg	uintptr_t drm_queue_seq;
808504d986fSmrg
80911bf0794Smrg	if (!xf86_crtc || !xf86_crtc->enabled)
81011bf0794Smrg		return;
811504d986fSmrg
81211bf0794Smrg	drmmode_crtc = xf86_crtc->driver_private;
81311bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
81446845023Smrg	    !drmmode_crtc->scanout[drmmode_crtc->scanout_id] ||
81524b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
816504d986fSmrg		return;
817504d986fSmrg
818504d986fSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
819504d986fSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
820504d986fSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, NULL,
821504d986fSmrg					       amdgpu_prime_scanout_update_handler,
82290f2b693Smrg					       amdgpu_prime_scanout_update_abort,
82390f2b693Smrg					       FALSE);
824504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
825504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
826504d986fSmrg			   "amdgpu_drm_queue_alloc failed for PRIME update\n");
82790f2b693Smrg		amdgpu_prime_scanout_update_handler(xf86_crtc, 0, 0, NULL);
828504d986fSmrg		return;
829504d986fSmrg	}
830504d986fSmrg
83190f2b693Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
83290f2b693Smrg
83324b90cf4Smrg	if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
83424b90cf4Smrg				 1, drm_queue_seq, NULL, NULL)) {
83590f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) {
83690f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
83790f2b693Smrg				   "drmmode_wait_vblank failed for PRIME update: %s\n",
83890f2b693Smrg				   strerror(errno));
83990f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED;
84090f2b693Smrg		}
84190f2b693Smrg
84290f2b693Smrg		drmmode_crtc->drmmode->event_context.vblank_handler(pAMDGPUEnt->fd,
84390f2b693Smrg								    0, 0, 0,
84490f2b693Smrg								    (void*)drm_queue_seq);
84590f2b693Smrg		drmmode_crtc->wait_flip_nesting_level++;
84690f2b693Smrg		amdgpu_drm_queue_handle_deferred(xf86_crtc);
847504d986fSmrg		return;
848504d986fSmrg	}
849504d986fSmrg
85090f2b693Smrg	if (drmmode_crtc->scanout_status ==
85190f2b693Smrg	    (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) {
85290f2b693Smrg		/* The page flip and vblank ioctls failed before, but the vblank
85390f2b693Smrg		 * ioctl is working again, so we can try re-enabling TearFree
85490f2b693Smrg		 */
85590f2b693Smrg		xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode,
85690f2b693Smrg						 xf86_crtc->rotation,
85790f2b693Smrg						 xf86_crtc->x, xf86_crtc->y);
85890f2b693Smrg	}
85990f2b693Smrg
86090f2b693Smrg	drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED;
861504d986fSmrg}
862504d986fSmrg
863504d986fSmrgstatic void
864504d986fSmrgamdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
865504d986fSmrg{
86646845023Smrg	ScreenPtr screen = ent->secondary_dst->drawable.pScreen;
867504d986fSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
868504d986fSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
86911bf0794Smrg	xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent);
87011bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc;
871504d986fSmrg	uintptr_t drm_queue_seq;
872504d986fSmrg	unsigned scanout_id;
87390f2b693Smrg	struct drmmode_fb *fb;
874504d986fSmrg
87511bf0794Smrg	if (!crtc || !crtc->enabled)
87611bf0794Smrg		return;
877504d986fSmrg
87811bf0794Smrg	drmmode_crtc = crtc->driver_private;
87990f2b693Smrg	scanout_id = drmmode_crtc->scanout_id ^ 1;
88011bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
88146845023Smrg	    !drmmode_crtc->scanout[scanout_id] ||
88224b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
883504d986fSmrg		return;
884504d986fSmrg
885504d986fSmrg	if (!amdgpu_prime_scanout_do_update(crtc, scanout_id))
886504d986fSmrg		return;
887504d986fSmrg
88846845023Smrg	fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]);
88990f2b693Smrg	if (!fb) {
89090f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
89190f2b693Smrg			   "Failed to get FB for PRIME flip.\n");
89290f2b693Smrg		return;
89390f2b693Smrg	}
89490f2b693Smrg
895504d986fSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(crtc,
896504d986fSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
89790f2b693Smrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, fb,
89824b90cf4Smrg					       amdgpu_scanout_flip_handler,
89990f2b693Smrg					       amdgpu_scanout_flip_abort, TRUE);
900504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
901504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
902504d986fSmrg			   "Allocating DRM event queue entry failed for PRIME flip.\n");
903504d986fSmrg		return;
904504d986fSmrg	}
905504d986fSmrg
90690f2b693Smrg	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
90790f2b693Smrg					      fb->handle, 0, drm_queue_seq, 1)
90890f2b693Smrg	    != 0) {
90990f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
91090f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
91190f2b693Smrg				   "flip queue failed in %s: %s, TearFree inactive\n",
91290f2b693Smrg				   __func__, strerror(errno));
91390f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED;
91490f2b693Smrg		}
91590f2b693Smrg
91624b90cf4Smrg		amdgpu_drm_abort_entry(drm_queue_seq);
91724b90cf4Smrg		return;
91824b90cf4Smrg	}
91924b90cf4Smrg
92090f2b693Smrg	if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) {
92190f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n");
92290f2b693Smrg		drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED;
923504d986fSmrg	}
924504d986fSmrg
925504d986fSmrg	drmmode_crtc->scanout_id = scanout_id;
92635d5b7c7Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
92790f2b693Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb);
928504d986fSmrg}
929504d986fSmrg
930504d986fSmrgstatic void
931504d986fSmrgamdgpu_dirty_update(ScrnInfoPtr scrn)
932504d986fSmrg{
933504d986fSmrg	ScreenPtr screen = scrn->pScreen;
934504d986fSmrg	PixmapDirtyUpdatePtr ent;
935504d986fSmrg	RegionPtr region;
936504d986fSmrg
937504d986fSmrg	xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
938504d986fSmrg		if (screen->isGPU) {
939504d986fSmrg			PixmapDirtyUpdatePtr region_ent = ent;
940504d986fSmrg
94146845023Smrg			if (primary_has_sync_shared_pixmap(scrn, ent)) {
94246845023Smrg				ScreenPtr primary_screen = amdgpu_dirty_primary(ent);
943504d986fSmrg
94446845023Smrg				xorg_list_for_each_entry(region_ent, &primary_screen->pixmap_dirty_list, ent) {
94546845023Smrg					if (amdgpu_dirty_src_equals(ent, region_ent->secondary_dst))
946504d986fSmrg						break;
947504d986fSmrg				}
948504d986fSmrg			}
949504d986fSmrg
950504d986fSmrg			region = dirty_region(region_ent);
951504d986fSmrg
952504d986fSmrg			if (RegionNotEmpty(region)) {
95311bf0794Smrg				xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent);
95411bf0794Smrg				drmmode_crtc_private_ptr drmmode_crtc = NULL;
95511bf0794Smrg
95611bf0794Smrg				if (crtc)
95711bf0794Smrg					drmmode_crtc = crtc->driver_private;
95811bf0794Smrg
95911bf0794Smrg				if (drmmode_crtc && drmmode_crtc->tear_free)
960504d986fSmrg					amdgpu_prime_scanout_flip(ent);
961504d986fSmrg				else
962504d986fSmrg					amdgpu_prime_scanout_update(ent);
963504d986fSmrg			} else {
964504d986fSmrg				DamageEmpty(region_ent->damage);
965504d986fSmrg			}
966504d986fSmrg
967504d986fSmrg			RegionDestroy(region);
968504d986fSmrg		} else {
96946845023Smrg			if (secondary_has_sync_shared_pixmap(scrn, ent))
970504d986fSmrg				continue;
971504d986fSmrg
972504d986fSmrg			region = dirty_region(ent);
973504d986fSmrg			redisplay_dirty(ent, region);
974504d986fSmrg			RegionDestroy(region);
975504d986fSmrg		}
976504d986fSmrg	}
977504d986fSmrg}
97824b90cf4Smrg
97946845023Smrgstatic void
98046845023SmrgamdgpuSourceValidate(DrawablePtr draw, int x, int y, int w, int h,
98146845023Smrg		     unsigned int subWindowMode)
98246845023Smrg{
98346845023Smrg}
984504d986fSmrg
98511bf0794SmrgBool
98624b90cf4Smrgamdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id,
98735d5b7c7Smrg			 PixmapPtr src_pix, BoxRec extents)
988d6c0b56eSmrg{
989d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
99035d5b7c7Smrg	RegionRec region = { .extents = extents, .data = NULL };
991504d986fSmrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
992504d986fSmrg	ScreenPtr pScreen = scrn->pScreen;
993d6c0b56eSmrg	DrawablePtr pDraw;
994d6c0b56eSmrg
995d6c0b56eSmrg	if (!xf86_crtc->enabled ||
99646845023Smrg	    !drmmode_crtc->scanout[scanout_id] ||
99735d5b7c7Smrg	    extents.x1 >= extents.x2 || extents.y1 >= extents.y2)
998d6c0b56eSmrg		return FALSE;
999d6c0b56eSmrg
100046845023Smrg	pDraw = &drmmode_crtc->scanout[scanout_id]->drawable;
100135d5b7c7Smrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents))
1002d6c0b56eSmrg		return FALSE;
1003d6c0b56eSmrg
100411bf0794Smrg	if (drmmode_crtc->tear_free) {
100524b90cf4Smrg		amdgpu_sync_scanout_pixmaps(xf86_crtc, &region, scanout_id);
100624b90cf4Smrg		RegionCopy(&drmmode_crtc->scanout_last_region, &region);
1007504d986fSmrg	}
1008504d986fSmrg
1009d6c0b56eSmrg	if (xf86_crtc->driverIsPerformingTransform) {
1010d6c0b56eSmrg		SourceValidateProcPtr SourceValidate = pScreen->SourceValidate;
1011d6c0b56eSmrg		PictFormatPtr format = PictureWindowFormat(pScreen->root);
1012d6c0b56eSmrg		int error;
1013d6c0b56eSmrg		PicturePtr src, dst;
1014d6c0b56eSmrg
101524b90cf4Smrg		src = CreatePicture(None, &src_pix->drawable, format, 0L, NULL,
101624b90cf4Smrg				    serverClient, &error);
1017d6c0b56eSmrg		if (!src) {
1018d6c0b56eSmrg			ErrorF("Failed to create source picture for transformed scanout "
1019d6c0b56eSmrg			       "update\n");
1020d6c0b56eSmrg			goto out;
1021d6c0b56eSmrg		}
1022d6c0b56eSmrg
1023d6c0b56eSmrg		dst = CreatePicture(None, pDraw, format, 0L, NULL, serverClient, &error);
1024d6c0b56eSmrg		if (!dst) {
1025d6c0b56eSmrg			ErrorF("Failed to create destination picture for transformed scanout "
1026d6c0b56eSmrg			       "update\n");
1027d6c0b56eSmrg			goto free_src;
1028d6c0b56eSmrg		}
1029d6c0b56eSmrg		error = SetPictureTransform(src, &xf86_crtc->crtc_to_framebuffer);
1030d6c0b56eSmrg		if (error) {
1031d6c0b56eSmrg			ErrorF("SetPictureTransform failed for transformed scanout "
1032d6c0b56eSmrg			       "update\n");
1033d6c0b56eSmrg			goto free_dst;
1034d6c0b56eSmrg		}
1035d6c0b56eSmrg
1036d6c0b56eSmrg		if (xf86_crtc->filter)
1037d6c0b56eSmrg			SetPicturePictFilter(src, xf86_crtc->filter, xf86_crtc->params,
1038d6c0b56eSmrg					     xf86_crtc->nparams);
1039d6c0b56eSmrg
104046845023Smrg		pScreen->SourceValidate = amdgpuSourceValidate;
1041d6c0b56eSmrg		CompositePicture(PictOpSrc,
1042d6c0b56eSmrg				 src, NULL, dst,
104335d5b7c7Smrg				 extents.x1, extents.y1, 0, 0, extents.x1,
104435d5b7c7Smrg				 extents.y1, extents.x2 - extents.x1,
104535d5b7c7Smrg				 extents.y2 - extents.y1);
1046d6c0b56eSmrg		pScreen->SourceValidate = SourceValidate;
1047d6c0b56eSmrg
1048d6c0b56eSmrg free_dst:
1049d6c0b56eSmrg		FreePicture(dst, None);
1050d6c0b56eSmrg free_src:
1051d6c0b56eSmrg		FreePicture(src, None);
1052d6c0b56eSmrg	} else
1053d6c0b56eSmrg out:
1054d6c0b56eSmrg	{
1055d6c0b56eSmrg		GCPtr gc = GetScratchGC(pDraw->depth, pScreen);
1056d6c0b56eSmrg
1057d6c0b56eSmrg		ValidateGC(pDraw, gc);
105824b90cf4Smrg		(*gc->ops->CopyArea)(&src_pix->drawable, pDraw, gc,
105935d5b7c7Smrg				     xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
106035d5b7c7Smrg				     extents.x2 - extents.x1, extents.y2 - extents.y1,
106135d5b7c7Smrg				     extents.x1, extents.y1);
1062d6c0b56eSmrg		FreeScratchGC(gc);
1063d6c0b56eSmrg	}
1064d6c0b56eSmrg
1065d6c0b56eSmrg	return TRUE;
1066d6c0b56eSmrg}
1067d6c0b56eSmrg
1068d6c0b56eSmrgstatic void
1069d6c0b56eSmrgamdgpu_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
1070d6c0b56eSmrg{
1071d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = event_data;
1072d6c0b56eSmrg
107335d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
1074d6c0b56eSmrg}
1075d6c0b56eSmrg
107611bf0794Smrgstatic void
1077d6c0b56eSmrgamdgpu_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
1078d6c0b56eSmrg							  void *event_data)
1079d6c0b56eSmrg{
108024b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = event_data;
108124b90cf4Smrg	ScreenPtr screen = crtc->scrn->pScreen;
108224b90cf4Smrg	RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage);
108324b90cf4Smrg
108424b90cf4Smrg	if (crtc->enabled &&
108524b90cf4Smrg	    !drmmode_crtc->flip_pending &&
108624b90cf4Smrg	    drmmode_crtc->dpms_mode == DPMSModeOn) {
108724b90cf4Smrg		if (amdgpu_scanout_do_update(crtc, drmmode_crtc->scanout_id,
108824b90cf4Smrg					     screen->GetWindowPixmap(screen->root),
108935d5b7c7Smrg					     region->extents)) {
109035d5b7c7Smrg			amdgpu_glamor_flush(crtc->scrn);
109124b90cf4Smrg			RegionEmpty(region);
109235d5b7c7Smrg		}
109324b90cf4Smrg	}
1094d6c0b56eSmrg
1095d6c0b56eSmrg	amdgpu_scanout_update_abort(crtc, event_data);
1096d6c0b56eSmrg}
1097d6c0b56eSmrg
1098d6c0b56eSmrgstatic void
1099d6c0b56eSmrgamdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
1100d6c0b56eSmrg{
1101d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
110290f2b693Smrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
110390f2b693Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
1104d6c0b56eSmrg	uintptr_t drm_queue_seq;
1105d6c0b56eSmrg	DamagePtr pDamage;
1106d6c0b56eSmrg	RegionPtr pRegion;
1107d6c0b56eSmrg	BoxRec extents;
1108d6c0b56eSmrg
1109d6c0b56eSmrg	if (!xf86_crtc->enabled ||
1110d6c0b56eSmrg	    drmmode_crtc->scanout_update_pending ||
111124b90cf4Smrg	    drmmode_crtc->flip_pending ||
111224b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
1113d6c0b56eSmrg		return;
1114d6c0b56eSmrg
1115504d986fSmrg	pDamage = drmmode_crtc->scanout_damage;
1116d6c0b56eSmrg	if (!pDamage)
1117d6c0b56eSmrg		return;
1118d6c0b56eSmrg
1119d6c0b56eSmrg	pRegion = DamageRegion(pDamage);
1120d6c0b56eSmrg	if (!RegionNotEmpty(pRegion))
1121d6c0b56eSmrg		return;
1122d6c0b56eSmrg
1123d6c0b56eSmrg	extents = *RegionExtents(pRegion);
1124504d986fSmrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents)) {
1125504d986fSmrg		RegionEmpty(pRegion);
1126d6c0b56eSmrg		return;
1127504d986fSmrg	}
1128d6c0b56eSmrg
1129d6c0b56eSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
1130d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
1131d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT,
1132d6c0b56eSmrg					       drmmode_crtc,
1133d6c0b56eSmrg					       amdgpu_scanout_update_handler,
113490f2b693Smrg					       amdgpu_scanout_update_abort,
113590f2b693Smrg					       FALSE);
1136504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
1137d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1138d6c0b56eSmrg			   "amdgpu_drm_queue_alloc failed for scanout update\n");
113990f2b693Smrg		amdgpu_scanout_update_handler(xf86_crtc, 0, 0, drmmode_crtc);
1140d6c0b56eSmrg		return;
1141d6c0b56eSmrg	}
1142d6c0b56eSmrg
114390f2b693Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
114490f2b693Smrg
114524b90cf4Smrg	if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
114624b90cf4Smrg				 1, drm_queue_seq, NULL, NULL)) {
114790f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) {
114890f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
114990f2b693Smrg				   "drmmode_wait_vblank failed for scanout update: %s\n",
115090f2b693Smrg				   strerror(errno));
115190f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED;
115290f2b693Smrg		}
115390f2b693Smrg
115490f2b693Smrg		drmmode_crtc->drmmode->event_context.vblank_handler(pAMDGPUEnt->fd,
115590f2b693Smrg								    0, 0, 0,
115690f2b693Smrg								    (void*)drm_queue_seq);
115790f2b693Smrg		drmmode_crtc->wait_flip_nesting_level++;
115890f2b693Smrg		amdgpu_drm_queue_handle_deferred(xf86_crtc);
1159d6c0b56eSmrg		return;
1160d6c0b56eSmrg	}
1161d6c0b56eSmrg
116290f2b693Smrg	if (drmmode_crtc->scanout_status ==
116390f2b693Smrg	    (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) {
116490f2b693Smrg		/* The page flip and vblank ioctls failed before, but the vblank
116590f2b693Smrg		 * ioctl is working again, so we can try re-enabling TearFree
116690f2b693Smrg		 */
116790f2b693Smrg		xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode,
116890f2b693Smrg						 xf86_crtc->rotation,
116990f2b693Smrg						 xf86_crtc->x, xf86_crtc->y);
117090f2b693Smrg	}
117190f2b693Smrg
117290f2b693Smrg	drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED;
1173d6c0b56eSmrg}
1174d6c0b56eSmrg
1175d6c0b56eSmrgstatic void
1176d6c0b56eSmrgamdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
1177d6c0b56eSmrg					xf86CrtcPtr xf86_crtc)
1178d6c0b56eSmrg{
1179d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
118024b90cf4Smrg	RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage);
118111bf0794Smrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
118211bf0794Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
1183d6c0b56eSmrg	uintptr_t drm_queue_seq;
1184d6c0b56eSmrg	unsigned scanout_id;
118590f2b693Smrg	struct drmmode_fb *fb;
1186d6c0b56eSmrg
118711bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
118824b90cf4Smrg	    drmmode_crtc->flip_pending ||
118924b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
1190d6c0b56eSmrg		return;
1191d6c0b56eSmrg
1192d6c0b56eSmrg	scanout_id = drmmode_crtc->scanout_id ^ 1;
119324b90cf4Smrg	if (!amdgpu_scanout_do_update(xf86_crtc, scanout_id,
119424b90cf4Smrg				      pScreen->GetWindowPixmap(pScreen->root),
119535d5b7c7Smrg				      region->extents))
1196d6c0b56eSmrg		return;
119735d5b7c7Smrg
119835d5b7c7Smrg	amdgpu_glamor_flush(scrn);
119924b90cf4Smrg	RegionEmpty(region);
1200d6c0b56eSmrg
120146845023Smrg	fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]);
120290f2b693Smrg	if (!fb) {
120390f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
120490f2b693Smrg			   "Failed to get FB for scanout flip.\n");
120590f2b693Smrg		return;
120690f2b693Smrg	}
120790f2b693Smrg
1208d6c0b56eSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
1209d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
121090f2b693Smrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, fb,
121124b90cf4Smrg					       amdgpu_scanout_flip_handler,
121290f2b693Smrg					       amdgpu_scanout_flip_abort, TRUE);
1213504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
1214d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1215d6c0b56eSmrg			   "Allocating DRM event queue entry failed.\n");
1216d6c0b56eSmrg		return;
1217d6c0b56eSmrg	}
1218d6c0b56eSmrg
121911bf0794Smrg	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
122090f2b693Smrg					      fb->handle, 0, drm_queue_seq, 1)
122190f2b693Smrg	    != 0) {
122290f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
122390f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
122490f2b693Smrg				   "flip queue failed in %s: %s, TearFree inactive\n",
122590f2b693Smrg				   __func__, strerror(errno));
122690f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED;
122790f2b693Smrg		}
122890f2b693Smrg
122911bf0794Smrg		amdgpu_drm_abort_entry(drm_queue_seq);
123024b90cf4Smrg		RegionCopy(DamageRegion(drmmode_crtc->scanout_damage),
123124b90cf4Smrg			   &drmmode_crtc->scanout_last_region);
123224b90cf4Smrg		RegionEmpty(&drmmode_crtc->scanout_last_region);
123324b90cf4Smrg		amdgpu_scanout_update(xf86_crtc);
123446845023Smrg		drmmode_crtc_scanout_destroy(&drmmode_crtc->scanout[scanout_id]);
123524b90cf4Smrg		drmmode_crtc->tear_free = FALSE;
1236d6c0b56eSmrg		return;
1237d6c0b56eSmrg	}
1238d6c0b56eSmrg
123990f2b693Smrg	if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) {
124090f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n");
124190f2b693Smrg		drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED;
124290f2b693Smrg	}
124390f2b693Smrg
1244d6c0b56eSmrg	drmmode_crtc->scanout_id = scanout_id;
124535d5b7c7Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
124690f2b693Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb);
1247d6c0b56eSmrg}
1248d6c0b56eSmrg
1249d6c0b56eSmrgstatic void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
1250d6c0b56eSmrg{
1251d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1252d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1253d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1254d6c0b56eSmrg	int c;
1255d6c0b56eSmrg
1256d6c0b56eSmrg	pScreen->BlockHandler = info->BlockHandler;
1257d6c0b56eSmrg	(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
1258d6c0b56eSmrg	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
1259d6c0b56eSmrg
126046845023Smrg	if (!xf86ScreenToScrn(amdgpu_primary_screen(pScreen))->vtSema)
126124b90cf4Smrg		return;
126224b90cf4Smrg
126324b90cf4Smrg	if (!pScreen->isGPU)
1264504d986fSmrg	{
1265504d986fSmrg		for (c = 0; c < xf86_config->num_crtc; c++) {
126611bf0794Smrg			xf86CrtcPtr crtc = xf86_config->crtc[c];
126711bf0794Smrg			drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
126811bf0794Smrg
126946845023Smrg			if (drmmode_crtc->rotate)
127035d5b7c7Smrg				continue;
127135d5b7c7Smrg
127211bf0794Smrg			if (drmmode_crtc->tear_free)
127311bf0794Smrg				amdgpu_scanout_flip(pScreen, info, crtc);
127446845023Smrg			else if (drmmode_crtc->scanout[drmmode_crtc->scanout_id])
127511bf0794Smrg				amdgpu_scanout_update(crtc);
1276504d986fSmrg		}
1277d6c0b56eSmrg	}
1278d6c0b56eSmrg
127911bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,0,0,0)
1280d6c0b56eSmrg	if (info->use_glamor)
1281d6c0b56eSmrg		amdgpu_glamor_flush(pScrn);
128211bf0794Smrg#endif
1283d6c0b56eSmrg
1284504d986fSmrg	amdgpu_dirty_update(pScrn);
1285d6c0b56eSmrg}
1286d6c0b56eSmrg
1287d6c0b56eSmrg/* This is called by AMDGPUPreInit to set up the default visual */
1288d6c0b56eSmrgstatic Bool AMDGPUPreInitVisual(ScrnInfoPtr pScrn)
1289d6c0b56eSmrg{
1290d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1291d6c0b56eSmrg
1292d6c0b56eSmrg	if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb))
1293d6c0b56eSmrg		return FALSE;
1294d6c0b56eSmrg
1295d6c0b56eSmrg	switch (pScrn->depth) {
1296d6c0b56eSmrg	case 8:
1297d6c0b56eSmrg	case 15:
1298d6c0b56eSmrg	case 16:
1299d6c0b56eSmrg	case 24:
130024b90cf4Smrg	case 30:
1301d6c0b56eSmrg		break;
1302d6c0b56eSmrg
1303d6c0b56eSmrg	default:
1304d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1305d6c0b56eSmrg			   "Given depth (%d) is not supported by %s driver\n",
1306d6c0b56eSmrg			   pScrn->depth, AMDGPU_DRIVER_NAME);
1307d6c0b56eSmrg		return FALSE;
1308d6c0b56eSmrg	}
1309d6c0b56eSmrg
1310d6c0b56eSmrg	xf86PrintDepthBpp(pScrn);
1311d6c0b56eSmrg
1312d6c0b56eSmrg	info->pix24bpp = xf86GetBppFromDepth(pScrn, pScrn->depth);
1313d6c0b56eSmrg	info->pixel_bytes = pScrn->bitsPerPixel / 8;
1314d6c0b56eSmrg
1315d6c0b56eSmrg	if (info->pix24bpp == 24) {
1316d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1317d6c0b56eSmrg			   "Amdgpu does NOT support 24bpp\n");
1318d6c0b56eSmrg		return FALSE;
1319d6c0b56eSmrg	}
1320d6c0b56eSmrg
1321d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1322d6c0b56eSmrg		   "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n",
1323d6c0b56eSmrg		   pScrn->depth,
1324d6c0b56eSmrg		   info->pixel_bytes,
1325d6c0b56eSmrg		   info->pixel_bytes > 1 ? "s" : "", info->pix24bpp);
1326d6c0b56eSmrg
1327d6c0b56eSmrg	if (!xf86SetDefaultVisual(pScrn, -1))
1328d6c0b56eSmrg		return FALSE;
1329d6c0b56eSmrg
1330d6c0b56eSmrg	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
1331d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1332d6c0b56eSmrg			   "Default visual (%s) is not supported at depth %d\n",
1333d6c0b56eSmrg			   xf86GetVisualName(pScrn->defaultVisual),
1334d6c0b56eSmrg			   pScrn->depth);
1335d6c0b56eSmrg		return FALSE;
1336d6c0b56eSmrg	}
1337d6c0b56eSmrg	return TRUE;
1338d6c0b56eSmrg}
1339d6c0b56eSmrg
1340d6c0b56eSmrg/* This is called by AMDGPUPreInit to handle all color weight issues */
1341d6c0b56eSmrgstatic Bool AMDGPUPreInitWeight(ScrnInfoPtr pScrn)
1342d6c0b56eSmrg{
1343d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1344d6c0b56eSmrg
1345d6c0b56eSmrg	/* Save flag for 6 bit DAC to use for
1346d6c0b56eSmrg	   setting CRTC registers.  Otherwise use
1347d6c0b56eSmrg	   an 8 bit DAC, even if xf86SetWeight sets
1348d6c0b56eSmrg	   pScrn->rgbBits to some value other than
1349d6c0b56eSmrg	   8. */
1350d6c0b56eSmrg	info->dac6bits = FALSE;
1351d6c0b56eSmrg
1352d6c0b56eSmrg	if (pScrn->depth > 8) {
1353d6c0b56eSmrg		rgb defaultWeight = { 0, 0, 0 };
1354d6c0b56eSmrg
1355d6c0b56eSmrg		if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
1356d6c0b56eSmrg			return FALSE;
1357d6c0b56eSmrg	} else {
1358d6c0b56eSmrg		pScrn->rgbBits = 8;
1359d6c0b56eSmrg	}
1360d6c0b56eSmrg
1361d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1362d6c0b56eSmrg		   "Using %d bits per RGB (%d bit DAC)\n",
1363d6c0b56eSmrg		   pScrn->rgbBits, info->dac6bits ? 6 : 8);
1364d6c0b56eSmrg
1365d6c0b56eSmrg	return TRUE;
1366d6c0b56eSmrg}
1367d6c0b56eSmrg
1368d6c0b56eSmrgstatic Bool AMDGPUPreInitAccel_KMS(ScrnInfoPtr pScrn)
1369d6c0b56eSmrg{
1370d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1371d6c0b56eSmrg
1372d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_ACCEL, TRUE)) {
1373d6c0b56eSmrg		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1374d6c0b56eSmrg		Bool use_glamor = TRUE;
1375d6c0b56eSmrg#ifdef HAVE_GBM_BO_USE_LINEAR
1376d6c0b56eSmrg		const char *accel_method;
1377d6c0b56eSmrg
1378d6c0b56eSmrg		accel_method = xf86GetOptValString(info->Options, OPTION_ACCEL_METHOD);
1379d6c0b56eSmrg		if ((accel_method && !strcmp(accel_method, "none")))
1380d6c0b56eSmrg			use_glamor = FALSE;
1381d6c0b56eSmrg#endif
1382d6c0b56eSmrg
1383d6c0b56eSmrg#ifdef DRI2
1384d6c0b56eSmrg		info->dri2.available = ! !xf86LoadSubModule(pScrn, "dri2");
1385d6c0b56eSmrg#endif
1386d6c0b56eSmrg
1387d6c0b56eSmrg		if (info->dri2.available)
1388d6c0b56eSmrg			info->gbm = gbm_create_device(pAMDGPUEnt->fd);
1389d6c0b56eSmrg
139024b90cf4Smrg		if (info->gbm) {
139135d5b7c7Smrg			if (use_glamor) {
139235d5b7c7Smrg				if (amdgpu_glamor_pre_init(pScrn))
139335d5b7c7Smrg					return TRUE;
139435d5b7c7Smrg
139535d5b7c7Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
139635d5b7c7Smrg					   "amdgpu_glamor_pre_init returned "
139735d5b7c7Smrg					   "FALSE, using ShadowFB\n");
139835d5b7c7Smrg			}
139924b90cf4Smrg		} else {
140024b90cf4Smrg			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
140124b90cf4Smrg				   "gbm_create_device returned NULL, using "
140224b90cf4Smrg				   "ShadowFB\n");
140324b90cf4Smrg		}
140424b90cf4Smrg	} else {
140524b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
140624b90cf4Smrg			   "GPU acceleration disabled, using ShadowFB\n");
1407d6c0b56eSmrg	}
1408d6c0b56eSmrg
1409d6c0b56eSmrg	if (!xf86LoadSubModule(pScrn, "shadow"))
141024b90cf4Smrg		return FALSE;
1411d6c0b56eSmrg
141224b90cf4Smrg	info->dri2.available = FALSE;
141324b90cf4Smrg	info->shadow_fb = TRUE;
1414d6c0b56eSmrg	return TRUE;
1415d6c0b56eSmrg}
1416d6c0b56eSmrg
141711bf0794Smrgstatic Bool AMDGPUPreInitChipType_KMS(ScrnInfoPtr pScrn,
141811bf0794Smrg				      struct amdgpu_gpu_info *gpu_info)
1419d6c0b56eSmrg{
1420d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
142111bf0794Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1422d6c0b56eSmrg
142390f2b693Smrg	pScrn->chipset = (char*)amdgpu_get_marketing_name(pAMDGPUEnt->pDev);
142411bf0794Smrg	if (!pScrn->chipset)
142511bf0794Smrg		pScrn->chipset = "Unknown AMD Radeon GPU";
1426d6c0b56eSmrg
1427d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1428d6c0b56eSmrg		   "Chipset: \"%s\" (ChipID = 0x%04x)\n",
142946845023Smrg		   pScrn->chipset, gpu_info->asic_id);
1430d6c0b56eSmrg
143111bf0794Smrg	info->family = gpu_info->family_id;
1432d6c0b56eSmrg
1433d6c0b56eSmrg	return TRUE;
1434d6c0b56eSmrg}
1435d6c0b56eSmrg
143611bf0794Smrgstatic Bool amdgpu_get_tile_config(AMDGPUInfoPtr info,
143711bf0794Smrg				   struct amdgpu_gpu_info *gpu_info)
1438d6c0b56eSmrg{
143911bf0794Smrg	switch ((gpu_info->gb_addr_cfg & 0x70) >> 4) {
1440d6c0b56eSmrg	case 0:
1441d6c0b56eSmrg		info->group_bytes = 256;
1442d6c0b56eSmrg		break;
1443d6c0b56eSmrg	case 1:
1444d6c0b56eSmrg		info->group_bytes = 512;
1445d6c0b56eSmrg		break;
1446d6c0b56eSmrg	default:
1447d6c0b56eSmrg		return FALSE;
1448d6c0b56eSmrg	}
1449d6c0b56eSmrg
1450d6c0b56eSmrg	info->have_tiling_info = TRUE;
1451d6c0b56eSmrg	return TRUE;
1452d6c0b56eSmrg}
1453d6c0b56eSmrg
1454d6c0b56eSmrgstatic void AMDGPUSetupCapabilities(ScrnInfoPtr pScrn)
1455d6c0b56eSmrg{
1456d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1457d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1458d6c0b56eSmrg	uint64_t value;
1459d6c0b56eSmrg	int ret;
1460d6c0b56eSmrg
1461d6c0b56eSmrg	pScrn->capabilities = 0;
1462d6c0b56eSmrg
1463d6c0b56eSmrg	/* PRIME offloading requires acceleration */
1464d6c0b56eSmrg	if (!info->use_glamor)
1465d6c0b56eSmrg		return;
1466d6c0b56eSmrg
1467d6c0b56eSmrg	ret = drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PRIME, &value);
1468d6c0b56eSmrg	if (ret == 0) {
1469d6c0b56eSmrg		if (value & DRM_PRIME_CAP_EXPORT)
1470504d986fSmrg			pScrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SourceOffload;
1471504d986fSmrg		if (value & DRM_PRIME_CAP_IMPORT) {
1472504d986fSmrg			pScrn->capabilities |= RR_Capability_SinkOffload;
1473504d986fSmrg			if (info->drmmode.count_crtcs)
1474504d986fSmrg				pScrn->capabilities |= RR_Capability_SinkOutput;
1475504d986fSmrg		}
1476d6c0b56eSmrg	}
1477d6c0b56eSmrg}
1478d6c0b56eSmrg
1479d6c0b56eSmrg/* When the root window is created, initialize the screen contents from
1480d6c0b56eSmrg * console if -background none was specified on the command line
1481d6c0b56eSmrg */
1482d6c0b56eSmrgstatic Bool AMDGPUCreateWindow_oneshot(WindowPtr pWin)
1483d6c0b56eSmrg{
1484d6c0b56eSmrg	ScreenPtr pScreen = pWin->drawable.pScreen;
1485d6c0b56eSmrg	ScrnInfoPtr pScrn;
1486d6c0b56eSmrg	AMDGPUInfoPtr info;
1487d6c0b56eSmrg	Bool ret;
1488d6c0b56eSmrg
1489d6c0b56eSmrg	if (pWin != pScreen->root)
1490d6c0b56eSmrg		ErrorF("%s called for non-root window %p\n", __func__, pWin);
1491d6c0b56eSmrg
1492d6c0b56eSmrg	pScrn = xf86ScreenToScrn(pScreen);
1493d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
1494d6c0b56eSmrg	pScreen->CreateWindow = info->CreateWindow;
1495d6c0b56eSmrg	ret = pScreen->CreateWindow(pWin);
1496d6c0b56eSmrg
1497d6c0b56eSmrg	if (ret)
1498d6c0b56eSmrg		drmmode_copy_fb(pScrn, &info->drmmode);
1499d6c0b56eSmrg
1500d6c0b56eSmrg	return ret;
1501d6c0b56eSmrg}
1502d6c0b56eSmrg
150311bf0794Smrg/* When the root window is mapped, set the initial modes */
150424b90cf4Smrgvoid AMDGPUWindowExposures_oneshot(WindowPtr pWin, RegionPtr pRegion
150511bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
150624b90cf4Smrg				   , RegionPtr pBSRegion
150711bf0794Smrg#endif
150824b90cf4Smrg				   )
150911bf0794Smrg{
151011bf0794Smrg	ScreenPtr pScreen = pWin->drawable.pScreen;
151111bf0794Smrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
151211bf0794Smrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
151311bf0794Smrg
151411bf0794Smrg	if (pWin != pScreen->root)
151511bf0794Smrg		ErrorF("%s called for non-root window %p\n", __func__, pWin);
151611bf0794Smrg
151711bf0794Smrg	pScreen->WindowExposures = info->WindowExposures;
151811bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
151911bf0794Smrg	pScreen->WindowExposures(pWin, pRegion, pBSRegion);
152011bf0794Smrg#else
152111bf0794Smrg	pScreen->WindowExposures(pWin, pRegion);
152211bf0794Smrg#endif
152311bf0794Smrg
152411bf0794Smrg	amdgpu_glamor_finish(pScrn);
152511bf0794Smrg	drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE);
152611bf0794Smrg}
152711bf0794Smrg
1528d6c0b56eSmrgBool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
1529d6c0b56eSmrg{
1530d6c0b56eSmrg	AMDGPUInfoPtr info;
1531d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt;
153211bf0794Smrg	struct amdgpu_gpu_info gpu_info;
153311bf0794Smrg	MessageType from;
1534d6c0b56eSmrg	Gamma zeros = { 0.0, 0.0, 0.0 };
1535d6c0b56eSmrg	int cpp;
1536d6c0b56eSmrg	uint64_t heap_size = 0;
1537d6c0b56eSmrg	uint64_t max_allocation = 0;
1538d6c0b56eSmrg
1539d6c0b56eSmrg	if (flags & PROBE_DETECT)
1540d6c0b56eSmrg		return TRUE;
1541d6c0b56eSmrg
1542d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1543d6c0b56eSmrg		       "AMDGPUPreInit_KMS\n");
1544d6c0b56eSmrg	if (pScrn->numEntities != 1)
1545d6c0b56eSmrg		return FALSE;
154690f2b693Smrg
154790f2b693Smrg	pAMDGPUEnt = xf86GetEntityPrivate(pScrn->entityList[0],
154890f2b693Smrg					  getAMDGPUEntityIndex())->ptr;
154990f2b693Smrg
1550d6c0b56eSmrg	if (!AMDGPUGetRec(pScrn))
1551d6c0b56eSmrg		return FALSE;
1552d6c0b56eSmrg
1553d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
155490f2b693Smrg	info->instance_id = pAMDGPUEnt->num_scrns++;
155590f2b693Smrg	pAMDGPUEnt->scrn[info->instance_id] = pScrn;
155690f2b693Smrg
1557d6c0b56eSmrg	info->pEnt =
1558d6c0b56eSmrg	    xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
1559d6c0b56eSmrg	if (info->pEnt->location.type != BUS_PCI
1560d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS
1561d6c0b56eSmrg	    && info->pEnt->location.type != BUS_PLATFORM
1562d6c0b56eSmrg#endif
1563d6c0b56eSmrg	    )
156424b90cf4Smrg		return FALSE;
1565d6c0b56eSmrg
156690f2b693Smrg	if (xf86IsEntityShared(pScrn->entityList[0]) &&
156790f2b693Smrg	    info->instance_id == 0) {
156890f2b693Smrg		xf86SetPrimInitDone(pScrn->entityList[0]);
1569d6c0b56eSmrg	}
1570d6c0b56eSmrg
1571d6c0b56eSmrg	pScrn->monitor = pScrn->confScreen->monitor;
1572d6c0b56eSmrg
1573d6c0b56eSmrg	if (!AMDGPUPreInitVisual(pScrn))
157424b90cf4Smrg		return FALSE;
1575d6c0b56eSmrg
1576d6c0b56eSmrg	xf86CollectOptions(pScrn, NULL);
1577d6c0b56eSmrg	if (!(info->Options = malloc(sizeof(AMDGPUOptions_KMS))))
157824b90cf4Smrg		return FALSE;
1579d6c0b56eSmrg
1580d6c0b56eSmrg	memcpy(info->Options, AMDGPUOptions_KMS, sizeof(AMDGPUOptions_KMS));
1581d6c0b56eSmrg	xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options);
1582d6c0b56eSmrg
1583d6c0b56eSmrg	if (!AMDGPUPreInitWeight(pScrn))
158424b90cf4Smrg		return FALSE;
1585d6c0b56eSmrg
158611bf0794Smrg	memset(&gpu_info, 0, sizeof(gpu_info));
158711bf0794Smrg	amdgpu_query_gpu_info(pAMDGPUEnt->pDev, &gpu_info);
158811bf0794Smrg
158911bf0794Smrg	if (!AMDGPUPreInitChipType_KMS(pScrn, &gpu_info))
159024b90cf4Smrg		return FALSE;
1591d6c0b56eSmrg
1592d6c0b56eSmrg	info->dri2.available = FALSE;
1593d6c0b56eSmrg	info->dri2.enabled = FALSE;
159490f2b693Smrg	info->dri2.pKernelDRMVersion = drmGetVersion(pAMDGPUEnt->fd);
159590f2b693Smrg	if (info->dri2.pKernelDRMVersion == NULL) {
159690f2b693Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
159790f2b693Smrg			   "AMDGPUDRIGetVersion failed to get the DRM version\n");
159890f2b693Smrg		return FALSE;
159990f2b693Smrg	}
1600d6c0b56eSmrg
1601d6c0b56eSmrg	/* Get ScreenInit function */
1602d6c0b56eSmrg	if (!xf86LoadSubModule(pScrn, "fb"))
1603d6c0b56eSmrg		return FALSE;
1604d6c0b56eSmrg
1605d6c0b56eSmrg	if (!AMDGPUPreInitAccel_KMS(pScrn))
160624b90cf4Smrg		return FALSE;
1607d6c0b56eSmrg
160835d5b7c7Smrg	amdgpu_drm_queue_init(pScrn);
1609d6c0b56eSmrg
1610d6c0b56eSmrg	/* don't enable tiling if accel is not enabled */
1611d6c0b56eSmrg	if (info->use_glamor) {
1612d6c0b56eSmrg		/* set default group bytes, overridden by kernel info below */
1613d6c0b56eSmrg		info->group_bytes = 256;
1614d6c0b56eSmrg		info->have_tiling_info = FALSE;
161511bf0794Smrg		amdgpu_get_tile_config(info, &gpu_info);
1616d6c0b56eSmrg	}
1617d6c0b56eSmrg
1618d6c0b56eSmrg	if (info->use_glamor) {
161911bf0794Smrg		from = X_DEFAULT;
1620d6c0b56eSmrg
162111bf0794Smrg		info->tear_free = 2;
162211bf0794Smrg		if (xf86GetOptValBool(info->Options, OPTION_TEAR_FREE,
162311bf0794Smrg				      &info->tear_free))
162411bf0794Smrg			from = X_CONFIG;
162511bf0794Smrg		xf86DrvMsg(pScrn->scrnIndex, from, "TearFree property default: %s\n",
162611bf0794Smrg			   info->tear_free == 2 ? "auto" : (info->tear_free ? "on" : "off"));
1627d6c0b56eSmrg
1628d6c0b56eSmrg		info->shadow_primary =
1629d6c0b56eSmrg			xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE);
1630d6c0b56eSmrg
1631d6c0b56eSmrg		if (info->shadow_primary)
1632d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowPrimary enabled\n");
163390f2b693Smrg
163490f2b693Smrg		if (!pScrn->is_gpu) {
163590f2b693Smrg			from = xf86GetOptValBool(info->Options, OPTION_VARIABLE_REFRESH,
163690f2b693Smrg						 &info->vrr_support) ? X_CONFIG : X_DEFAULT;
163790f2b693Smrg
163890f2b693Smrg			xf86DrvMsg(pScrn->scrnIndex, from, "VariableRefresh: %sabled\n",
163990f2b693Smrg				   info->vrr_support ? "en" : "dis");
164090f2b693Smrg		}
1641d6c0b56eSmrg	}
1642d6c0b56eSmrg
164324b90cf4Smrg	if (!pScrn->is_gpu) {
164411bf0794Smrg		info->allowPageFlip = xf86ReturnOptValBool(info->Options,
164511bf0794Smrg							   OPTION_PAGE_FLIP,
164611bf0794Smrg							   TRUE);
164777d6d1ecSmrg		if (info->shadow_primary) {
164811bf0794Smrg			xf86DrvMsg(pScrn->scrnIndex,
164911bf0794Smrg				   info->allowPageFlip ? X_WARNING : X_DEFAULT,
165011bf0794Smrg				   "KMS Pageflipping: disabled%s\n",
165111bf0794Smrg				   info->allowPageFlip ?
165277d6d1ecSmrg				   " because of ShadowPrimary" : "");
165311bf0794Smrg			info->allowPageFlip = FALSE;
165411bf0794Smrg		} else {
165511bf0794Smrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
165611bf0794Smrg				   "KMS Pageflipping: %sabled\n",
165711bf0794Smrg				   info->allowPageFlip ? "en" : "dis");
165811bf0794Smrg		}
1659d6c0b56eSmrg	}
1660d6c0b56eSmrg
1661d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_DELETE_DP12, FALSE)) {
1662d6c0b56eSmrg		info->drmmode.delete_dp_12_displays = TRUE;
1663d6c0b56eSmrg	}
1664d6c0b56eSmrg
1665d6c0b56eSmrg	if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) ==
1666d6c0b56eSmrg	    FALSE) {
1667d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1668d6c0b56eSmrg			   "Kernel modesetting setup failed\n");
166924b90cf4Smrg		return FALSE;
1670d6c0b56eSmrg	}
1671d6c0b56eSmrg
1672504d986fSmrg	AMDGPUSetupCapabilities(pScrn);
1673504d986fSmrg
1674d6c0b56eSmrg	if (info->drmmode.count_crtcs == 1)
1675d6c0b56eSmrg		pAMDGPUEnt->HasCRTC2 = FALSE;
1676d6c0b56eSmrg	else
1677d6c0b56eSmrg		pAMDGPUEnt->HasCRTC2 = TRUE;
1678d6c0b56eSmrg
167911bf0794Smrg	if (info->family < AMDGPU_FAMILY_CI) {
1680504d986fSmrg		info->cursor_w = CURSOR_WIDTH;
1681504d986fSmrg		info->cursor_h = CURSOR_HEIGHT;
1682504d986fSmrg	} else {
1683504d986fSmrg		info->cursor_w = CURSOR_WIDTH_CIK;
1684504d986fSmrg		info->cursor_h = CURSOR_HEIGHT_CIK;
1685504d986fSmrg	}
1686d6c0b56eSmrg
1687d6c0b56eSmrg	amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_GTT,
1688d6c0b56eSmrg				&heap_size, &max_allocation);
1689d6c0b56eSmrg	info->gart_size = heap_size;
1690d6c0b56eSmrg	amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_VRAM,
1691d6c0b56eSmrg				&heap_size, &max_allocation);
1692d6c0b56eSmrg	info->vram_size = max_allocation;
1693d6c0b56eSmrg
1694d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1695d6c0b56eSmrg		   "mem size init: gart size :%llx vram size: s:%llx visible:%llx\n",
1696d6c0b56eSmrg		   (unsigned long long)info->gart_size,
1697d6c0b56eSmrg		   (unsigned long long)heap_size,
1698d6c0b56eSmrg		   (unsigned long long)max_allocation);
1699d6c0b56eSmrg
1700d6c0b56eSmrg	cpp = pScrn->bitsPerPixel / 8;
1701d6c0b56eSmrg	pScrn->displayWidth =
1702d6c0b56eSmrg	    AMDGPU_ALIGN(pScrn->virtualX, drmmode_get_pitch_align(pScrn, cpp));
1703d6c0b56eSmrg
1704d6c0b56eSmrg	/* Set display resolution */
1705d6c0b56eSmrg	xf86SetDpi(pScrn, 0, 0);
1706d6c0b56eSmrg
1707d6c0b56eSmrg	if (!xf86SetGamma(pScrn, zeros))
1708d6c0b56eSmrg		return FALSE;
1709d6c0b56eSmrg
1710d6c0b56eSmrg	if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
1711d6c0b56eSmrg		if (!xf86LoadSubModule(pScrn, "ramdac"))
1712d6c0b56eSmrg			return FALSE;
1713d6c0b56eSmrg	}
1714d6c0b56eSmrg
171535d5b7c7Smrg	if (!pScrn->modes
1716d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS
1717d6c0b56eSmrg	    && !pScrn->is_gpu
1718d6c0b56eSmrg#endif
1719d6c0b56eSmrg	    ) {
1720d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
172124b90cf4Smrg		return FALSE;
1722d6c0b56eSmrg	}
1723d6c0b56eSmrg
1724d6c0b56eSmrg	return TRUE;
1725d6c0b56eSmrg}
1726d6c0b56eSmrg
1727d6c0b56eSmrgstatic Bool AMDGPUCursorInit_KMS(ScreenPtr pScreen)
1728d6c0b56eSmrg{
1729d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1730d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1731d6c0b56eSmrg
173224b90cf4Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
173324b90cf4Smrg		       "Initializing Cursor\n");
173424b90cf4Smrg
173524b90cf4Smrg	/* Set Silken Mouse */
173624b90cf4Smrg	xf86SetSilkenMouse(pScreen);
173724b90cf4Smrg
173824b90cf4Smrg	/* Cursor setup */
173924b90cf4Smrg	miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
174024b90cf4Smrg
174124b90cf4Smrg	if (info->allowPageFlip) {
174224b90cf4Smrg		miPointerScreenPtr PointPriv =
174324b90cf4Smrg			dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
174424b90cf4Smrg
174524b90cf4Smrg		if (!dixRegisterScreenPrivateKey(&amdgpu_device_private_key, pScreen,
174624b90cf4Smrg						 PRIVATE_DEVICE,
174724b90cf4Smrg						 sizeof(struct amdgpu_device_priv))) {
174824b90cf4Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "dixRegisterScreenPrivateKey failed\n");
174924b90cf4Smrg			return FALSE;
175024b90cf4Smrg		}
175124b90cf4Smrg
175235d5b7c7Smrg		info->SpriteFuncs = PointPriv->spriteFuncs;
175335d5b7c7Smrg		PointPriv->spriteFuncs = &drmmode_sprite_funcs;
175424b90cf4Smrg	}
175524b90cf4Smrg
175624b90cf4Smrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
175724b90cf4Smrg		return TRUE;
175824b90cf4Smrg
175924b90cf4Smrg	if (!xf86_cursors_init(pScreen, info->cursor_w, info->cursor_h,
176024b90cf4Smrg			       HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
176124b90cf4Smrg			       HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
176224b90cf4Smrg			       HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
176324b90cf4Smrg			       HARDWARE_CURSOR_UPDATE_UNHIDDEN |
176424b90cf4Smrg			       HARDWARE_CURSOR_ARGB)) {
176524b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86_cursors_init failed\n");
176624b90cf4Smrg		return FALSE;
176724b90cf4Smrg	}
176824b90cf4Smrg
176924b90cf4Smrg	return TRUE;
1770d6c0b56eSmrg}
1771d6c0b56eSmrg
1772d6c0b56eSmrgvoid AMDGPUBlank(ScrnInfoPtr pScrn)
1773d6c0b56eSmrg{
1774d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1775d6c0b56eSmrg	xf86OutputPtr output;
1776d6c0b56eSmrg	xf86CrtcPtr crtc;
1777d6c0b56eSmrg	int o, c;
1778d6c0b56eSmrg
1779d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1780d6c0b56eSmrg		crtc = xf86_config->crtc[c];
1781d6c0b56eSmrg		for (o = 0; o < xf86_config->num_output; o++) {
1782d6c0b56eSmrg			output = xf86_config->output[o];
1783d6c0b56eSmrg			if (output->crtc != crtc)
1784d6c0b56eSmrg				continue;
1785d6c0b56eSmrg
1786d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOff);
1787d6c0b56eSmrg		}
1788d6c0b56eSmrg		crtc->funcs->dpms(crtc, DPMSModeOff);
1789d6c0b56eSmrg	}
1790d6c0b56eSmrg}
1791d6c0b56eSmrg
1792d6c0b56eSmrgvoid AMDGPUUnblank(ScrnInfoPtr pScrn)
1793d6c0b56eSmrg{
1794d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1795d6c0b56eSmrg	xf86OutputPtr output;
1796d6c0b56eSmrg	xf86CrtcPtr crtc;
1797d6c0b56eSmrg	int o, c;
1798d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1799d6c0b56eSmrg		crtc = xf86_config->crtc[c];
1800d6c0b56eSmrg		if (!crtc->enabled)
1801d6c0b56eSmrg			continue;
1802d6c0b56eSmrg		crtc->funcs->dpms(crtc, DPMSModeOn);
1803d6c0b56eSmrg		for (o = 0; o < xf86_config->num_output; o++) {
1804d6c0b56eSmrg			output = xf86_config->output[o];
1805d6c0b56eSmrg			if (output->crtc != crtc)
1806d6c0b56eSmrg				continue;
1807d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOn);
1808d6c0b56eSmrg		}
1809d6c0b56eSmrg	}
1810d6c0b56eSmrg}
1811d6c0b56eSmrg
1812d6c0b56eSmrgstatic Bool amdgpu_set_drm_master(ScrnInfoPtr pScrn)
1813d6c0b56eSmrg{
1814d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1815d6c0b56eSmrg	int err;
1816d6c0b56eSmrg
1817d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD
1818d6c0b56eSmrg	if (pAMDGPUEnt->platform_dev &&
1819d6c0b56eSmrg	    (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
1820d6c0b56eSmrg		return TRUE;
1821d6c0b56eSmrg#endif
1822d6c0b56eSmrg
1823d6c0b56eSmrg	err = drmSetMaster(pAMDGPUEnt->fd);
1824d6c0b56eSmrg	if (err)
1825d6c0b56eSmrg		ErrorF("Unable to retrieve master\n");
1826d6c0b56eSmrg
1827d6c0b56eSmrg	return err == 0;
1828d6c0b56eSmrg}
1829d6c0b56eSmrg
1830d6c0b56eSmrgstatic void amdgpu_drop_drm_master(ScrnInfoPtr pScrn)
1831d6c0b56eSmrg{
1832d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1833d6c0b56eSmrg
1834d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD
1835d6c0b56eSmrg	if (pAMDGPUEnt->platform_dev &&
1836d6c0b56eSmrg	    (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
1837d6c0b56eSmrg		return;
1838d6c0b56eSmrg#endif
1839d6c0b56eSmrg
1840d6c0b56eSmrg	drmDropMaster(pAMDGPUEnt->fd);
1841d6c0b56eSmrg}
1842d6c0b56eSmrg
1843d6c0b56eSmrg
184424b90cf4Smrgstatic
184524b90cf4SmrgCARD32 cleanup_black_fb(OsTimerPtr timer, CARD32 now, pointer data)
184624b90cf4Smrg{
184724b90cf4Smrg	ScreenPtr screen = data;
184824b90cf4Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
184924b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
185024b90cf4Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
185124b90cf4Smrg	int c;
185224b90cf4Smrg
185346845023Smrg	if (xf86ScreenToScrn(amdgpu_primary_screen(screen))->vtSema)
185424b90cf4Smrg		return 0;
185524b90cf4Smrg
185624b90cf4Smrg	/* Unreference the all-black FB created by AMDGPULeaveVT_KMS. After
185724b90cf4Smrg	 * this, there should be no FB left created by this driver.
185824b90cf4Smrg	 */
185924b90cf4Smrg	for (c = 0; c < xf86_config->num_crtc; c++) {
186024b90cf4Smrg		drmmode_crtc_private_ptr drmmode_crtc =
186124b90cf4Smrg			xf86_config->crtc[c]->driver_private;
186224b90cf4Smrg
186324b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL);
186424b90cf4Smrg	}
186524b90cf4Smrg
186624b90cf4Smrg	TimerFree(timer);
186724b90cf4Smrg	return 0;
186824b90cf4Smrg}
1869d6c0b56eSmrg
1870d6c0b56eSmrgstatic Bool AMDGPUSaveScreen_KMS(ScreenPtr pScreen, int mode)
1871d6c0b56eSmrg{
1872d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1873d6c0b56eSmrg	Bool unblank;
1874d6c0b56eSmrg
1875d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1876d6c0b56eSmrg		       "AMDGPUSaveScreen(%d)\n", mode);
1877d6c0b56eSmrg
1878d6c0b56eSmrg	unblank = xf86IsUnblank(mode);
1879d6c0b56eSmrg	if (unblank)
1880d6c0b56eSmrg		SetTimeSinceLastInputEvent();
1881d6c0b56eSmrg
1882d6c0b56eSmrg	if ((pScrn != NULL) && pScrn->vtSema) {
1883d6c0b56eSmrg		if (unblank)
1884d6c0b56eSmrg			AMDGPUUnblank(pScrn);
1885d6c0b56eSmrg		else
1886d6c0b56eSmrg			AMDGPUBlank(pScrn);
1887d6c0b56eSmrg	}
1888d6c0b56eSmrg	return TRUE;
1889d6c0b56eSmrg}
1890d6c0b56eSmrg
1891d6c0b56eSmrg/* Called at the end of each server generation.  Restore the original
1892d6c0b56eSmrg * text mode, unmap video memory, and unwrap and call the saved
1893d6c0b56eSmrg * CloseScreen function.
1894d6c0b56eSmrg */
189524b90cf4Smrgstatic Bool AMDGPUCloseScreen_KMS(ScreenPtr pScreen)
1896d6c0b56eSmrg{
1897d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1898d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1899d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1900d6c0b56eSmrg
1901d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1902d6c0b56eSmrg		       "AMDGPUCloseScreen\n");
1903d6c0b56eSmrg
1904d6c0b56eSmrg	/* Clear mask of assigned crtc's in this generation */
1905d6c0b56eSmrg	pAMDGPUEnt->assigned_crtcs = 0;
1906d6c0b56eSmrg
1907d6c0b56eSmrg	drmmode_uevent_fini(pScrn, &info->drmmode);
1908d6c0b56eSmrg	amdgpu_drm_queue_close(pScrn);
1909d6c0b56eSmrg
1910504d986fSmrg	if (info->callback_event_type != -1) {
1911504d986fSmrg		DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn);
1912504d986fSmrg		DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
1913504d986fSmrg	}
1914d6c0b56eSmrg
1915d6c0b56eSmrg	amdgpu_sync_close(pScreen);
1916d6c0b56eSmrg	amdgpu_drop_drm_master(pScrn);
1917d6c0b56eSmrg
1918d6c0b56eSmrg	drmmode_fini(pScrn, &info->drmmode);
1919d6c0b56eSmrg	if (info->dri2.enabled) {
1920d6c0b56eSmrg		amdgpu_dri2_close_screen(pScreen);
1921d6c0b56eSmrg	}
1922d6c0b56eSmrg	amdgpu_glamor_fini(pScreen);
1923d6c0b56eSmrg	pScrn->vtSema = FALSE;
1924d6c0b56eSmrg	xf86ClearPrimInitDone(info->pEnt->index);
192524b90cf4Smrg
192624b90cf4Smrg	if (info->allowPageFlip) {
192724b90cf4Smrg		miPointerScreenPtr PointPriv =
192824b90cf4Smrg			dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
192924b90cf4Smrg
193035d5b7c7Smrg		if (PointPriv->spriteFuncs == &drmmode_sprite_funcs)
193135d5b7c7Smrg			PointPriv->spriteFuncs = info->SpriteFuncs;
193224b90cf4Smrg	}
193324b90cf4Smrg
1934d6c0b56eSmrg	pScreen->BlockHandler = info->BlockHandler;
1935d6c0b56eSmrg	pScreen->CloseScreen = info->CloseScreen;
193624b90cf4Smrg	return pScreen->CloseScreen(pScreen);
1937d6c0b56eSmrg}
1938d6c0b56eSmrg
193924b90cf4Smrgvoid AMDGPUFreeScreen_KMS(ScrnInfoPtr pScrn)
1940d6c0b56eSmrg{
1941d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1942d6c0b56eSmrg		       "AMDGPUFreeScreen\n");
1943d6c0b56eSmrg
1944d6c0b56eSmrg	AMDGPUFreeRec(pScrn);
1945d6c0b56eSmrg}
1946d6c0b56eSmrg
194724b90cf4SmrgBool AMDGPUScreenInit_KMS(ScreenPtr pScreen, int argc, char **argv)
1948d6c0b56eSmrg{
1949d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1950d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1951d6c0b56eSmrg	int subPixelOrder = SubPixelUnknown;
1952d6c0b56eSmrg	MessageType from;
1953d6c0b56eSmrg	Bool value;
1954d6c0b56eSmrg	int driLevel;
1955d6c0b56eSmrg	const char *s;
1956d6c0b56eSmrg	void *front_ptr;
1957d6c0b56eSmrg
1958d6c0b56eSmrg	pScrn->fbOffset = 0;
1959d6c0b56eSmrg
1960d6c0b56eSmrg	miClearVisualTypes();
1961d6c0b56eSmrg	if (!miSetVisualTypes(pScrn->depth,
1962d6c0b56eSmrg			      miGetDefaultVisualMask(pScrn->depth),
1963d6c0b56eSmrg			      pScrn->rgbBits, pScrn->defaultVisual))
1964d6c0b56eSmrg		return FALSE;
1965d6c0b56eSmrg	miSetPixmapDepths();
1966d6c0b56eSmrg
1967d6c0b56eSmrg	if (!amdgpu_set_drm_master(pScrn))
1968d6c0b56eSmrg		return FALSE;
1969d6c0b56eSmrg
1970d6c0b56eSmrg	info->directRenderingEnabled = FALSE;
1971d6c0b56eSmrg	if (info->shadow_fb == FALSE)
1972d6c0b56eSmrg		info->directRenderingEnabled = amdgpu_dri2_screen_init(pScreen);
1973d6c0b56eSmrg
1974d6c0b56eSmrg	if (!amdgpu_setup_kernel_mem(pScreen)) {
1975d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1976d6c0b56eSmrg			   "amdgpu_setup_kernel_mem failed\n");
1977d6c0b56eSmrg		return FALSE;
1978d6c0b56eSmrg	}
1979d6c0b56eSmrg	front_ptr = info->front_buffer->cpu_ptr;
1980d6c0b56eSmrg
1981d6c0b56eSmrg	if (info->shadow_fb) {
1982d6c0b56eSmrg		info->fb_shadow = calloc(1,
1983d6c0b56eSmrg					 pScrn->displayWidth * pScrn->virtualY *
1984d6c0b56eSmrg					 ((pScrn->bitsPerPixel + 7) >> 3));
198535d5b7c7Smrg		if (!info->fb_shadow) {
1986d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1987d6c0b56eSmrg				   "Failed to allocate shadow framebuffer\n");
198824b90cf4Smrg			return FALSE;
1989d6c0b56eSmrg		} else {
1990d6c0b56eSmrg			if (!fbScreenInit(pScreen, info->fb_shadow,
1991d6c0b56eSmrg					  pScrn->virtualX, pScrn->virtualY,
1992d6c0b56eSmrg					  pScrn->xDpi, pScrn->yDpi,
1993d6c0b56eSmrg					  pScrn->displayWidth,
1994d6c0b56eSmrg					  pScrn->bitsPerPixel))
1995d6c0b56eSmrg				return FALSE;
1996d6c0b56eSmrg		}
1997d6c0b56eSmrg	}
1998d6c0b56eSmrg
1999d6c0b56eSmrg	if (info->shadow_fb == FALSE) {
2000d6c0b56eSmrg		/* Init fb layer */
2001d6c0b56eSmrg		if (!fbScreenInit(pScreen, front_ptr,
2002d6c0b56eSmrg				  pScrn->virtualX, pScrn->virtualY,
2003d6c0b56eSmrg				  pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
2004d6c0b56eSmrg				  pScrn->bitsPerPixel))
2005d6c0b56eSmrg			return FALSE;
2006d6c0b56eSmrg	}
2007d6c0b56eSmrg
2008d6c0b56eSmrg	xf86SetBlackWhitePixels(pScreen);
2009d6c0b56eSmrg
2010d6c0b56eSmrg	if (pScrn->bitsPerPixel > 8) {
2011d6c0b56eSmrg		VisualPtr visual;
2012d6c0b56eSmrg
2013d6c0b56eSmrg		visual = pScreen->visuals + pScreen->numVisuals;
2014d6c0b56eSmrg		while (--visual >= pScreen->visuals) {
2015d6c0b56eSmrg			if ((visual->class | DynamicClass) == DirectColor) {
2016d6c0b56eSmrg				visual->offsetRed = pScrn->offset.red;
2017d6c0b56eSmrg				visual->offsetGreen = pScrn->offset.green;
2018d6c0b56eSmrg				visual->offsetBlue = pScrn->offset.blue;
2019d6c0b56eSmrg				visual->redMask = pScrn->mask.red;
2020d6c0b56eSmrg				visual->greenMask = pScrn->mask.green;
2021d6c0b56eSmrg				visual->blueMask = pScrn->mask.blue;
2022d6c0b56eSmrg			}
2023d6c0b56eSmrg		}
2024d6c0b56eSmrg	}
2025d6c0b56eSmrg
2026d6c0b56eSmrg	/* Must be after RGB order fixed */
2027d6c0b56eSmrg	fbPictureInit(pScreen, 0, 0);
2028d6c0b56eSmrg
2029d6c0b56eSmrg#ifdef RENDER
2030d6c0b56eSmrg	if ((s = xf86GetOptValString(info->Options, OPTION_SUBPIXEL_ORDER))) {
2031d6c0b56eSmrg		if (strcmp(s, "RGB") == 0)
2032d6c0b56eSmrg			subPixelOrder = SubPixelHorizontalRGB;
2033d6c0b56eSmrg		else if (strcmp(s, "BGR") == 0)
2034d6c0b56eSmrg			subPixelOrder = SubPixelHorizontalBGR;
2035d6c0b56eSmrg		else if (strcmp(s, "NONE") == 0)
2036d6c0b56eSmrg			subPixelOrder = SubPixelNone;
2037d6c0b56eSmrg		PictureSetSubpixelOrder(pScreen, subPixelOrder);
2038d6c0b56eSmrg	}
2039d6c0b56eSmrg#endif
2040d6c0b56eSmrg
204124b90cf4Smrg	if (!pScreen->isGPU) {
204224b90cf4Smrg		if (xorgGetVersion() >= XORG_VERSION_NUMERIC(1,18,3,0,0))
204324b90cf4Smrg			value = info->use_glamor;
204424b90cf4Smrg		else
204524b90cf4Smrg			value = FALSE;
204611bf0794Smrg		from = X_DEFAULT;
2047d6c0b56eSmrg
204811bf0794Smrg		if (info->use_glamor) {
204911bf0794Smrg			if (xf86GetOptValBool(info->Options, OPTION_DRI3, &value))
205011bf0794Smrg				from = X_CONFIG;
2051d6c0b56eSmrg
205211bf0794Smrg			if (xf86GetOptValInteger(info->Options, OPTION_DRI, &driLevel) &&
205311bf0794Smrg			    (driLevel == 2 || driLevel == 3)) {
205411bf0794Smrg				from = X_CONFIG;
205511bf0794Smrg				value = driLevel == 3;
205611bf0794Smrg			}
2057d6c0b56eSmrg		}
2058d6c0b56eSmrg
205911bf0794Smrg		if (value) {
206011bf0794Smrg			value = amdgpu_sync_init(pScreen) &&
206111bf0794Smrg				amdgpu_present_screen_init(pScreen) &&
206211bf0794Smrg				amdgpu_dri3_screen_init(pScreen);
2063d6c0b56eSmrg
206411bf0794Smrg			if (!value)
206511bf0794Smrg				from = X_WARNING;
206611bf0794Smrg		}
2067d6c0b56eSmrg
206811bf0794Smrg		xf86DrvMsg(pScrn->scrnIndex, from, "DRI3 %sabled\n", value ? "en" : "dis");
206911bf0794Smrg	}
2070d6c0b56eSmrg
2071d6c0b56eSmrg	pScrn->vtSema = TRUE;
2072d6c0b56eSmrg	xf86SetBackingStore(pScreen);
2073d6c0b56eSmrg
2074d6c0b56eSmrg	if (info->directRenderingEnabled) {
2075d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2076d6c0b56eSmrg			   "Direct rendering enabled\n");
2077d6c0b56eSmrg	} else {
2078d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2079d6c0b56eSmrg			   "Direct rendering disabled\n");
2080d6c0b56eSmrg	}
2081d6c0b56eSmrg
2082d6c0b56eSmrg	if (info->use_glamor && info->directRenderingEnabled) {
2083d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2084d6c0b56eSmrg			       "Initializing Acceleration\n");
2085d6c0b56eSmrg		if (amdgpu_glamor_init(pScreen)) {
2086d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2087d6c0b56eSmrg				   "Acceleration enabled\n");
2088d6c0b56eSmrg		} else {
2089d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2090d6c0b56eSmrg				   "Acceleration initialization failed\n");
2091d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2092d6c0b56eSmrg				   "2D and 3D acceleration disabled\n");
2093d6c0b56eSmrg			info->use_glamor = FALSE;
2094d6c0b56eSmrg		}
2095d6c0b56eSmrg	} else if (info->directRenderingEnabled) {
2096d6c0b56eSmrg		if (!amdgpu_pixmap_init(pScreen))
2097d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D acceleration disabled\n");
2098d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration disabled\n");
2099d6c0b56eSmrg	} else {
210024b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D and 3D acceleration disabled\n");
2101d6c0b56eSmrg	}
2102d6c0b56eSmrg
2103d6c0b56eSmrg	/* Init DPMS */
2104d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2105d6c0b56eSmrg		       "Initializing DPMS\n");
2106d6c0b56eSmrg	xf86DPMSInit(pScreen, xf86DPMSSet, 0);
2107d6c0b56eSmrg
210824b90cf4Smrg	if (!AMDGPUCursorInit_KMS(pScreen))
210924b90cf4Smrg		return FALSE;
2110d6c0b56eSmrg
2111d6c0b56eSmrg	/* DGA setup */
2112d6c0b56eSmrg#ifdef XFreeXDGA
2113d6c0b56eSmrg	/* DGA is dangerous on kms as the base and framebuffer location may change:
2114d6c0b56eSmrg	 * http://lists.freedesktop.org/archives/xorg-devel/2009-September/002113.html
2115d6c0b56eSmrg	 */
2116d6c0b56eSmrg	/* xf86DiDGAInit(pScreen, info->LinearAddr + pScrn->fbOffset); */
2117d6c0b56eSmrg#endif
211824b90cf4Smrg	if (info->shadow_fb == FALSE && !pScreen->isGPU) {
2119d6c0b56eSmrg		/* Init Xv */
2120d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2121d6c0b56eSmrg			       "Initializing Xv\n");
2122d6c0b56eSmrg		AMDGPUInitVideo(pScreen);
2123d6c0b56eSmrg	}
2124d6c0b56eSmrg
2125d6c0b56eSmrg	if (info->shadow_fb == TRUE) {
2126d6c0b56eSmrg		if (!shadowSetup(pScreen)) {
2127d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2128d6c0b56eSmrg				   "Shadowfb initialization failed\n");
2129d6c0b56eSmrg			return FALSE;
2130d6c0b56eSmrg		}
2131d6c0b56eSmrg	}
2132d6c0b56eSmrg	pScrn->pScreen = pScreen;
2133d6c0b56eSmrg
213424b90cf4Smrg	if (!pScreen->isGPU) {
213511bf0794Smrg		if (serverGeneration == 1 && bgNoneRoot && info->use_glamor) {
213611bf0794Smrg			info->CreateWindow = pScreen->CreateWindow;
213711bf0794Smrg			pScreen->CreateWindow = AMDGPUCreateWindow_oneshot;
213811bf0794Smrg		}
213911bf0794Smrg		info->WindowExposures = pScreen->WindowExposures;
214011bf0794Smrg		pScreen->WindowExposures = AMDGPUWindowExposures_oneshot;
2141d6c0b56eSmrg	}
2142d6c0b56eSmrg
2143d6c0b56eSmrg	/* Provide SaveScreen & wrap BlockHandler and CloseScreen */
2144d6c0b56eSmrg	/* Wrap CloseScreen */
2145d6c0b56eSmrg	info->CloseScreen = pScreen->CloseScreen;
2146d6c0b56eSmrg	pScreen->CloseScreen = AMDGPUCloseScreen_KMS;
2147d6c0b56eSmrg	pScreen->SaveScreen = AMDGPUSaveScreen_KMS;
2148d6c0b56eSmrg	info->BlockHandler = pScreen->BlockHandler;
214911bf0794Smrg	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
2150d6c0b56eSmrg
2151d6c0b56eSmrg	info->CreateScreenResources = pScreen->CreateScreenResources;
2152d6c0b56eSmrg	pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS;
2153d6c0b56eSmrg
2154d6c0b56eSmrg	pScreen->StartPixmapTracking = PixmapStartDirtyTracking;
2155d6c0b56eSmrg	pScreen->StopPixmapTracking = PixmapStopDirtyTracking;
2156504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP
2157504d986fSmrg	pScreen->SyncSharedPixmap = amdgpu_sync_shared_pixmap;
2158d6c0b56eSmrg#endif
2159d6c0b56eSmrg
2160d6c0b56eSmrg	if (!xf86CrtcScreenInit(pScreen))
2161d6c0b56eSmrg		return FALSE;
2162d6c0b56eSmrg
2163d6c0b56eSmrg	/* Wrap pointer motion to flip touch screen around */
2164d6c0b56eSmrg//    info->PointerMoved = pScrn->PointerMoved;
2165d6c0b56eSmrg//    pScrn->PointerMoved = AMDGPUPointerMoved;
2166d6c0b56eSmrg
2167d6c0b56eSmrg	if (!drmmode_setup_colormap(pScreen, pScrn))
2168d6c0b56eSmrg		return FALSE;
2169d6c0b56eSmrg
2170d6c0b56eSmrg	/* Note unused options */
2171d6c0b56eSmrg	if (serverGeneration == 1)
2172d6c0b56eSmrg		xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
2173d6c0b56eSmrg
217490f2b693Smrg	if (info->vrr_support) {
217590f2b693Smrg		if (!amdgpu_property_vectors_wrapped) {
217690f2b693Smrg			saved_change_property = ProcVector[X_ChangeProperty];
217790f2b693Smrg			ProcVector[X_ChangeProperty] = amdgpu_change_property;
217890f2b693Smrg			saved_delete_property = ProcVector[X_DeleteProperty];
217990f2b693Smrg			ProcVector[X_DeleteProperty] = amdgpu_delete_property;
218090f2b693Smrg			amdgpu_property_vectors_wrapped = TRUE;
218190f2b693Smrg		}
218290f2b693Smrg
218390f2b693Smrg		amdgpu_vrr_atom = MakeAtom("_VARIABLE_REFRESH",
218490f2b693Smrg					   strlen("_VARIABLE_REFRESH"), TRUE);
218590f2b693Smrg	}
218690f2b693Smrg
2187d6c0b56eSmrg	drmmode_init(pScrn, &info->drmmode);
2188d6c0b56eSmrg
2189d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2190d6c0b56eSmrg		       "AMDGPUScreenInit finished\n");
2191d6c0b56eSmrg
2192d6c0b56eSmrg	return TRUE;
2193d6c0b56eSmrg}
2194d6c0b56eSmrg
219524b90cf4SmrgBool AMDGPUEnterVT_KMS(ScrnInfoPtr pScrn)
2196d6c0b56eSmrg{
2197d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2198d6c0b56eSmrg
2199d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2200d6c0b56eSmrg		       "AMDGPUEnterVT_KMS\n");
2201d6c0b56eSmrg
2202d6c0b56eSmrg	amdgpu_set_drm_master(pScrn);
2203d6c0b56eSmrg
220424b90cf4Smrg	if (info->shadow_fb) {
220524b90cf4Smrg		int pitch;
220624b90cf4Smrg		struct amdgpu_buffer *front_buffer =
220724b90cf4Smrg			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
220824b90cf4Smrg					       pScrn->virtualY, pScrn->depth,
220946845023Smrg					       AMDGPU_CREATE_PIXMAP_SCANOUT |
221024b90cf4Smrg					       AMDGPU_CREATE_PIXMAP_LINEAR,
221124b90cf4Smrg					       pScrn->bitsPerPixel,
221224b90cf4Smrg					       &pitch);
221324b90cf4Smrg
221424b90cf4Smrg		if (front_buffer) {
221524b90cf4Smrg			if (amdgpu_bo_map(pScrn, front_buffer) == 0) {
221624b90cf4Smrg				memset(front_buffer->cpu_ptr, 0, pitch * pScrn->virtualY);
221724b90cf4Smrg				amdgpu_bo_unref(&info->front_buffer);
221824b90cf4Smrg				info->front_buffer = front_buffer;
221924b90cf4Smrg			} else {
222024b90cf4Smrg				amdgpu_bo_unref(&front_buffer);
222124b90cf4Smrg				front_buffer = NULL;
222224b90cf4Smrg			}
222324b90cf4Smrg		}
222424b90cf4Smrg
222524b90cf4Smrg		if (!front_buffer) {
222624b90cf4Smrg			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
222724b90cf4Smrg				   "Failed to allocate new scanout BO after VT switch, "
222824b90cf4Smrg				   "other DRM masters may see screen contents\n");
222924b90cf4Smrg		}
223024b90cf4Smrg	}
223124b90cf4Smrg
2232d6c0b56eSmrg	pScrn->vtSema = TRUE;
2233d6c0b56eSmrg
2234d6c0b56eSmrg	if (!drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE))
2235d6c0b56eSmrg		return FALSE;
2236d6c0b56eSmrg
2237d6c0b56eSmrg	return TRUE;
2238d6c0b56eSmrg}
2239d6c0b56eSmrg
224024b90cf4Smrgstatic void
224177d6d1ecSmrgpixmap_unref_fb(PixmapPtr pixmap)
224224b90cf4Smrg{
224377d6d1ecSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
224424b90cf4Smrg	struct drmmode_fb **fb_ptr = amdgpu_pixmap_get_fb_ptr(pixmap);
224577d6d1ecSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
224624b90cf4Smrg
224724b90cf4Smrg	if (fb_ptr)
224824b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, fb_ptr, NULL);
224924b90cf4Smrg}
225024b90cf4Smrg
225177d6d1ecSmrgstatic void
225277d6d1ecSmrgclient_pixmap_unref_fb(void *value, XID id, void *pScreen)
225377d6d1ecSmrg{
225477d6d1ecSmrg	PixmapPtr pixmap = value;
225577d6d1ecSmrg
225677d6d1ecSmrg	if (pixmap->drawable.pScreen == pScreen)
225777d6d1ecSmrg		pixmap_unref_fb(pixmap);
225877d6d1ecSmrg}
225977d6d1ecSmrg
226024b90cf4Smrgvoid AMDGPULeaveVT_KMS(ScrnInfoPtr pScrn)
2261d6c0b56eSmrg{
226224b90cf4Smrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
226324b90cf4Smrg	ScreenPtr pScreen = pScrn->pScreen;
2264d6c0b56eSmrg
2265d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2266d6c0b56eSmrg		       "AMDGPULeaveVT_KMS\n");
2267d6c0b56eSmrg
226824b90cf4Smrg	if (!info->shadow_fb) {
226924b90cf4Smrg		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
227024b90cf4Smrg		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
227124b90cf4Smrg		xf86CrtcPtr crtc;
227224b90cf4Smrg		drmmode_crtc_private_ptr drmmode_crtc;
227324b90cf4Smrg		unsigned w = 0, h = 0;
227424b90cf4Smrg		int i;
227524b90cf4Smrg
227677d6d1ecSmrg		/* If we're called from CloseScreen, trying to clear the black
227777d6d1ecSmrg		 * scanout BO will likely crash and burn
227877d6d1ecSmrg		 */
227977d6d1ecSmrg		if (!pScreen->GCperDepth[0])
228077d6d1ecSmrg			goto hide_cursors;
228177d6d1ecSmrg
228224b90cf4Smrg		/* Compute maximum scanout dimensions of active CRTCs */
228324b90cf4Smrg		for (i = 0; i < xf86_config->num_crtc; i++) {
228424b90cf4Smrg			crtc = xf86_config->crtc[i];
228524b90cf4Smrg			drmmode_crtc = crtc->driver_private;
228624b90cf4Smrg
228724b90cf4Smrg			if (!drmmode_crtc->fb)
228824b90cf4Smrg				continue;
228924b90cf4Smrg
229024b90cf4Smrg			w = max(w, crtc->mode.HDisplay);
229124b90cf4Smrg			h = max(h, crtc->mode.VDisplay);
229224b90cf4Smrg		}
2293d6c0b56eSmrg
229424b90cf4Smrg		/* Make all active CRTCs scan out from an all-black framebuffer */
229524b90cf4Smrg		if (w > 0 && h > 0) {
229646845023Smrg			PixmapPtr black_scanout =
229746845023Smrg				pScreen->CreatePixmap(pScreen, w, h, pScrn->depth,
229846845023Smrg						      AMDGPU_CREATE_PIXMAP_SCANOUT);
229946845023Smrg
230046845023Smrg			if (black_scanout) {
230124b90cf4Smrg				struct drmmode_fb *black_fb =
230246845023Smrg					amdgpu_pixmap_get_fb(black_scanout);
230324b90cf4Smrg
230446845023Smrg				amdgpu_pixmap_clear(black_scanout);
230524b90cf4Smrg				amdgpu_glamor_finish(pScrn);
230624b90cf4Smrg
230724b90cf4Smrg				for (i = 0; i < xf86_config->num_crtc; i++) {
230824b90cf4Smrg					crtc = xf86_config->crtc[i];
230924b90cf4Smrg					drmmode_crtc = crtc->driver_private;
231024b90cf4Smrg
231124b90cf4Smrg					if (drmmode_crtc->fb) {
231224b90cf4Smrg						if (black_fb) {
231324b90cf4Smrg							drmmode_set_mode(crtc, black_fb, &crtc->mode, 0, 0);
231424b90cf4Smrg						} else {
231524b90cf4Smrg							drmModeSetCrtc(pAMDGPUEnt->fd,
231624b90cf4Smrg								       drmmode_crtc->mode_crtc->crtc_id, 0,
231724b90cf4Smrg								       0, 0, NULL, 0, NULL);
231824b90cf4Smrg							drmmode_fb_reference(pAMDGPUEnt->fd,
231924b90cf4Smrg									     &drmmode_crtc->fb, NULL);
232024b90cf4Smrg						}
232124b90cf4Smrg
232224b90cf4Smrg						if (pScrn->is_gpu) {
232346845023Smrg							if (drmmode_crtc->scanout[0])
232446845023Smrg								pixmap_unref_fb(drmmode_crtc->scanout[0]);
232546845023Smrg							if (drmmode_crtc->scanout[1])
232646845023Smrg								pixmap_unref_fb(drmmode_crtc->scanout[1]);
232724b90cf4Smrg						} else {
232890f2b693Smrg							drmmode_crtc_scanout_free(crtc);
232924b90cf4Smrg						}
233024b90cf4Smrg					}
233124b90cf4Smrg				}
233246845023Smrg
233346845023Smrg				pScreen->DestroyPixmap(black_scanout);
233424b90cf4Smrg			}
233524b90cf4Smrg		}
233624b90cf4Smrg
233724b90cf4Smrg		xf86RotateFreeShadow(pScrn);
233824b90cf4Smrg
233924b90cf4Smrg		/* Unreference FBs of all pixmaps. After this, the only FB remaining
234024b90cf4Smrg		 * should be the all-black one being scanned out by active CRTCs
234124b90cf4Smrg		 */
234224b90cf4Smrg		for (i = 0; i < currentMaxClients; i++) {
234324b90cf4Smrg			if (i > 0 &&
234424b90cf4Smrg			    (!clients[i] || clients[i]->clientState != ClientStateRunning))
234524b90cf4Smrg				continue;
234624b90cf4Smrg
234777d6d1ecSmrg			FindClientResourcesByType(clients[i], RT_PIXMAP,
234877d6d1ecSmrg						  client_pixmap_unref_fb, pScreen);
234924b90cf4Smrg		}
235024b90cf4Smrg
235177d6d1ecSmrg		pixmap_unref_fb(pScreen->GetScreenPixmap(pScreen));
235224b90cf4Smrg	} else {
235324b90cf4Smrg		memset(info->front_buffer->cpu_ptr, 0, pScrn->virtualX *
235424b90cf4Smrg		       info->pixel_bytes * pScrn->virtualY);
235524b90cf4Smrg	}
235624b90cf4Smrg
235777d6d1ecSmrg	if (pScreen->GCperDepth[0])
235877d6d1ecSmrg		TimerSet(NULL, 0, 1000, cleanup_black_fb, pScreen);
2359d6c0b56eSmrg
236077d6d1ecSmrg hide_cursors:
2361d6c0b56eSmrg	xf86_hide_cursors(pScrn);
2362d6c0b56eSmrg
236324b90cf4Smrg	amdgpu_drop_drm_master(pScrn);
236424b90cf4Smrg
2365d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2366d6c0b56eSmrg		       "Ok, leaving now...\n");
2367d6c0b56eSmrg}
2368d6c0b56eSmrg
236924b90cf4SmrgBool AMDGPUSwitchMode_KMS(ScrnInfoPtr pScrn, DisplayModePtr mode)
2370d6c0b56eSmrg{
2371d6c0b56eSmrg	Bool ret;
2372d6c0b56eSmrg	ret = xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
2373d6c0b56eSmrg	return ret;
2374d6c0b56eSmrg
2375d6c0b56eSmrg}
2376d6c0b56eSmrg
237724b90cf4Smrgvoid AMDGPUAdjustFrame_KMS(ScrnInfoPtr pScrn, int x, int y)
2378d6c0b56eSmrg{
2379d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2380d6c0b56eSmrg	drmmode_adjust_frame(pScrn, &info->drmmode, x, y);
2381d6c0b56eSmrg	return;
2382d6c0b56eSmrg}
2383d6c0b56eSmrg
2384d6c0b56eSmrgstatic Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen)
2385d6c0b56eSmrg{
2386d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
238790f2b693Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2388d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2389d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2390d6c0b56eSmrg	int cpp = info->pixel_bytes;
2391d6c0b56eSmrg	int cursor_size;
239290f2b693Smrg	int c, i;
2393d6c0b56eSmrg
2394d6c0b56eSmrg	cursor_size = info->cursor_w * info->cursor_h * 4;
2395d6c0b56eSmrg	cursor_size = AMDGPU_ALIGN(cursor_size, AMDGPU_GPU_PAGE_SIZE);
2396d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
239790f2b693Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[c]->driver_private;
239890f2b693Smrg
239990f2b693Smrg		for (i = 0; i < 2; i++) {
240090f2b693Smrg			if (!drmmode_crtc->cursor_buffer[i]) {
240190f2b693Smrg				drmmode_crtc->cursor_buffer[i] =
240290f2b693Smrg					amdgpu_bo_open(pAMDGPUEnt->pDev,
240390f2b693Smrg						       cursor_size, 0,
240490f2b693Smrg						       AMDGPU_GEM_DOMAIN_VRAM);
240590f2b693Smrg
240690f2b693Smrg				if (!(drmmode_crtc->cursor_buffer[i])) {
2407d6c0b56eSmrg					ErrorF("Failed to allocate cursor buffer memory\n");
2408d6c0b56eSmrg					return FALSE;
2409d6c0b56eSmrg				}
2410d6c0b56eSmrg
241190f2b693Smrg				if (amdgpu_bo_cpu_map(drmmode_crtc->cursor_buffer[i]->bo.amdgpu,
241290f2b693Smrg						      &drmmode_crtc->cursor_buffer[i]->cpu_ptr))
2413d6c0b56eSmrg					ErrorF("Failed to map cursor buffer memory\n");
2414d6c0b56eSmrg			}
2415d6c0b56eSmrg		}
2416d6c0b56eSmrg	}
2417d6c0b56eSmrg
241835d5b7c7Smrg	if (!info->front_buffer) {
2419d6c0b56eSmrg		int pitch;
242046845023Smrg		int hint = AMDGPU_CREATE_PIXMAP_SCANOUT;
2421d6c0b56eSmrg
2422d6c0b56eSmrg		if (info->shadow_primary)
242346845023Smrg			hint |= AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
2424d6c0b56eSmrg		else if (!info->use_glamor)
242546845023Smrg			hint |= AMDGPU_CREATE_PIXMAP_LINEAR;
2426d6c0b56eSmrg
2427d6c0b56eSmrg		info->front_buffer =
2428d6c0b56eSmrg			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
2429d6c0b56eSmrg					       pScrn->virtualY, pScrn->depth,
2430d6c0b56eSmrg					       hint, pScrn->bitsPerPixel,
2431d6c0b56eSmrg					       &pitch);
2432d6c0b56eSmrg		if (!(info->front_buffer)) {
2433d6c0b56eSmrg			ErrorF("Failed to allocate front buffer memory\n");
2434d6c0b56eSmrg			return FALSE;
2435d6c0b56eSmrg		}
2436d6c0b56eSmrg
2437d6c0b56eSmrg		if (!info->use_glamor &&
2438d6c0b56eSmrg		    amdgpu_bo_map(pScrn, info->front_buffer) != 0) {
2439d6c0b56eSmrg			ErrorF("Failed to map front buffer memory\n");
2440d6c0b56eSmrg			return FALSE;
2441d6c0b56eSmrg		}
2442d6c0b56eSmrg
2443d6c0b56eSmrg		pScrn->displayWidth = pitch / cpp;
2444d6c0b56eSmrg	}
2445d6c0b56eSmrg
2446d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Front buffer pitch: %d bytes\n",
2447d6c0b56eSmrg		   pScrn->displayWidth * cpp);
2448d6c0b56eSmrg	return TRUE;
2449d6c0b56eSmrg}
2450d6c0b56eSmrg
2451d6c0b56eSmrg/* Used to disallow modes that are not supported by the hardware */
245224b90cf4SmrgModeStatus AMDGPUValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode,
2453d6c0b56eSmrg			   Bool verbose, int flag)
2454d6c0b56eSmrg{
2455d6c0b56eSmrg	/* There are problems with double scan mode at high clocks
2456d6c0b56eSmrg	 * They're likely related PLL and display buffer settings.
2457d6c0b56eSmrg	 * Disable these modes for now.
2458d6c0b56eSmrg	 */
2459d6c0b56eSmrg	if (mode->Flags & V_DBLSCAN) {
2460d6c0b56eSmrg		if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768))
2461d6c0b56eSmrg			return MODE_CLOCK_RANGE;
2462d6c0b56eSmrg	}
2463d6c0b56eSmrg	return MODE_OK;
2464d6c0b56eSmrg}
2465