diff options
Diffstat (limited to 'src/amdgpu_kms.c')
-rw-r--r-- | src/amdgpu_kms.c | 1100 |
1 files changed, 1100 insertions, 0 deletions
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c new file mode 100644 index 0000000..4612000 --- /dev/null +++ b/src/amdgpu_kms.c @@ -0,0 +1,1100 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <sys/ioctl.h> +/* Driver data structures */ +#include "amdgpu_drv.h" +#include "amdgpu_probe.h" +#include "micmap.h" + +#include "amdgpu_version.h" +#include "shadow.h" + +#include "amdpciids.h" + +/* DPMS */ +#ifdef HAVE_XEXTPROTO_71 +#include <X11/extensions/dpmsconst.h> +#else +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#endif + +#include "amdgpu_chipinfo_gen.h" +#include "amdgpu_bo_helper.h" +#include "amdgpu_pixmap.h" + +#include <gbm.h> + +extern SymTabRec AMDGPUChipsets[]; +static Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen); + +const OptionInfoRec AMDGPUOptions_KMS[] = { + {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_SUBPIXEL_ORDER, "SubPixelOrder", OPTV_ANYSTR, {0}, FALSE}, + {OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE}, + {OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE}, + {-1, NULL, OPTV_NONE, {0}, FALSE} +}; + +const OptionInfoRec *AMDGPUOptionsWeak(void) +{ + return AMDGPUOptions_KMS; +} + +extern _X_EXPORT int gAMDGPUEntityIndex; + +static int getAMDGPUEntityIndex(void) +{ + return gAMDGPUEntityIndex; +} + +AMDGPUEntPtr AMDGPUEntPriv(ScrnInfoPtr pScrn) +{ + DevUnion *pPriv; + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + pPriv = xf86GetEntityPrivate(info->pEnt->index, getAMDGPUEntityIndex()); + return pPriv->ptr; +} + +/* Allocate our private AMDGPUInfoRec */ +static Bool AMDGPUGetRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(AMDGPUInfoRec), 1); + return TRUE; +} + +/* Free our private AMDGPUInfoRec */ +static void AMDGPUFreeRec(ScrnInfoPtr pScrn) +{ + AMDGPUInfoPtr info; + + if (!pScrn || !pScrn->driverPrivate) + return; + + info = AMDGPUPTR(pScrn); + + if (info->dri2.drm_fd > 0) { + DevUnion *pPriv; + AMDGPUEntPtr pAMDGPUEnt; + pPriv = xf86GetEntityPrivate(pScrn->entityList[0], + getAMDGPUEntityIndex()); + + pAMDGPUEnt = pPriv->ptr; + pAMDGPUEnt->fd_ref--; + if (!pAMDGPUEnt->fd_ref) { + amdgpu_device_deinitialize(pAMDGPUEnt->pDev); + drmClose(pAMDGPUEnt->fd); + pAMDGPUEnt->fd = 0; + } + } + + free(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + +static void *amdgpuShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset, + int mode, CARD32 * size, void *closure) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + int stride; + + stride = (pScrn->displayWidth * pScrn->bitsPerPixel) / 8; + *size = stride; + + return ((uint8_t *) info->front_buffer->cpu_ptr + row * stride + offset); +} + +static Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + PixmapPtr pixmap; + + pScreen->CreateScreenResources = info->CreateScreenResources; + if (!(*pScreen->CreateScreenResources) (pScreen)) + return FALSE; + pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS; + + if (!drmmode_set_desired_modes(pScrn, &info->drmmode)) + return FALSE; + + drmmode_uevent_init(pScrn, &info->drmmode); + + if (info->shadow_fb) { + pixmap = pScreen->GetScreenPixmap(pScreen); + + if (!shadowAdd(pScreen, pixmap, shadowUpdatePackedWeak(), + amdgpuShadowWindow, 0, NULL)) + return FALSE; + } + + if (info->dri2.enabled || info->use_glamor) { + if (info->front_buffer) { + PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen); + amdgpu_set_pixmap_bo(pPix, info->front_buffer); + } + } + + if (info->use_glamor) + amdgpu_glamor_create_screen_resources(pScreen); + + return TRUE; +} + +#ifdef AMDGPU_PIXMAP_SHARING +static void redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty) +{ + RegionRec pixregion; + + PixmapRegionInit(&pixregion, dirty->slave_dst); + DamageRegionAppend(&dirty->slave_dst->drawable, &pixregion); + PixmapSyncDirtyHelper(dirty, &pixregion); + + DamageRegionProcessPending(&dirty->slave_dst->drawable); + RegionUninit(&pixregion); +} + +static void amdgpu_dirty_update(ScreenPtr screen) +{ + RegionPtr region; + PixmapDirtyUpdatePtr ent; + + if (xorg_list_is_empty(&screen->pixmap_dirty_list)) + return; + + xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) { + region = DamageRegion(ent->damage); + if (RegionNotEmpty(region)) { + redisplay_dirty(screen, ent); + DamageEmpty(ent->damage); + } + } +} +#endif + +static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) +{ + SCREEN_PTR(arg); + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + + pScreen->BlockHandler = info->BlockHandler; + (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS); + pScreen->BlockHandler = AMDGPUBlockHandler_KMS; + + if (info->use_glamor) + amdgpu_glamor_flush(pScrn); + +#ifdef AMDGPU_PIXMAP_SHARING + amdgpu_dirty_update(pScreen); +#endif +} + +static void +amdgpu_flush_callback(CallbackListPtr * list, + pointer user_data, pointer call_data) +{ + ScrnInfoPtr pScrn = user_data; + + if (pScrn->vtSema) { + amdgpu_glamor_flush(pScrn); + } +} + +static Bool AMDGPUIsAccelWorking(ScrnInfoPtr pScrn) +{ + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); + uint32_t accel_working; + + if (amdgpu_query_info(pAMDGPUEnt->pDev, AMDGPU_INFO_ACCEL_WORKING, + sizeof(accel_working), &accel_working) != 0) + return FALSE; + + return accel_working; +} + +/* This is called by AMDGPUPreInit to set up the default visual */ +static Bool AMDGPUPreInitVisual(ScrnInfoPtr pScrn) +{ + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + + if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) + return FALSE; + + switch (pScrn->depth) { + case 8: + case 15: + case 16: + case 24: + break; + + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by %s driver\n", + pScrn->depth, AMDGPU_DRIVER_NAME); + return FALSE; + } + + xf86PrintDepthBpp(pScrn); + + info->pix24bpp = xf86GetBppFromDepth(pScrn, pScrn->depth); + info->pixel_bytes = pScrn->bitsPerPixel / 8; + + if (info->pix24bpp == 24) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Amdgpu does NOT support 24bpp\n"); + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n", + pScrn->depth, + info->pixel_bytes, + info->pixel_bytes > 1 ? "s" : "", info->pix24bpp); + + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + + if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Default visual (%s) is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), + pScrn->depth); + return FALSE; + } + return TRUE; +} + +/* This is called by AMDGPUPreInit to handle all color weight issues */ +static Bool AMDGPUPreInitWeight(ScrnInfoPtr pScrn) +{ + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + + /* Save flag for 6 bit DAC to use for + setting CRTC registers. Otherwise use + an 8 bit DAC, even if xf86SetWeight sets + pScrn->rgbBits to some value other than + 8. */ + info->dac6bits = FALSE; + + if (pScrn->depth > 8) { + rgb defaultWeight = { 0, 0, 0 }; + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + return FALSE; + } else { + pScrn->rgbBits = 8; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d bits per RGB (%d bit DAC)\n", + pScrn->rgbBits, info->dac6bits ? 6 : 8); + + return TRUE; +} + +static Bool AMDGPUPreInitAccel_KMS(ScrnInfoPtr pScrn) +{ + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + const char *accel_method; + + if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, + info->ChipFamily == CHIP_FAMILY_HAWAII) && + AMDGPUIsAccelWorking(pScrn)) { + Bool use_glamor = TRUE; + + accel_method = xf86GetOptValString(info->Options, OPTION_ACCEL_METHOD); + if ((accel_method && !strcmp(accel_method, "none"))) + use_glamor = FALSE; + +#ifdef DRI2 + info->dri2.available = ! !xf86LoadSubModule(pScrn, "dri2"); +#endif + + if (info->dri2.available) + info->gbm = gbm_create_device(info->dri2.drm_fd); + if (info->gbm == NULL) + info->dri2.available = FALSE; + + if (use_glamor && + amdgpu_glamor_pre_init(pScrn)) + return TRUE; + + if (info->dri2.available) + return TRUE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "GPU accel disabled or not working, using shadowfb for KMS\n"); + info->shadow_fb = TRUE; + if (!xf86LoadSubModule(pScrn, "shadow")) + info->shadow_fb = FALSE; + + return TRUE; +} + +static Bool AMDGPUPreInitChipType_KMS(ScrnInfoPtr pScrn) +{ + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + int i; + + info->Chipset = PCI_DEV_DEVICE_ID(info->PciInfo); + pScrn->chipset = + (char *)xf86TokenToString(AMDGPUChipsets, info->Chipset); + if (!pScrn->chipset) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ChipID 0x%04x is not recognized\n", info->Chipset); + return FALSE; + } + + if (info->Chipset < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Chipset \"%s\" is not recognized\n", + pScrn->chipset); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Chipset: \"%s\" (ChipID = 0x%04x)\n", + pScrn->chipset, info->Chipset); + + for (i = 0; i < sizeof(AMDGPUCards) / sizeof(AMDGPUCardInfo); i++) { + if (info->Chipset == AMDGPUCards[i].pci_device_id) { + AMDGPUCardInfo *card = &AMDGPUCards[i]; + info->ChipFamily = card->chip_family; + break; + } + } + + return TRUE; +} + +static void amdgpu_reference_drm_fd(ScrnInfoPtr pScrn) +{ + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); + + info->dri2.drm_fd = pAMDGPUEnt->fd; + pAMDGPUEnt->fd_ref++; + info->drmmode.fd = info->dri2.drm_fd; +} + +static Bool amdgpu_get_tile_config(ScrnInfoPtr pScrn) +{ + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); + struct amdgpu_gpu_info gpu_info; + + memset(&gpu_info, 0, sizeof(gpu_info)); + amdgpu_query_gpu_info(pAMDGPUEnt->pDev, &gpu_info); + + switch ((gpu_info.gb_addr_cfg & 0x70) >> 4) { + case 0: + info->group_bytes = 256; + break; + case 1: + info->group_bytes = 512; + break; + default: + return FALSE; + } + + info->have_tiling_info = TRUE; + return TRUE; +} + +static void AMDGPUSetupCapabilities(ScrnInfoPtr pScrn) +{ +#ifdef AMDGPU_PIXMAP_SHARING + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + uint64_t value; + int ret; + + pScrn->capabilities = 0; + ret = drmGetCap(info->dri2.drm_fd, DRM_CAP_PRIME, &value); + if (ret == 0) { + if (value & DRM_PRIME_CAP_EXPORT) + pScrn->capabilities |= + RR_Capability_SourceOutput | + RR_Capability_SinkOffload; + if (value & DRM_PRIME_CAP_IMPORT) + pScrn->capabilities |= + RR_Capability_SourceOffload | + RR_Capability_SinkOutput; + } +#endif +} + +Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags) +{ + AMDGPUInfoPtr info; + AMDGPUEntPtr pAMDGPUEnt; + DevUnion *pPriv; + Gamma zeros = { 0.0, 0.0, 0.0 }; + int cpp; + uint64_t heap_size = 0; + uint64_t max_allocation = 0; + + if (flags & PROBE_DETECT) + return TRUE; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "AMDGPUPreInit_KMS\n"); + if (pScrn->numEntities != 1) + return FALSE; + if (!AMDGPUGetRec(pScrn)) + return FALSE; + + info = AMDGPUPTR(pScrn); + info->IsSecondary = FALSE; + info->IsPrimary = FALSE; + info->pEnt = + xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]); + if (info->pEnt->location.type != BUS_PCI +#ifdef XSERVER_PLATFORM_BUS + && info->pEnt->location.type != BUS_PLATFORM +#endif + ) + goto fail; + + pPriv = xf86GetEntityPrivate(pScrn->entityList[0], + getAMDGPUEntityIndex()); + pAMDGPUEnt = pPriv->ptr; + + if (xf86IsEntityShared(pScrn->entityList[0])) { + if (xf86IsPrimInitDone(pScrn->entityList[0])) { + info->IsSecondary = TRUE; + pAMDGPUEnt->pSecondaryScrn = pScrn; + } else { + info->IsPrimary = TRUE; + xf86SetPrimInitDone(pScrn->entityList[0]); + pAMDGPUEnt->pPrimaryScrn = pScrn; + pAMDGPUEnt->HasSecondary = FALSE; + } + } + + info->PciInfo = xf86GetPciInfoForEntity(info->pEnt->index); + pScrn->monitor = pScrn->confScreen->monitor; + + if (!AMDGPUPreInitVisual(pScrn)) + goto fail; + + xf86CollectOptions(pScrn, NULL); + if (!(info->Options = malloc(sizeof(AMDGPUOptions_KMS)))) + goto fail; + + memcpy(info->Options, AMDGPUOptions_KMS, sizeof(AMDGPUOptions_KMS)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options); + + if (!AMDGPUPreInitWeight(pScrn)) + goto fail; + + if (!AMDGPUPreInitChipType_KMS(pScrn)) + goto fail; + + amdgpu_reference_drm_fd(pScrn); + + info->dri2.available = FALSE; + info->dri2.enabled = FALSE; + info->dri2.pKernelDRMVersion = drmGetVersion(info->dri2.drm_fd); + if (info->dri2.pKernelDRMVersion == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "AMDGPUDRIGetVersion failed to get the DRM version\n"); + goto fail; + } + + if (!AMDGPUPreInitAccel_KMS(pScrn)) + goto fail; + + AMDGPUSetupCapabilities(pScrn); + + /* don't enable tiling if accel is not enabled */ + if (info->use_glamor) { + /* set default group bytes, overridden by kernel info below */ + info->group_bytes = 256; + info->have_tiling_info = FALSE; + amdgpu_get_tile_config(pScrn); + } + + info->allowPageFlip = xf86ReturnOptValBool(info->Options, + OPTION_PAGE_FLIP, + TRUE); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "KMS Pageflipping: %sabled\n", + info->allowPageFlip ? "en" : "dis"); + + if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) == + FALSE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Kernel modesetting setup failed\n"); + goto fail; + } + + if (info->drmmode.mode_res->count_crtcs == 1) + pAMDGPUEnt->HasCRTC2 = FALSE; + else + pAMDGPUEnt->HasCRTC2 = TRUE; + + info->cursor_w = CURSOR_WIDTH_CIK; + info->cursor_h = CURSOR_HEIGHT_CIK; + + amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_GTT, + &heap_size, &max_allocation); + info->gart_size = heap_size; + amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_VRAM, + &heap_size, &max_allocation); + info->vram_size = max_allocation; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "mem size init: gart size :%llx vram size: s:%llx visible:%llx\n", + (unsigned long long)info->gart_size, + (unsigned long long)heap_size, + (unsigned long long)max_allocation); + + cpp = pScrn->bitsPerPixel / 8; + pScrn->displayWidth = + AMDGPU_ALIGN(pScrn->virtualX, drmmode_get_pitch_align(pScrn, cpp)); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Get ScreenInit function */ + if (!xf86LoadSubModule(pScrn, "fb")) + return FALSE; + + if (!xf86SetGamma(pScrn, zeros)) + return FALSE; + + if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) { + if (!xf86LoadSubModule(pScrn, "ramdac")) + return FALSE; + } + + if (pScrn->modes == NULL +#ifdef XSERVER_PLATFORM_BUS + && !pScrn->is_gpu +#endif + ) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); + goto fail; + } + + return TRUE; +fail: + AMDGPUFreeRec(pScrn); + return FALSE; + +} + +static Bool AMDGPUCursorInit_KMS(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + + return xf86_cursors_init(pScreen, info->cursor_w, info->cursor_h, + (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 | + HARDWARE_CURSOR_UPDATE_UNHIDDEN | + HARDWARE_CURSOR_ARGB)); +} + +void AMDGPUBlank(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + int o, c; + + for (c = 0; c < xf86_config->num_crtc; c++) { + crtc = xf86_config->crtc[c]; + for (o = 0; o < xf86_config->num_output; o++) { + output = xf86_config->output[o]; + if (output->crtc != crtc) + continue; + + output->funcs->dpms(output, DPMSModeOff); + } + crtc->funcs->dpms(crtc, DPMSModeOff); + } +} + +void AMDGPUUnblank(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + int o, c; + for (c = 0; c < xf86_config->num_crtc; c++) { + crtc = xf86_config->crtc[c]; + if (!crtc->enabled) + continue; + crtc->funcs->dpms(crtc, DPMSModeOn); + for (o = 0; o < xf86_config->num_output; o++) { + output = xf86_config->output[o]; + if (output->crtc != crtc) + continue; + output->funcs->dpms(output, DPMSModeOn); + } + } +} + +static Bool AMDGPUSaveScreen_KMS(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + Bool unblank; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "AMDGPUSaveScreen(%d)\n", mode); + + unblank = xf86IsUnblank(mode); + if (unblank) + SetTimeSinceLastInputEvent(); + + if ((pScrn != NULL) && pScrn->vtSema) { + if (unblank) + AMDGPUUnblank(pScrn); + else + AMDGPUBlank(pScrn); + } + return TRUE; +} + +/* Called at the end of each server generation. Restore the original + * text mode, unmap video memory, and unwrap and call the saved + * CloseScreen function. + */ +static Bool AMDGPUCloseScreen_KMS(CLOSE_SCREEN_ARGS_DECL) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "AMDGPUCloseScreen\n"); + + drmmode_uevent_fini(pScrn, &info->drmmode); + + DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn); + + drmDropMaster(info->dri2.drm_fd); + + drmmode_fini(pScrn, &info->drmmode); + if (info->dri2.enabled) { + amdgpu_dri2_close_screen(pScreen); + } + pScrn->vtSema = FALSE; + xf86ClearPrimInitDone(info->pEnt->index); + pScreen->BlockHandler = info->BlockHandler; + pScreen->CloseScreen = info->CloseScreen; + return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS); +} + +void AMDGPUFreeScreen_KMS(FREE_SCREEN_ARGS_DECL) +{ + SCRN_INFO_PTR(arg); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "AMDGPUFreeScreen\n"); + + /* when server quits at PreInit, we don't need do this anymore */ + if (!info) + return; + + AMDGPUFreeRec(pScrn); +} + +Bool AMDGPUScreenInit_KMS(SCREEN_INIT_ARGS_DECL) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + int subPixelOrder = SubPixelUnknown; + char *s; + void *front_ptr; + int ret; + + pScrn->fbOffset = 0; + + miClearVisualTypes(); + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + miSetPixmapDepths(); + + ret = drmSetMaster(info->dri2.drm_fd); + if (ret) { + ErrorF("Unable to retrieve master\n"); + return FALSE; + } + info->directRenderingEnabled = FALSE; + if (info->shadow_fb == FALSE) + info->directRenderingEnabled = amdgpu_dri2_screen_init(pScreen); + + if (!amdgpu_setup_kernel_mem(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "amdgpu_setup_kernel_mem failed\n"); + return FALSE; + } + front_ptr = info->front_buffer->cpu_ptr; + + if (info->shadow_fb) { + info->fb_shadow = calloc(1, + pScrn->displayWidth * pScrn->virtualY * + ((pScrn->bitsPerPixel + 7) >> 3)); + if (info->fb_shadow == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate shadow framebuffer\n"); + info->shadow_fb = FALSE; + } else { + if (!fbScreenInit(pScreen, info->fb_shadow, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, + pScrn->bitsPerPixel)) + return FALSE; + } + } + + if (info->shadow_fb == FALSE) { + /* Init fb layer */ + if (!fbScreenInit(pScreen, front_ptr, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, + pScrn->bitsPerPixel)) + return FALSE; + } + + xf86SetBlackWhitePixels(pScreen); + + if (pScrn->bitsPerPixel > 8) { + VisualPtr visual; + + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + /* Must be after RGB order fixed */ + fbPictureInit(pScreen, 0, 0); + +#ifdef RENDER + if ((s = xf86GetOptValString(info->Options, OPTION_SUBPIXEL_ORDER))) { + if (strcmp(s, "RGB") == 0) + subPixelOrder = SubPixelHorizontalRGB; + else if (strcmp(s, "BGR") == 0) + subPixelOrder = SubPixelHorizontalBGR; + else if (strcmp(s, "NONE") == 0) + subPixelOrder = SubPixelNone; + PictureSetSubpixelOrder(pScreen, subPixelOrder); + } +#endif + + pScrn->vtSema = TRUE; + xf86SetBackingStore(pScreen); + + if (info->directRenderingEnabled) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Direct rendering enabled\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Direct rendering disabled\n"); + } + + if (info->use_glamor && info->directRenderingEnabled) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "Initializing Acceleration\n"); + if (amdgpu_glamor_init(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Acceleration enabled\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Acceleration initialization failed\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "2D and 3D acceleration disabled\n"); + info->use_glamor = FALSE; + } + } else if (info->directRenderingEnabled) { + if (!amdgpu_pixmap_init(pScreen)) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D acceleration disabled\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration disabled\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D and 3D cceleration disabled\n"); + } + + /* Init DPMS */ + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "Initializing DPMS\n"); + xf86DPMSInit(pScreen, xf86DPMSSet, 0); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "Initializing Cursor\n"); + + /* Set Silken Mouse */ + xf86SetSilkenMouse(pScreen); + + /* Cursor setup */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) { + if (AMDGPUCursorInit_KMS(pScreen)) { + } + } + + /* DGA setup */ +#ifdef XFreeXDGA + /* DGA is dangerous on kms as the base and framebuffer location may change: + * http://lists.freedesktop.org/archives/xorg-devel/2009-September/002113.html + */ + /* xf86DiDGAInit(pScreen, info->LinearAddr + pScrn->fbOffset); */ +#endif + if (info->shadow_fb == FALSE) { + /* Init Xv */ + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "Initializing Xv\n"); + AMDGPUInitVideo(pScreen); + } + + if (info->shadow_fb == TRUE) { + if (!shadowSetup(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Shadowfb initialization failed\n"); + return FALSE; + } + } + pScrn->pScreen = pScreen; + + /* Provide SaveScreen & wrap BlockHandler and CloseScreen */ + /* Wrap CloseScreen */ + info->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = AMDGPUCloseScreen_KMS; + pScreen->SaveScreen = AMDGPUSaveScreen_KMS; + info->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = AMDGPUBlockHandler_KMS; + + if (!AddCallback(&FlushCallback, amdgpu_flush_callback, pScrn)) + return FALSE; + + info->CreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS; + +#ifdef AMDGPU_PIXMAP_SHARING + pScreen->StartPixmapTracking = PixmapStartDirtyTracking; + pScreen->StopPixmapTracking = PixmapStopDirtyTracking; +#endif + + if (!xf86CrtcScreenInit(pScreen)) + return FALSE; + + /* Wrap pointer motion to flip touch screen around */ +// info->PointerMoved = pScrn->PointerMoved; +// pScrn->PointerMoved = AMDGPUPointerMoved; + + if (!drmmode_setup_colormap(pScreen, pScrn)) + return FALSE; + + /* Note unused options */ + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + + drmmode_init(pScrn, &info->drmmode); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "AMDGPUScreenInit finished\n"); + + return TRUE; +} + +Bool AMDGPUEnterVT_KMS(VT_FUNC_ARGS_DECL) +{ + SCRN_INFO_PTR(arg); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + int ret; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "AMDGPUEnterVT_KMS\n"); + + ret = drmSetMaster(info->dri2.drm_fd); + if (ret) + ErrorF("Unable to retrieve master\n"); + + pScrn->vtSema = TRUE; + + if (!drmmode_set_desired_modes(pScrn, &info->drmmode)) + return FALSE; + + return TRUE; +} + +void AMDGPULeaveVT_KMS(VT_FUNC_ARGS_DECL) +{ + SCRN_INFO_PTR(arg); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "AMDGPULeaveVT_KMS\n"); + + drmDropMaster(info->dri2.drm_fd); + + xf86RotateFreeShadow(pScrn); + + xf86_hide_cursors(pScrn); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, + "Ok, leaving now...\n"); +} + +Bool AMDGPUSwitchMode_KMS(SWITCH_MODE_ARGS_DECL) +{ + SCRN_INFO_PTR(arg); + Bool ret; + ret = xf86SetSingleMode(pScrn, mode, RR_Rotate_0); + return ret; + +} + +void AMDGPUAdjustFrame_KMS(ADJUST_FRAME_ARGS_DECL) +{ + SCRN_INFO_PTR(arg); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + drmmode_adjust_frame(pScrn, &info->drmmode, x, y); + return; +} + +static Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int cpp = info->pixel_bytes; + int cursor_size; + int c; + + cursor_size = info->cursor_w * info->cursor_h * 4; + cursor_size = AMDGPU_ALIGN(cursor_size, AMDGPU_GPU_PAGE_SIZE); + for (c = 0; c < xf86_config->num_crtc; c++) { + /* cursor objects */ + if (info->cursor_buffer[c] == NULL) { + if (info->gbm) { + info->cursor_buffer[c] = (struct amdgpu_buffer *)calloc(1, sizeof(struct amdgpu_buffer)); + if (!info->cursor_buffer[c]) { + return FALSE; + } + info->cursor_buffer[c]->ref_count = 1; + + info->cursor_buffer[c]->bo.gbm = gbm_bo_create(info->gbm, + info->cursor_w, + info->cursor_h, + GBM_FORMAT_ARGB8888, + GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE); + if (!info->cursor_buffer[c]->bo.gbm) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate cursor buffer memory\n"); + free(info->cursor_buffer[c]); + return FALSE; + } + } else { + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); + info->cursor_buffer[c] = amdgpu_bo_open(pAMDGPUEnt->pDev, + cursor_size, + 0, + AMDGPU_GEM_DOMAIN_VRAM); + if (!(info->cursor_buffer[c])) { + ErrorF("Failed to allocate cursor buffer memory\n"); + return FALSE; + } + + if (amdgpu_bo_cpu_map(info->cursor_buffer[c]->bo.amdgpu, + &info->cursor_buffer[c]->cpu_ptr)) { + ErrorF("Failed to map cursor buffer memory\n"); + } + } + + drmmode_set_cursor(pScrn, &info->drmmode, c, + info->cursor_buffer[c]); + } + } + + if (info->front_buffer == NULL) { + int pitch; + int hint = info->use_glamor ? 0 : AMDGPU_CREATE_PIXMAP_LINEAR; + + info->front_buffer = + amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX, + pScrn->virtualY, pScrn->depth, + hint, pScrn->bitsPerPixel, + &pitch); + if (!(info->front_buffer)) { + ErrorF("Failed to allocate front buffer memory\n"); + return FALSE; + } + + if (amdgpu_bo_map(pScrn, info->front_buffer)) { + ErrorF("Failed to map front buffer memory\n"); + return FALSE; + } + + pScrn->displayWidth = pitch / cpp; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Front buffer pitch: %d bytes\n", + pScrn->displayWidth * cpp); + return TRUE; +} + +/* Used to disallow modes that are not supported by the hardware */ +ModeStatus AMDGPUValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, + Bool verbose, int flag) +{ + /* There are problems with double scan mode at high clocks + * They're likely related PLL and display buffer settings. + * Disable these modes for now. + */ + if (mode->Flags & V_DBLSCAN) { + if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768)) + return MODE_CLOCK_RANGE; + } + return MODE_OK; +} |