amdgpu_probe.c revision 504d986f
1/*
2 * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
3 *                VA Linux Systems Inc., Fremont, California.
4 *
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation on the rights to use, copy, modify, merge,
11 * publish, distribute, sublicense, and/or sell copies of the Software,
12 * and to permit persons to whom the Software is furnished to do so,
13 * subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23 * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <errno.h>
34#include <string.h>
35#include <stdlib.h>
36
37/*
38 * Authors:
39 *   Kevin E. Martin <martin@xfree86.org>
40 *   Rickard E. Faith <faith@valinux.com>
41 * KMS support - Dave Airlie <airlied@redhat.com>
42 */
43
44#include "amdgpu_probe.h"
45#include "amdgpu_version.h"
46#include "amdgpu_drv.h"
47#include "amdpciids.h"
48
49#include "xf86.h"
50
51#include "xf86drmMode.h"
52#include "dri.h"
53
54#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
55#include <xf86_OSproc.h>
56#endif
57
58#ifdef XSERVER_PLATFORM_BUS
59#include <xf86platformBus.h>
60#endif
61
62#include "amdgpu_chipset_gen.h"
63
64#include "amdgpu_pci_chipset_gen.h"
65
66#include "amdgpu_pci_device_match_gen.h"
67
68_X_EXPORT int gAMDGPUEntityIndex = -1;
69
70/* Return the options for supported chipset 'n'; NULL otherwise */
71static const OptionInfoRec *AMDGPUAvailableOptions(int chipid, int busid)
72{
73	return AMDGPUOptionsWeak();
74}
75
76/* Return the string name for supported chipset 'n'; NULL otherwise. */
77static void AMDGPUIdentify(int flags)
78{
79	xf86PrintChipsets(AMDGPU_NAME,
80			  "Driver for AMD Radeon chipsets", AMDGPUUniqueChipsets);
81}
82
83static char *amdgpu_bus_id(ScrnInfoPtr pScrn, struct pci_device *dev)
84{
85	char *busid;
86
87	XNFasprintf(&busid, "pci:%04x:%02x:%02x.%d",
88		    dev->domain, dev->bus, dev->dev, dev->func);
89
90	if (!busid)
91		xf86DrvMsgVerb(pScrn->scrnIndex, X_ERROR, 0,
92			       "AMDGPU: Failed to generate bus ID string\n");
93
94	return busid;
95}
96
97static Bool amdgpu_kernel_mode_enabled(ScrnInfoPtr pScrn, char *busIdString)
98{
99	int ret = drmCheckModesettingSupported(busIdString);
100
101#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
102	if (ret) {
103		if (xf86LoadKernelModule("amdgpukms"))
104			ret = drmCheckModesettingSupported(busIdString);
105	}
106#endif
107	if (ret) {
108		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
109			       "[KMS] drm report modesetting isn't supported.\n");
110		return FALSE;
111	}
112
113	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
114		       "[KMS] Kernel modesetting enabled.\n");
115	return TRUE;
116}
117
118static int amdgpu_kernel_open_fd(ScrnInfoPtr pScrn, char *busid,
119				 struct xf86_platform_device *platform_dev)
120{
121	int fd;
122
123#ifdef XF86_PDEV_SERVER_FD
124	if (platform_dev) {
125		fd = xf86_get_platform_device_int_attrib(platform_dev,
126							 ODEV_ATTRIB_FD, -1);
127		if (fd != -1)
128			return fd;
129	}
130#endif
131
132	fd = drmOpen(NULL, busid);
133	if (fd == -1)
134		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
135			   "[drm] Failed to open DRM device for %s: %s\n",
136			   busid, strerror(errno));
137	return fd;
138}
139
140static Bool amdgpu_open_drm_master(ScrnInfoPtr pScrn, AMDGPUEntPtr pAMDGPUEnt,
141				   char *busid)
142{
143	drmSetVersion sv;
144	int err;
145
146	pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, busid, NULL);
147	if (pAMDGPUEnt->fd == -1)
148		return FALSE;
149
150	/* Check that what we opened was a master or a master-capable FD,
151	 * by setting the version of the interface we'll use to talk to it.
152	 * (see DRIOpenDRMMaster() in DRI1)
153	 */
154	sv.drm_di_major = 1;
155	sv.drm_di_minor = 1;
156	sv.drm_dd_major = -1;
157	sv.drm_dd_minor = -1;
158	err = drmSetInterfaceVersion(pAMDGPUEnt->fd, &sv);
159	if (err != 0) {
160		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
161			   "[drm] failed to set drm interface version.\n");
162		drmClose(pAMDGPUEnt->fd);
163		return FALSE;
164	}
165
166	return TRUE;
167}
168
169static Bool amdgpu_get_scrninfo(int entity_num, struct pci_device *pci_dev)
170{
171	ScrnInfoPtr pScrn = NULL;
172	char *busid;
173	EntityInfoPtr pEnt;
174	DevUnion *pPriv;
175	AMDGPUEntPtr pAMDGPUEnt;
176
177	pScrn = xf86ConfigPciEntity(pScrn, 0, entity_num, AMDGPUPciChipsets,
178				    NULL, NULL, NULL, NULL, NULL);
179
180	if (!pScrn)
181		return FALSE;
182
183	busid = amdgpu_bus_id(pScrn, pci_dev);
184	if (!amdgpu_kernel_mode_enabled(pScrn, busid))
185		goto error;
186
187	pScrn->driverVersion = AMDGPU_VERSION_CURRENT;
188	pScrn->driverName = AMDGPU_DRIVER_NAME;
189	pScrn->name = AMDGPU_NAME;
190	pScrn->Probe = NULL;
191
192	pScrn->PreInit = AMDGPUPreInit_KMS;
193	pScrn->ScreenInit = AMDGPUScreenInit_KMS;
194	pScrn->SwitchMode = AMDGPUSwitchMode_KMS;
195	pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS;
196	pScrn->EnterVT = AMDGPUEnterVT_KMS;
197	pScrn->LeaveVT = AMDGPULeaveVT_KMS;
198	pScrn->FreeScreen = AMDGPUFreeScreen_KMS;
199	pScrn->ValidMode = AMDGPUValidMode;
200
201	pEnt = xf86GetEntityInfo(entity_num);
202
203	/* Create a AMDGPUEntity for all chips, even with old single head
204	 * Radeon, need to use pAMDGPUEnt for new monitor detection routines.
205	 */
206	xf86SetEntitySharable(entity_num);
207
208	if (gAMDGPUEntityIndex == -1)
209		gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex();
210
211	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
212
213	if (!pPriv->ptr) {
214		uint32_t major_version;
215		uint32_t minor_version;
216
217		pPriv->ptr = xnfcalloc(sizeof(AMDGPUEntRec), 1);
218		if (!pPriv->ptr)
219			goto error;
220
221		pAMDGPUEnt = pPriv->ptr;
222		if (!amdgpu_open_drm_master(pScrn, pAMDGPUEnt, busid))
223			goto error_fd;
224
225		pAMDGPUEnt->fd_ref = 1;
226
227		if (amdgpu_device_initialize(pAMDGPUEnt->fd,
228					     &major_version,
229					     &minor_version,
230					     &pAMDGPUEnt->pDev)) {
231			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
232				   "amdgpu_device_initialize failed\n");
233			goto error_amdgpu;
234		}
235	} else {
236		pAMDGPUEnt = pPriv->ptr;
237		pAMDGPUEnt->fd_ref++;
238	}
239
240	xf86SetEntityInstanceForScreen(pScrn, pEnt->index,
241				       xf86GetNumEntityInstances(pEnt->
242								 index)
243				       - 1);
244	free(pEnt);
245	free(busid);
246
247	return TRUE;
248
249error_amdgpu:
250	drmClose(pAMDGPUEnt->fd);
251error_fd:
252	free(pPriv->ptr);
253error:
254	free(busid);
255	return FALSE;
256}
257
258static Bool
259amdgpu_pci_probe(DriverPtr pDriver,
260		 int entity_num, struct pci_device *device, intptr_t match_data)
261{
262	return amdgpu_get_scrninfo(entity_num, device);
263}
264
265static Bool AMDGPUDriverFunc(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data)
266{
267	xorgHWFlags *flag;
268
269	switch (op) {
270	case GET_REQUIRED_HW_INTERFACES:
271		flag = (CARD32 *) data;
272		(*flag) = 0;
273		return TRUE;
274#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(1,15,99,0,0)
275	case SUPPORTS_SERVER_FDS:
276		return TRUE;
277#endif
278       default:
279		return FALSE;
280	}
281}
282
283#ifdef XSERVER_PLATFORM_BUS
284static Bool
285amdgpu_platform_probe(DriverPtr pDriver,
286		      int entity_num, int flags,
287		      struct xf86_platform_device *dev, intptr_t match_data)
288{
289	ScrnInfoPtr pScrn;
290	int scr_flags = 0;
291	char *busid;
292	EntityInfoPtr pEnt;
293	DevUnion *pPriv;
294	AMDGPUEntPtr pAMDGPUEnt;
295
296	if (!dev->pdev)
297		return FALSE;
298
299	if (flags & PLATFORM_PROBE_GPU_SCREEN)
300		scr_flags = XF86_ALLOCATE_GPU_SCREEN;
301
302	pScrn = xf86AllocateScreen(pDriver, scr_flags);
303	if (xf86IsEntitySharable(entity_num))
304		xf86SetEntityShared(entity_num);
305	xf86AddEntityToScreen(pScrn, entity_num);
306
307	busid = amdgpu_bus_id(pScrn, dev->pdev);
308	if (!busid)
309		return FALSE;
310
311	if (!amdgpu_kernel_mode_enabled(pScrn, busid))
312		goto error;
313
314	pScrn->driverVersion = AMDGPU_VERSION_CURRENT;
315	pScrn->driverName = AMDGPU_DRIVER_NAME;
316	pScrn->name = AMDGPU_NAME;
317	pScrn->Probe = NULL;
318	pScrn->PreInit = AMDGPUPreInit_KMS;
319	pScrn->ScreenInit = AMDGPUScreenInit_KMS;
320	pScrn->SwitchMode = AMDGPUSwitchMode_KMS;
321	pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS;
322	pScrn->EnterVT = AMDGPUEnterVT_KMS;
323	pScrn->LeaveVT = AMDGPULeaveVT_KMS;
324	pScrn->FreeScreen = AMDGPUFreeScreen_KMS;
325	pScrn->ValidMode = AMDGPUValidMode;
326
327	pEnt = xf86GetEntityInfo(entity_num);
328
329	/* Create a AMDGPUEntity for all chips, even with old single head
330	 * Radeon, need to use pAMDGPUEnt for new monitor detection routines.
331	 */
332	xf86SetEntitySharable(entity_num);
333
334	if (gAMDGPUEntityIndex == -1)
335		gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex();
336
337	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
338
339	if (!pPriv->ptr) {
340		uint32_t major_version;
341		uint32_t minor_version;
342
343		pPriv->ptr = xnfcalloc(sizeof(AMDGPUEntRec), 1);
344		pAMDGPUEnt = pPriv->ptr;
345		pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, busid, dev);
346		if (pAMDGPUEnt->fd < 0)
347			goto error_fd;
348
349		pAMDGPUEnt->fd_ref = 1;
350
351		if (amdgpu_device_initialize(pAMDGPUEnt->fd,
352					     &major_version,
353					     &minor_version,
354					     &pAMDGPUEnt->pDev)) {
355			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
356				   "amdgpu_device_initialize failed\n");
357			goto error_amdgpu;
358		}
359	} else {
360		pAMDGPUEnt = pPriv->ptr;
361		pAMDGPUEnt->fd_ref++;
362	}
363	pAMDGPUEnt->platform_dev = dev;
364
365	xf86SetEntityInstanceForScreen(pScrn, pEnt->index,
366				       xf86GetNumEntityInstances(pEnt->
367								 index)
368				       - 1);
369	free(pEnt);
370	free(busid);
371
372	return TRUE;
373
374error_amdgpu:
375	drmClose(pAMDGPUEnt->fd);
376error_fd:
377	free(pPriv->ptr);
378error:
379	free(busid);
380	return FALSE;
381}
382#endif
383
384_X_EXPORT DriverRec AMDGPU = {
385	AMDGPU_VERSION_CURRENT,
386	AMDGPU_DRIVER_NAME,
387	AMDGPUIdentify,
388	NULL,
389	AMDGPUAvailableOptions,
390	NULL,
391	0,
392	AMDGPUDriverFunc,
393	amdgpu_device_match,
394	amdgpu_pci_probe,
395#ifdef XSERVER_PLATFORM_BUS
396	amdgpu_platform_probe
397#endif
398};
399