1d6c0b56eSmrg/* 2d6c0b56eSmrg * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and 3d6c0b56eSmrg * VA Linux Systems Inc., Fremont, California. 4d6c0b56eSmrg * 5d6c0b56eSmrg * All Rights Reserved. 6d6c0b56eSmrg * 7d6c0b56eSmrg * Permission is hereby granted, free of charge, to any person obtaining 8d6c0b56eSmrg * a copy of this software and associated documentation files (the 9d6c0b56eSmrg * "Software"), to deal in the Software without restriction, including 10d6c0b56eSmrg * without limitation on the rights to use, copy, modify, merge, 11d6c0b56eSmrg * publish, distribute, sublicense, and/or sell copies of the Software, 12d6c0b56eSmrg * and to permit persons to whom the Software is furnished to do so, 13d6c0b56eSmrg * subject to the following conditions: 14d6c0b56eSmrg * 15d6c0b56eSmrg * The above copyright notice and this permission notice (including the 16d6c0b56eSmrg * next paragraph) shall be included in all copies or substantial 17d6c0b56eSmrg * portions of the Software. 18d6c0b56eSmrg * 19d6c0b56eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20d6c0b56eSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d6c0b56eSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22d6c0b56eSmrg * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR 23d6c0b56eSmrg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24d6c0b56eSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25d6c0b56eSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26d6c0b56eSmrg * DEALINGS IN THE SOFTWARE. 27d6c0b56eSmrg */ 28d6c0b56eSmrg 29d6c0b56eSmrg#ifdef HAVE_CONFIG_H 30d6c0b56eSmrg#include "config.h" 31d6c0b56eSmrg#endif 32d6c0b56eSmrg 33d6c0b56eSmrg#include <errno.h> 34d6c0b56eSmrg#include <string.h> 35d6c0b56eSmrg#include <stdlib.h> 3646845023Smrg#include <sys/stat.h> 3746845023Smrg#include <fcntl.h> 38d6c0b56eSmrg 39d6c0b56eSmrg/* 40d6c0b56eSmrg * Authors: 41d6c0b56eSmrg * Kevin E. Martin <martin@xfree86.org> 42d6c0b56eSmrg * Rickard E. Faith <faith@valinux.com> 43d6c0b56eSmrg * KMS support - Dave Airlie <airlied@redhat.com> 44d6c0b56eSmrg */ 45d6c0b56eSmrg 46d6c0b56eSmrg#include "amdgpu_probe.h" 47d6c0b56eSmrg#include "amdgpu_version.h" 48d6c0b56eSmrg#include "amdgpu_drv.h" 49d6c0b56eSmrg 50d6c0b56eSmrg#include "xf86.h" 51d6c0b56eSmrg 52d6c0b56eSmrg#include "xf86drmMode.h" 53d6c0b56eSmrg 54d6c0b56eSmrg#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 55d6c0b56eSmrg#include <xf86_OSproc.h> 56d6c0b56eSmrg#endif 57d6c0b56eSmrg 58d6c0b56eSmrg#include <xf86platformBus.h> 59d6c0b56eSmrg 60d6c0b56eSmrg_X_EXPORT int gAMDGPUEntityIndex = -1; 61d6c0b56eSmrg 62d6c0b56eSmrg/* Return the options for supported chipset 'n'; NULL otherwise */ 63d6c0b56eSmrgstatic const OptionInfoRec *AMDGPUAvailableOptions(int chipid, int busid) 64d6c0b56eSmrg{ 65d6c0b56eSmrg return AMDGPUOptionsWeak(); 66d6c0b56eSmrg} 67d6c0b56eSmrg 6811bf0794Smrgstatic SymTabRec AMDGPUAny[] = { 6911bf0794Smrg { 0, "All GPUs supported by the amdgpu kernel driver" }, 7011bf0794Smrg { -1, NULL } 7111bf0794Smrg}; 7211bf0794Smrg 73d6c0b56eSmrg/* Return the string name for supported chipset 'n'; NULL otherwise. */ 74d6c0b56eSmrgstatic void AMDGPUIdentify(int flags) 75d6c0b56eSmrg{ 7611bf0794Smrg xf86PrintChipsets(AMDGPU_NAME, "Driver for AMD Radeon", AMDGPUAny); 77d6c0b56eSmrg} 78d6c0b56eSmrg 7946845023Smrgstatic Bool amdgpu_device_matches(const drmDevicePtr device, 8046845023Smrg const struct pci_device *dev) 81d6c0b56eSmrg{ 8246845023Smrg return (device->bustype == DRM_BUS_PCI && 8346845023Smrg device->businfo.pci->domain == dev->domain && 8446845023Smrg device->businfo.pci->bus == dev->bus && 8546845023Smrg device->businfo.pci->dev == dev->dev && 8646845023Smrg device->businfo.pci->func == dev->func); 87d6c0b56eSmrg} 88d6c0b56eSmrg 8946845023Smrgstatic Bool amdgpu_kernel_mode_enabled(ScrnInfoPtr pScrn) 90d6c0b56eSmrg{ 9146845023Smrg#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 9246845023Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 9346845023Smrg const char *busIdString = pAMDGPUEnt->busid; 94d6c0b56eSmrg int ret = drmCheckModesettingSupported(busIdString); 95d6c0b56eSmrg 96d6c0b56eSmrg if (ret) { 97d6c0b56eSmrg if (xf86LoadKernelModule("amdgpukms")) 98d6c0b56eSmrg ret = drmCheckModesettingSupported(busIdString); 99d6c0b56eSmrg } 100d6c0b56eSmrg if (ret) { 101d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, 102d6c0b56eSmrg "[KMS] drm report modesetting isn't supported.\n"); 103d6c0b56eSmrg return FALSE; 104d6c0b56eSmrg } 105d6c0b56eSmrg 10646845023Smrg#endif 107d6c0b56eSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, 108d6c0b56eSmrg "[KMS] Kernel modesetting enabled.\n"); 109d6c0b56eSmrg return TRUE; 110d6c0b56eSmrg} 111d6c0b56eSmrg 11235d5b7c7Smrgstatic int amdgpu_kernel_open_fd(ScrnInfoPtr pScrn, 11335d5b7c7Smrg struct pci_device *pci_dev, 11446845023Smrg struct xf86_platform_device *platform_dev, 11546845023Smrg AMDGPUEntPtr pAMDGPUEnt) 116d6c0b56eSmrg{ 11746845023Smrg#define MAX_DRM_DEVICES 64 11846845023Smrg drmDevicePtr devices[MAX_DRM_DEVICES]; 11935d5b7c7Smrg struct pci_device *dev; 12046845023Smrg const char *path; 12146845023Smrg int fd = -1, i, ret; 12246845023Smrg 12346845023Smrg if (platform_dev) 12446845023Smrg dev = platform_dev->pdev; 12546845023Smrg else 12646845023Smrg dev = pci_dev; 12746845023Smrg 12846845023Smrg XNFasprintf(&pAMDGPUEnt->busid, "pci:%04x:%02x:%02x.%u", 12946845023Smrg dev->domain, dev->bus, dev->dev, dev->func); 130d6c0b56eSmrg 131d6c0b56eSmrg if (platform_dev) { 13246845023Smrg#ifdef ODEV_ATTRIB_FD 133d6c0b56eSmrg fd = xf86_get_platform_device_int_attrib(platform_dev, 134d6c0b56eSmrg ODEV_ATTRIB_FD, -1); 135d6c0b56eSmrg if (fd != -1) 136d6c0b56eSmrg return fd; 137d6c0b56eSmrg#endif 138d6c0b56eSmrg 13946845023Smrg#ifdef ODEV_ATTRIB_PATH 14046845023Smrg path = xf86_get_platform_device_attrib(platform_dev, 14146845023Smrg ODEV_ATTRIB_PATH); 14235d5b7c7Smrg 14346845023Smrg fd = open(path, O_RDWR | O_CLOEXEC); 14446845023Smrg if (fd != -1) 14546845023Smrg return fd; 14646845023Smrg#endif 14746845023Smrg } 14846845023Smrg 14946845023Smrg if (!amdgpu_kernel_mode_enabled(pScrn)) 15035d5b7c7Smrg return -1; 15135d5b7c7Smrg 15246845023Smrg ret = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); 15346845023Smrg if (ret == -1) { 15446845023Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 15546845023Smrg "[drm] Failed to retrieve DRM devices information.\n"); 15635d5b7c7Smrg return -1; 15735d5b7c7Smrg } 15846845023Smrg for (i = 0; i < ret; i++) { 15946845023Smrg if (amdgpu_device_matches(devices[i], dev) && 16046845023Smrg devices[i]->available_nodes & (1 << DRM_NODE_PRIMARY)) { 16146845023Smrg path = devices[i]->nodes[DRM_NODE_PRIMARY]; 16246845023Smrg fd = open(path, O_RDWR | O_CLOEXEC); 16346845023Smrg break; 16446845023Smrg } 16546845023Smrg } 16646845023Smrg drmFreeDevices(devices, ret); 16735d5b7c7Smrg 168d6c0b56eSmrg if (fd == -1) 169d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 170d6c0b56eSmrg "[drm] Failed to open DRM device for %s: %s\n", 17146845023Smrg pAMDGPUEnt->busid, strerror(errno)); 172d6c0b56eSmrg return fd; 17346845023Smrg#undef MAX_DRM_DEVICES 174d6c0b56eSmrg} 175d6c0b56eSmrg 17611bf0794Smrgvoid amdgpu_kernel_close_fd(AMDGPUEntPtr pAMDGPUEnt) 17711bf0794Smrg{ 17835d5b7c7Smrg#if defined(XSERVER_PLATFORM_BUS) && defined(XF86_PDEV_SERVER_FD) 17911bf0794Smrg if (!(pAMDGPUEnt->platform_dev && 18011bf0794Smrg pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD)) 18111bf0794Smrg#endif 18246845023Smrg close(pAMDGPUEnt->fd); 18311bf0794Smrg pAMDGPUEnt->fd = -1; 18411bf0794Smrg} 18511bf0794Smrg 18646845023Smrg/* Pull a local version of the helper. It's available since 2.4.98 yet 18746845023Smrg * it may be too new for some distributions. 18846845023Smrg */ 18946845023Smrgstatic int local_drmIsMaster(int fd) 190d6c0b56eSmrg{ 19146845023Smrg return drmAuthMagic(fd, 0) != -EACCES; 19246845023Smrg} 193d6c0b56eSmrg 19446845023Smrgstatic Bool amdgpu_open_drm_master(ScrnInfoPtr pScrn, 19546845023Smrg struct pci_device *pci_dev, 19646845023Smrg struct xf86_platform_device *platform_dev, 19746845023Smrg AMDGPUEntPtr pAMDGPUEnt) 19846845023Smrg{ 19933a2f185Smrg drmSetVersion sv; 20033a2f185Smrg int err; 20133a2f185Smrg 20246845023Smrg pAMDGPUEnt->fd = amdgpu_kernel_open_fd(pScrn, pci_dev, platform_dev, pAMDGPUEnt); 203d6c0b56eSmrg if (pAMDGPUEnt->fd == -1) 204d6c0b56eSmrg return FALSE; 205d6c0b56eSmrg 20633a2f185Smrg /* Check that what we opened was a master or a master-capable FD, 20733a2f185Smrg * by setting the version of the interface we'll use to talk to it. 20833a2f185Smrg * (see DRIOpenDRMMaster() in DRI1) 20933a2f185Smrg */ 21033a2f185Smrg sv.drm_di_major = 1; 21133a2f185Smrg sv.drm_di_minor = 1; 21233a2f185Smrg sv.drm_dd_major = -1; 21333a2f185Smrg sv.drm_dd_minor = -1; 21433a2f185Smrg err = drmSetInterfaceVersion(pAMDGPUEnt->fd, &sv); 21533a2f185Smrg if (err != 0) { 21633a2f185Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 21733a2f185Smrg "[drm] failed to set drm interface version.\n"); 21833a2f185Smrg amdgpu_kernel_close_fd(pAMDGPUEnt); 21933a2f185Smrg return FALSE; 22033a2f185Smrg } 22133a2f185Smrg 22246845023Smrg /* Check that what we opened is a master or a master-capable FD */ 22346845023Smrg if (!local_drmIsMaster(pAMDGPUEnt->fd)) { 224d6c0b56eSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 22546845023Smrg "[drm] device is not DRM master.\n"); 22611bf0794Smrg amdgpu_kernel_close_fd(pAMDGPUEnt); 227d6c0b56eSmrg return FALSE; 228d6c0b56eSmrg } 229d6c0b56eSmrg 230d6c0b56eSmrg return TRUE; 231d6c0b56eSmrg} 232d6c0b56eSmrg 23346845023Smrgstatic Bool amdgpu_device_setup(ScrnInfoPtr pScrn, 23446845023Smrg struct pci_device *pci_dev, 23546845023Smrg struct xf86_platform_device *platform_dev, 23646845023Smrg AMDGPUEntPtr pAMDGPUEnt) 23746845023Smrg{ 23846845023Smrg uint32_t major_version; 23946845023Smrg uint32_t minor_version; 24046845023Smrg 24146845023Smrg pAMDGPUEnt->platform_dev = platform_dev; 24246845023Smrg if (!amdgpu_open_drm_master(pScrn, pci_dev, platform_dev, 24346845023Smrg pAMDGPUEnt)) 24446845023Smrg return FALSE; 24546845023Smrg 24646845023Smrg if (amdgpu_device_initialize(pAMDGPUEnt->fd, 24746845023Smrg &major_version, 24846845023Smrg &minor_version, 24946845023Smrg &pAMDGPUEnt->pDev)) { 25046845023Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 25146845023Smrg "amdgpu_device_initialize failed\n"); 25246845023Smrg goto error_amdgpu; 25346845023Smrg } 25446845023Smrg 25546845023Smrg return TRUE; 25646845023Smrg 25746845023Smrgerror_amdgpu: 25846845023Smrg amdgpu_kernel_close_fd(pAMDGPUEnt); 25946845023Smrg return FALSE; 26046845023Smrg} 26146845023Smrg 26246845023Smrgstatic Bool 26346845023Smrgamdgpu_probe(ScrnInfoPtr pScrn, int entity_num, 26446845023Smrg struct pci_device *pci_dev, struct xf86_platform_device *dev) 265d6c0b56eSmrg{ 26624b90cf4Smrg EntityInfoPtr pEnt = NULL; 267d6c0b56eSmrg DevUnion *pPriv; 268d6c0b56eSmrg AMDGPUEntPtr pAMDGPUEnt; 269d6c0b56eSmrg 270d6c0b56eSmrg if (!pScrn) 271d6c0b56eSmrg return FALSE; 272d6c0b56eSmrg 273d6c0b56eSmrg pScrn->driverVersion = AMDGPU_VERSION_CURRENT; 274d6c0b56eSmrg pScrn->driverName = AMDGPU_DRIVER_NAME; 275d6c0b56eSmrg pScrn->name = AMDGPU_NAME; 276d6c0b56eSmrg pScrn->Probe = NULL; 277d6c0b56eSmrg pScrn->PreInit = AMDGPUPreInit_KMS; 278d6c0b56eSmrg pScrn->ScreenInit = AMDGPUScreenInit_KMS; 279d6c0b56eSmrg pScrn->SwitchMode = AMDGPUSwitchMode_KMS; 280d6c0b56eSmrg pScrn->AdjustFrame = AMDGPUAdjustFrame_KMS; 281d6c0b56eSmrg pScrn->EnterVT = AMDGPUEnterVT_KMS; 282d6c0b56eSmrg pScrn->LeaveVT = AMDGPULeaveVT_KMS; 283d6c0b56eSmrg pScrn->FreeScreen = AMDGPUFreeScreen_KMS; 284d6c0b56eSmrg pScrn->ValidMode = AMDGPUValidMode; 285d6c0b56eSmrg 286d6c0b56eSmrg pEnt = xf86GetEntityInfo(entity_num); 287d6c0b56eSmrg 288d6c0b56eSmrg /* Create a AMDGPUEntity for all chips, even with old single head 289d6c0b56eSmrg * Radeon, need to use pAMDGPUEnt for new monitor detection routines. 290d6c0b56eSmrg */ 291d6c0b56eSmrg xf86SetEntitySharable(entity_num); 292d6c0b56eSmrg 293d6c0b56eSmrg if (gAMDGPUEntityIndex == -1) 294d6c0b56eSmrg gAMDGPUEntityIndex = xf86AllocateEntityPrivateIndex(); 295d6c0b56eSmrg 296d6c0b56eSmrg pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex); 297d6c0b56eSmrg 298d6c0b56eSmrg if (!pPriv->ptr) { 299d6c0b56eSmrg pPriv->ptr = xnfcalloc(sizeof(AMDGPUEntRec), 1); 300d6c0b56eSmrg if (!pPriv->ptr) 301d6c0b56eSmrg goto error; 302d6c0b56eSmrg 303d6c0b56eSmrg pAMDGPUEnt = pPriv->ptr; 30446845023Smrg if (!amdgpu_device_setup(pScrn, pci_dev, dev, pAMDGPUEnt)) 30524b90cf4Smrg goto error; 306d6c0b56eSmrg 307d6c0b56eSmrg pAMDGPUEnt->fd_ref = 1; 308d6c0b56eSmrg 309d6c0b56eSmrg } else { 310d6c0b56eSmrg pAMDGPUEnt = pPriv->ptr; 31190f2b693Smrg 31290f2b693Smrg if (pAMDGPUEnt->fd_ref == ARRAY_SIZE(pAMDGPUEnt->scrn)) { 31390f2b693Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 31490f2b693Smrg "Only up to %u Zaphod instances supported\n", 31590f2b693Smrg (unsigned)ARRAY_SIZE(pAMDGPUEnt->scrn)); 31690f2b693Smrg goto error; 31790f2b693Smrg } 31890f2b693Smrg 319d6c0b56eSmrg pAMDGPUEnt->fd_ref++; 320d6c0b56eSmrg } 321d6c0b56eSmrg 322d6c0b56eSmrg xf86SetEntityInstanceForScreen(pScrn, pEnt->index, 323d6c0b56eSmrg xf86GetNumEntityInstances(pEnt-> 324d6c0b56eSmrg index) 325d6c0b56eSmrg - 1); 326d6c0b56eSmrg free(pEnt); 327d6c0b56eSmrg 328d6c0b56eSmrg return TRUE; 329d6c0b56eSmrg 330d6c0b56eSmrgerror: 33124b90cf4Smrg free(pEnt); 332d6c0b56eSmrg return FALSE; 333d6c0b56eSmrg} 334d6c0b56eSmrg 335d6c0b56eSmrgstatic Bool 336d6c0b56eSmrgamdgpu_pci_probe(DriverPtr pDriver, 337d6c0b56eSmrg int entity_num, struct pci_device *device, intptr_t match_data) 338d6c0b56eSmrg{ 33946845023Smrg ScrnInfoPtr pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL, 34046845023Smrg NULL, NULL, NULL, NULL, NULL); 34146845023Smrg 34246845023Smrg return amdgpu_probe(pScrn, entity_num, device, NULL); 343d6c0b56eSmrg} 344d6c0b56eSmrg 345d6c0b56eSmrgstatic Bool AMDGPUDriverFunc(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data) 346d6c0b56eSmrg{ 347d6c0b56eSmrg xorgHWFlags *flag; 348d6c0b56eSmrg 349d6c0b56eSmrg switch (op) { 350d6c0b56eSmrg case GET_REQUIRED_HW_INTERFACES: 351d6c0b56eSmrg flag = (CARD32 *) data; 352d6c0b56eSmrg (*flag) = 0; 353d6c0b56eSmrg return TRUE; 354d6c0b56eSmrg#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(1,15,99,0,0) 355d6c0b56eSmrg case SUPPORTS_SERVER_FDS: 356d6c0b56eSmrg return TRUE; 357d6c0b56eSmrg#endif 358d6c0b56eSmrg default: 359d6c0b56eSmrg return FALSE; 360d6c0b56eSmrg } 361d6c0b56eSmrg} 362d6c0b56eSmrg 363d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS 364d6c0b56eSmrgstatic Bool 365d6c0b56eSmrgamdgpu_platform_probe(DriverPtr pDriver, 366d6c0b56eSmrg int entity_num, int flags, 367d6c0b56eSmrg struct xf86_platform_device *dev, intptr_t match_data) 368d6c0b56eSmrg{ 369d6c0b56eSmrg ScrnInfoPtr pScrn; 370d6c0b56eSmrg int scr_flags = 0; 371d6c0b56eSmrg 372d6c0b56eSmrg if (!dev->pdev) 373d6c0b56eSmrg return FALSE; 374d6c0b56eSmrg 375d6c0b56eSmrg if (flags & PLATFORM_PROBE_GPU_SCREEN) 376d6c0b56eSmrg scr_flags = XF86_ALLOCATE_GPU_SCREEN; 377d6c0b56eSmrg 378d6c0b56eSmrg pScrn = xf86AllocateScreen(pDriver, scr_flags); 379d6c0b56eSmrg if (xf86IsEntitySharable(entity_num)) 380d6c0b56eSmrg xf86SetEntityShared(entity_num); 381d6c0b56eSmrg xf86AddEntityToScreen(pScrn, entity_num); 382d6c0b56eSmrg 38346845023Smrg return amdgpu_probe(pScrn, entity_num, NULL, dev); 384d6c0b56eSmrg} 385d6c0b56eSmrg#endif 386d6c0b56eSmrg 38711bf0794Smrgstatic const struct pci_id_match amdgpu_device_match[] = { 38811bf0794Smrg {0x1002, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0}, 38911bf0794Smrg {0, 0, 0}, 39011bf0794Smrg}; 39111bf0794Smrg 39235d5b7c7SmrgDriverRec AMDGPU = { 393d6c0b56eSmrg AMDGPU_VERSION_CURRENT, 394d6c0b56eSmrg AMDGPU_DRIVER_NAME, 395d6c0b56eSmrg AMDGPUIdentify, 396d6c0b56eSmrg NULL, 397d6c0b56eSmrg AMDGPUAvailableOptions, 398d6c0b56eSmrg NULL, 399d6c0b56eSmrg 0, 400d6c0b56eSmrg AMDGPUDriverFunc, 401d6c0b56eSmrg amdgpu_device_match, 402d6c0b56eSmrg amdgpu_pci_probe, 403d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS 404d6c0b56eSmrg amdgpu_platform_probe 405d6c0b56eSmrg#endif 406d6c0b56eSmrg}; 407