1926deccbSFrançois Tigeot /* 2926deccbSFrançois Tigeot * Copyright 2008 Advanced Micro Devices, Inc. 3926deccbSFrançois Tigeot * Copyright 2008 Red Hat Inc. 4926deccbSFrançois Tigeot * Copyright 2009 Jerome Glisse. 5926deccbSFrançois Tigeot * 6926deccbSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 7926deccbSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 8926deccbSFrançois Tigeot * to deal in the Software without restriction, including without limitation 9926deccbSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10926deccbSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 11926deccbSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 12926deccbSFrançois Tigeot * 13926deccbSFrançois Tigeot * The above copyright notice and this permission notice shall be included in 14926deccbSFrançois Tigeot * all copies or substantial portions of the Software. 15926deccbSFrançois Tigeot * 16926deccbSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17926deccbSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18926deccbSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19926deccbSFrançois Tigeot * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20926deccbSFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21926deccbSFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22926deccbSFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE. 23926deccbSFrançois Tigeot * 24926deccbSFrançois Tigeot * Authors: Dave Airlie 25926deccbSFrançois Tigeot * Alex Deucher 26926deccbSFrançois Tigeot * Jerome Glisse 27926deccbSFrançois Tigeot * 28926deccbSFrançois Tigeot * $FreeBSD: head/sys/dev/drm2/radeon/radeon_device.c 255573 2013-09-14 17:24:41Z dumbbell $ 29926deccbSFrançois Tigeot */ 30926deccbSFrançois Tigeot #include <drm/drmP.h> 314250aa95Szrj #include "drm/drm_legacy.h" /* for drm_dma_handle_t */ 32926deccbSFrançois Tigeot #include <drm/drm_crtc_helper.h> 3383b4b9b9SFrançois Tigeot #include <drm/radeon_drm.h> 3457e252bfSMichael Neumann #include <asm/io.h> 35926deccbSFrançois Tigeot #include "radeon_reg.h" 36926deccbSFrançois Tigeot #include "radeon.h" 37926deccbSFrançois Tigeot #include "atom.h" 38926deccbSFrançois Tigeot 39926deccbSFrançois Tigeot static const char radeon_family_name[][16] = { 40926deccbSFrançois Tigeot "R100", 41926deccbSFrançois Tigeot "RV100", 42926deccbSFrançois Tigeot "RS100", 43926deccbSFrançois Tigeot "RV200", 44926deccbSFrançois Tigeot "RS200", 45926deccbSFrançois Tigeot "R200", 46926deccbSFrançois Tigeot "RV250", 47926deccbSFrançois Tigeot "RS300", 48926deccbSFrançois Tigeot "RV280", 49926deccbSFrançois Tigeot "R300", 50926deccbSFrançois Tigeot "R350", 51926deccbSFrançois Tigeot "RV350", 52926deccbSFrançois Tigeot "RV380", 53926deccbSFrançois Tigeot "R420", 54926deccbSFrançois Tigeot "R423", 55926deccbSFrançois Tigeot "RV410", 56926deccbSFrançois Tigeot "RS400", 57926deccbSFrançois Tigeot "RS480", 58926deccbSFrançois Tigeot "RS600", 59926deccbSFrançois Tigeot "RS690", 60926deccbSFrançois Tigeot "RS740", 61926deccbSFrançois Tigeot "RV515", 62926deccbSFrançois Tigeot "R520", 63926deccbSFrançois Tigeot "RV530", 64926deccbSFrançois Tigeot "RV560", 65926deccbSFrançois Tigeot "RV570", 66926deccbSFrançois Tigeot "R580", 67926deccbSFrançois Tigeot "R600", 68926deccbSFrançois Tigeot "RV610", 69926deccbSFrançois Tigeot "RV630", 70926deccbSFrançois Tigeot "RV670", 71926deccbSFrançois Tigeot "RV620", 72926deccbSFrançois Tigeot "RV635", 73926deccbSFrançois Tigeot "RS780", 74926deccbSFrançois Tigeot "RS880", 75926deccbSFrançois Tigeot "RV770", 76926deccbSFrançois Tigeot "RV730", 77926deccbSFrançois Tigeot "RV710", 78926deccbSFrançois Tigeot "RV740", 79926deccbSFrançois Tigeot "CEDAR", 80926deccbSFrançois Tigeot "REDWOOD", 81926deccbSFrançois Tigeot "JUNIPER", 82926deccbSFrançois Tigeot "CYPRESS", 83926deccbSFrançois Tigeot "HEMLOCK", 84926deccbSFrançois Tigeot "PALM", 85926deccbSFrançois Tigeot "SUMO", 86926deccbSFrançois Tigeot "SUMO2", 87926deccbSFrançois Tigeot "BARTS", 88926deccbSFrançois Tigeot "TURKS", 89926deccbSFrançois Tigeot "CAICOS", 90926deccbSFrançois Tigeot "CAYMAN", 91926deccbSFrançois Tigeot "ARUBA", 92926deccbSFrançois Tigeot "TAHITI", 93926deccbSFrançois Tigeot "PITCAIRN", 94926deccbSFrançois Tigeot "VERDE", 95b403bed8SMichael Neumann "OLAND", 96f43cf1b1SMichael Neumann "HAINAN", 9757e252bfSMichael Neumann "BONAIRE", 9857e252bfSMichael Neumann "KAVERI", 9957e252bfSMichael Neumann "KABINI", 100c6f73aabSFrançois Tigeot "HAWAII", 101c6f73aabSFrançois Tigeot "MULLINS", 102926deccbSFrançois Tigeot "LAST", 103926deccbSFrançois Tigeot }; 104926deccbSFrançois Tigeot 105c6f73aabSFrançois Tigeot #define RADEON_PX_QUIRK_DISABLE_PX (1 << 0) 106c6f73aabSFrançois Tigeot #define RADEON_PX_QUIRK_LONG_WAKEUP (1 << 1) 107c6f73aabSFrançois Tigeot 108c6f73aabSFrançois Tigeot struct radeon_px_quirk { 109c6f73aabSFrançois Tigeot u32 chip_vendor; 110c6f73aabSFrançois Tigeot u32 chip_device; 111c6f73aabSFrançois Tigeot u32 subsys_vendor; 112c6f73aabSFrançois Tigeot u32 subsys_device; 113c6f73aabSFrançois Tigeot u32 px_quirk_flags; 114c6f73aabSFrançois Tigeot }; 115c6f73aabSFrançois Tigeot 116c6f73aabSFrançois Tigeot static struct radeon_px_quirk radeon_px_quirk_list[] = { 117c6f73aabSFrançois Tigeot /* Acer aspire 5560g (CPU: AMD A4-3305M; GPU: AMD Radeon HD 6480g + 7470m) 118c6f73aabSFrançois Tigeot * https://bugzilla.kernel.org/show_bug.cgi?id=74551 119c6f73aabSFrançois Tigeot */ 120c6f73aabSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6760, 0x1025, 0x0672, RADEON_PX_QUIRK_DISABLE_PX }, 121c6f73aabSFrançois Tigeot /* Asus K73TA laptop with AMD A6-3400M APU and Radeon 6550 GPU 122c6f73aabSFrançois Tigeot * https://bugzilla.kernel.org/show_bug.cgi?id=51381 123c6f73aabSFrançois Tigeot */ 124c6f73aabSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX }, 125c6f73aabSFrançois Tigeot /* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU 126c6f73aabSFrançois Tigeot * https://bugzilla.kernel.org/show_bug.cgi?id=51381 127c6f73aabSFrançois Tigeot */ 128c6f73aabSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX }, 129c6f73aabSFrançois Tigeot /* macbook pro 8.2 */ 130c6f73aabSFrançois Tigeot { PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP }, 131c6f73aabSFrançois Tigeot { 0, 0, 0, 0, 0 }, 132c6f73aabSFrançois Tigeot }; 133c6f73aabSFrançois Tigeot 134c6f73aabSFrançois Tigeot bool radeon_is_px(struct drm_device *dev) 135c6f73aabSFrançois Tigeot { 136c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 137c6f73aabSFrançois Tigeot 138c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 139c6f73aabSFrançois Tigeot return true; 140c6f73aabSFrançois Tigeot return false; 141c6f73aabSFrançois Tigeot } 142c6f73aabSFrançois Tigeot 143c6f73aabSFrançois Tigeot static void radeon_device_handle_px_quirks(struct radeon_device *rdev) 144c6f73aabSFrançois Tigeot { 145c6f73aabSFrançois Tigeot struct radeon_px_quirk *p = radeon_px_quirk_list; 146c6f73aabSFrançois Tigeot 147c6f73aabSFrançois Tigeot /* Apply PX quirks */ 148c6f73aabSFrançois Tigeot while (p && p->chip_device != 0) { 149c6f73aabSFrançois Tigeot if (rdev->pdev->vendor == p->chip_vendor && 150c6f73aabSFrançois Tigeot rdev->pdev->device == p->chip_device && 151c6f73aabSFrançois Tigeot rdev->pdev->subsystem_vendor == p->subsys_vendor && 152c6f73aabSFrançois Tigeot rdev->pdev->subsystem_device == p->subsys_device) { 153c6f73aabSFrançois Tigeot rdev->px_quirk_flags = p->px_quirk_flags; 154c6f73aabSFrançois Tigeot break; 155c6f73aabSFrançois Tigeot } 156c6f73aabSFrançois Tigeot ++p; 157c6f73aabSFrançois Tigeot } 158c6f73aabSFrançois Tigeot 159c6f73aabSFrançois Tigeot if (rdev->px_quirk_flags & RADEON_PX_QUIRK_DISABLE_PX) 160c6f73aabSFrançois Tigeot rdev->flags &= ~RADEON_IS_PX; 161c6f73aabSFrançois Tigeot } 162c6f73aabSFrançois Tigeot 163926deccbSFrançois Tigeot /** 164f43cf1b1SMichael Neumann * radeon_program_register_sequence - program an array of registers. 165f43cf1b1SMichael Neumann * 166f43cf1b1SMichael Neumann * @rdev: radeon_device pointer 167f43cf1b1SMichael Neumann * @registers: pointer to the register array 168f43cf1b1SMichael Neumann * @array_size: size of the register array 169f43cf1b1SMichael Neumann * 170f43cf1b1SMichael Neumann * Programs an array or registers with and and or masks. 171f43cf1b1SMichael Neumann * This is a helper for setting golden registers. 172f43cf1b1SMichael Neumann */ 173f43cf1b1SMichael Neumann void radeon_program_register_sequence(struct radeon_device *rdev, 174f43cf1b1SMichael Neumann const u32 *registers, 175f43cf1b1SMichael Neumann const u32 array_size) 176f43cf1b1SMichael Neumann { 177f43cf1b1SMichael Neumann u32 tmp, reg, and_mask, or_mask; 178f43cf1b1SMichael Neumann int i; 179f43cf1b1SMichael Neumann 180f43cf1b1SMichael Neumann if (array_size % 3) 181f43cf1b1SMichael Neumann return; 182f43cf1b1SMichael Neumann 183f43cf1b1SMichael Neumann for (i = 0; i < array_size; i +=3) { 184f43cf1b1SMichael Neumann reg = registers[i + 0]; 185f43cf1b1SMichael Neumann and_mask = registers[i + 1]; 186f43cf1b1SMichael Neumann or_mask = registers[i + 2]; 187f43cf1b1SMichael Neumann 188f43cf1b1SMichael Neumann if (and_mask == 0xffffffff) { 189f43cf1b1SMichael Neumann tmp = or_mask; 190f43cf1b1SMichael Neumann } else { 191f43cf1b1SMichael Neumann tmp = RREG32(reg); 192f43cf1b1SMichael Neumann tmp &= ~and_mask; 193f43cf1b1SMichael Neumann tmp |= or_mask; 194f43cf1b1SMichael Neumann } 195f43cf1b1SMichael Neumann WREG32(reg, tmp); 196f43cf1b1SMichael Neumann } 197f43cf1b1SMichael Neumann } 198f43cf1b1SMichael Neumann 199c6f73aabSFrançois Tigeot void radeon_pci_config_reset(struct radeon_device *rdev) 200c6f73aabSFrançois Tigeot { 201c6f73aabSFrançois Tigeot pci_write_config_dword(rdev->pdev, 0x7c, RADEON_ASIC_RESET_DATA); 202c6f73aabSFrançois Tigeot } 203c6f73aabSFrançois Tigeot 204f43cf1b1SMichael Neumann /** 205926deccbSFrançois Tigeot * radeon_surface_init - Clear GPU surface registers. 206926deccbSFrançois Tigeot * 207926deccbSFrançois Tigeot * @rdev: radeon_device pointer 208926deccbSFrançois Tigeot * 209926deccbSFrançois Tigeot * Clear GPU surface registers (r1xx-r5xx). 210926deccbSFrançois Tigeot */ 211926deccbSFrançois Tigeot void radeon_surface_init(struct radeon_device *rdev) 212926deccbSFrançois Tigeot { 213926deccbSFrançois Tigeot /* FIXME: check this out */ 214926deccbSFrançois Tigeot if (rdev->family < CHIP_R600) { 215926deccbSFrançois Tigeot int i; 216926deccbSFrançois Tigeot 217926deccbSFrançois Tigeot for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) { 218926deccbSFrançois Tigeot if (rdev->surface_regs[i].bo) 219926deccbSFrançois Tigeot radeon_bo_get_surface_reg(rdev->surface_regs[i].bo); 220926deccbSFrançois Tigeot else 221926deccbSFrançois Tigeot radeon_clear_surface_reg(rdev, i); 222926deccbSFrançois Tigeot } 223926deccbSFrançois Tigeot /* enable surfaces */ 224926deccbSFrançois Tigeot WREG32(RADEON_SURFACE_CNTL, 0); 225926deccbSFrançois Tigeot } 226926deccbSFrançois Tigeot } 227926deccbSFrançois Tigeot 228926deccbSFrançois Tigeot /* 229926deccbSFrançois Tigeot * GPU scratch registers helpers function. 230926deccbSFrançois Tigeot */ 231926deccbSFrançois Tigeot /** 232926deccbSFrançois Tigeot * radeon_scratch_init - Init scratch register driver information. 233926deccbSFrançois Tigeot * 234926deccbSFrançois Tigeot * @rdev: radeon_device pointer 235926deccbSFrançois Tigeot * 236926deccbSFrançois Tigeot * Init CP scratch register driver information (r1xx-r5xx) 237926deccbSFrançois Tigeot */ 238926deccbSFrançois Tigeot void radeon_scratch_init(struct radeon_device *rdev) 239926deccbSFrançois Tigeot { 240926deccbSFrançois Tigeot int i; 241926deccbSFrançois Tigeot 242926deccbSFrançois Tigeot /* FIXME: check this out */ 243926deccbSFrançois Tigeot if (rdev->family < CHIP_R300) { 244926deccbSFrançois Tigeot rdev->scratch.num_reg = 5; 245926deccbSFrançois Tigeot } else { 246926deccbSFrançois Tigeot rdev->scratch.num_reg = 7; 247926deccbSFrançois Tigeot } 248926deccbSFrançois Tigeot rdev->scratch.reg_base = RADEON_SCRATCH_REG0; 249926deccbSFrançois Tigeot for (i = 0; i < rdev->scratch.num_reg; i++) { 250926deccbSFrançois Tigeot rdev->scratch.free[i] = true; 251926deccbSFrançois Tigeot rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4); 252926deccbSFrançois Tigeot } 253926deccbSFrançois Tigeot } 254926deccbSFrançois Tigeot 255926deccbSFrançois Tigeot /** 256926deccbSFrançois Tigeot * radeon_scratch_get - Allocate a scratch register 257926deccbSFrançois Tigeot * 258926deccbSFrançois Tigeot * @rdev: radeon_device pointer 259926deccbSFrançois Tigeot * @reg: scratch register mmio offset 260926deccbSFrançois Tigeot * 261926deccbSFrançois Tigeot * Allocate a CP scratch register for use by the driver (all asics). 262926deccbSFrançois Tigeot * Returns 0 on success or -EINVAL on failure. 263926deccbSFrançois Tigeot */ 264926deccbSFrançois Tigeot int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg) 265926deccbSFrançois Tigeot { 266926deccbSFrançois Tigeot int i; 267926deccbSFrançois Tigeot 268926deccbSFrançois Tigeot for (i = 0; i < rdev->scratch.num_reg; i++) { 269926deccbSFrançois Tigeot if (rdev->scratch.free[i]) { 270926deccbSFrançois Tigeot rdev->scratch.free[i] = false; 271926deccbSFrançois Tigeot *reg = rdev->scratch.reg[i]; 272926deccbSFrançois Tigeot return 0; 273926deccbSFrançois Tigeot } 274926deccbSFrançois Tigeot } 275926deccbSFrançois Tigeot return -EINVAL; 276926deccbSFrançois Tigeot } 277926deccbSFrançois Tigeot 278926deccbSFrançois Tigeot /** 279926deccbSFrançois Tigeot * radeon_scratch_free - Free a scratch register 280926deccbSFrançois Tigeot * 281926deccbSFrançois Tigeot * @rdev: radeon_device pointer 282926deccbSFrançois Tigeot * @reg: scratch register mmio offset 283926deccbSFrançois Tigeot * 284926deccbSFrançois Tigeot * Free a CP scratch register allocated for use by the driver (all asics) 285926deccbSFrançois Tigeot */ 286926deccbSFrançois Tigeot void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg) 287926deccbSFrançois Tigeot { 288926deccbSFrançois Tigeot int i; 289926deccbSFrançois Tigeot 290926deccbSFrançois Tigeot for (i = 0; i < rdev->scratch.num_reg; i++) { 291926deccbSFrançois Tigeot if (rdev->scratch.reg[i] == reg) { 292926deccbSFrançois Tigeot rdev->scratch.free[i] = true; 293926deccbSFrançois Tigeot return; 294926deccbSFrançois Tigeot } 295926deccbSFrançois Tigeot } 296926deccbSFrançois Tigeot } 297926deccbSFrançois Tigeot 298926deccbSFrançois Tigeot /* 29957e252bfSMichael Neumann * GPU doorbell aperture helpers function. 30057e252bfSMichael Neumann */ 30157e252bfSMichael Neumann /** 30257e252bfSMichael Neumann * radeon_doorbell_init - Init doorbell driver information. 30357e252bfSMichael Neumann * 30457e252bfSMichael Neumann * @rdev: radeon_device pointer 30557e252bfSMichael Neumann * 30657e252bfSMichael Neumann * Init doorbell driver information (CIK) 30757e252bfSMichael Neumann * Returns 0 on success, error on failure. 30857e252bfSMichael Neumann */ 309c6f73aabSFrançois Tigeot static int radeon_doorbell_init(struct radeon_device *rdev) 31057e252bfSMichael Neumann { 31157e252bfSMichael Neumann /* doorbell bar mapping */ 3124a26d795SImre Vadasz rdev->doorbell.base = pci_resource_start(rdev->pdev, 2); 3134a26d795SImre Vadasz rdev->doorbell.size = pci_resource_len(rdev->pdev, 2); 31457e252bfSMichael Neumann 315c6f73aabSFrançois Tigeot rdev->doorbell.num_doorbells = min_t(u32, rdev->doorbell.size / sizeof(u32), RADEON_MAX_DOORBELLS); 316c6f73aabSFrançois Tigeot if (rdev->doorbell.num_doorbells == 0) 317c6f73aabSFrançois Tigeot return -EINVAL; 31857e252bfSMichael Neumann 319c6f73aabSFrançois Tigeot rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.num_doorbells * sizeof(u32)); 32057e252bfSMichael Neumann if (rdev->doorbell.ptr == NULL) { 32157e252bfSMichael Neumann return -ENOMEM; 32257e252bfSMichael Neumann } 32357e252bfSMichael Neumann DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base); 32457e252bfSMichael Neumann DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size); 32557e252bfSMichael Neumann 326c6f73aabSFrançois Tigeot memset(&rdev->doorbell.used, 0, sizeof(rdev->doorbell.used)); 32757e252bfSMichael Neumann 32857e252bfSMichael Neumann return 0; 32957e252bfSMichael Neumann } 33057e252bfSMichael Neumann 33157e252bfSMichael Neumann /** 33257e252bfSMichael Neumann * radeon_doorbell_fini - Tear down doorbell driver information. 33357e252bfSMichael Neumann * 33457e252bfSMichael Neumann * @rdev: radeon_device pointer 33557e252bfSMichael Neumann * 33657e252bfSMichael Neumann * Tear down doorbell driver information (CIK) 33757e252bfSMichael Neumann */ 338c6f73aabSFrançois Tigeot static void radeon_doorbell_fini(struct radeon_device *rdev) 33957e252bfSMichael Neumann { 34024409b39SFrançois Tigeot iounmap(rdev->doorbell.ptr); 34157e252bfSMichael Neumann rdev->doorbell.ptr = NULL; 34257e252bfSMichael Neumann } 34357e252bfSMichael Neumann 34457e252bfSMichael Neumann /** 345c6f73aabSFrançois Tigeot * radeon_doorbell_get - Allocate a doorbell entry 34657e252bfSMichael Neumann * 34757e252bfSMichael Neumann * @rdev: radeon_device pointer 348c6f73aabSFrançois Tigeot * @doorbell: doorbell index 34957e252bfSMichael Neumann * 350c6f73aabSFrançois Tigeot * Allocate a doorbell for use by the driver (all asics). 35157e252bfSMichael Neumann * Returns 0 on success or -EINVAL on failure. 35257e252bfSMichael Neumann */ 35357e252bfSMichael Neumann int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell) 35457e252bfSMichael Neumann { 355c6f73aabSFrançois Tigeot unsigned long offset = find_first_zero_bit(rdev->doorbell.used, rdev->doorbell.num_doorbells); 356c6f73aabSFrançois Tigeot if (offset < rdev->doorbell.num_doorbells) { 357c6f73aabSFrançois Tigeot __set_bit(offset, rdev->doorbell.used); 358c6f73aabSFrançois Tigeot *doorbell = offset; 35957e252bfSMichael Neumann return 0; 360c6f73aabSFrançois Tigeot } else { 36157e252bfSMichael Neumann return -EINVAL; 36257e252bfSMichael Neumann } 363c6f73aabSFrançois Tigeot } 36457e252bfSMichael Neumann 36557e252bfSMichael Neumann /** 366c6f73aabSFrançois Tigeot * radeon_doorbell_free - Free a doorbell entry 36757e252bfSMichael Neumann * 36857e252bfSMichael Neumann * @rdev: radeon_device pointer 369c6f73aabSFrançois Tigeot * @doorbell: doorbell index 37057e252bfSMichael Neumann * 371c6f73aabSFrançois Tigeot * Free a doorbell allocated for use by the driver (all asics) 37257e252bfSMichael Neumann */ 37357e252bfSMichael Neumann void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell) 37457e252bfSMichael Neumann { 375c6f73aabSFrançois Tigeot if (doorbell < rdev->doorbell.num_doorbells) 376c6f73aabSFrançois Tigeot __clear_bit(doorbell, rdev->doorbell.used); 37757e252bfSMichael Neumann } 37857e252bfSMichael Neumann 37957e252bfSMichael Neumann /* 380926deccbSFrançois Tigeot * radeon_wb_*() 381926deccbSFrançois Tigeot * Writeback is the the method by which the the GPU updates special pages 382926deccbSFrançois Tigeot * in memory with the status of certain GPU events (fences, ring pointers, 383926deccbSFrançois Tigeot * etc.). 384926deccbSFrançois Tigeot */ 385926deccbSFrançois Tigeot 386926deccbSFrançois Tigeot /** 387926deccbSFrançois Tigeot * radeon_wb_disable - Disable Writeback 388926deccbSFrançois Tigeot * 389926deccbSFrançois Tigeot * @rdev: radeon_device pointer 390926deccbSFrançois Tigeot * 391926deccbSFrançois Tigeot * Disables Writeback (all asics). Used for suspend. 392926deccbSFrançois Tigeot */ 393926deccbSFrançois Tigeot void radeon_wb_disable(struct radeon_device *rdev) 394926deccbSFrançois Tigeot { 395926deccbSFrançois Tigeot rdev->wb.enabled = false; 396926deccbSFrançois Tigeot } 397926deccbSFrançois Tigeot 398926deccbSFrançois Tigeot /** 399926deccbSFrançois Tigeot * radeon_wb_fini - Disable Writeback and free memory 400926deccbSFrançois Tigeot * 401926deccbSFrançois Tigeot * @rdev: radeon_device pointer 402926deccbSFrançois Tigeot * 403926deccbSFrançois Tigeot * Disables Writeback and frees the Writeback memory (all asics). 404926deccbSFrançois Tigeot * Used at driver shutdown. 405926deccbSFrançois Tigeot */ 406926deccbSFrançois Tigeot void radeon_wb_fini(struct radeon_device *rdev) 407926deccbSFrançois Tigeot { 408926deccbSFrançois Tigeot radeon_wb_disable(rdev); 409926deccbSFrançois Tigeot if (rdev->wb.wb_obj) { 410f43cf1b1SMichael Neumann if (!radeon_bo_reserve(rdev->wb.wb_obj, false)) { 411f43cf1b1SMichael Neumann radeon_bo_kunmap(rdev->wb.wb_obj); 412f43cf1b1SMichael Neumann radeon_bo_unpin(rdev->wb.wb_obj); 413f43cf1b1SMichael Neumann radeon_bo_unreserve(rdev->wb.wb_obj); 414f43cf1b1SMichael Neumann } 415926deccbSFrançois Tigeot radeon_bo_unref(&rdev->wb.wb_obj); 416926deccbSFrançois Tigeot rdev->wb.wb = NULL; 417926deccbSFrançois Tigeot rdev->wb.wb_obj = NULL; 418926deccbSFrançois Tigeot } 419926deccbSFrançois Tigeot } 420926deccbSFrançois Tigeot 421926deccbSFrançois Tigeot /** 422926deccbSFrançois Tigeot * radeon_wb_init- Init Writeback driver info and allocate memory 423926deccbSFrançois Tigeot * 424926deccbSFrançois Tigeot * @rdev: radeon_device pointer 425926deccbSFrançois Tigeot * 426926deccbSFrançois Tigeot * Disables Writeback and frees the Writeback memory (all asics). 427926deccbSFrançois Tigeot * Used at driver startup. 428926deccbSFrançois Tigeot * Returns 0 on success or an -error on failure. 429926deccbSFrançois Tigeot */ 430926deccbSFrançois Tigeot int radeon_wb_init(struct radeon_device *rdev) 431926deccbSFrançois Tigeot { 432926deccbSFrançois Tigeot int r; 433926deccbSFrançois Tigeot void *wb_ptr; 434926deccbSFrançois Tigeot 435926deccbSFrançois Tigeot if (rdev->wb.wb_obj == NULL) { 436926deccbSFrançois Tigeot r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, 437c6f73aabSFrançois Tigeot RADEON_GEM_DOMAIN_GTT, 0, NULL, 438c6f73aabSFrançois Tigeot &rdev->wb.wb_obj); 439926deccbSFrançois Tigeot if (r) { 440926deccbSFrançois Tigeot dev_warn(rdev->dev, "(%d) create WB bo failed\n", r); 441926deccbSFrançois Tigeot return r; 442926deccbSFrançois Tigeot } 443926deccbSFrançois Tigeot r = radeon_bo_reserve(rdev->wb.wb_obj, false); 444926deccbSFrançois Tigeot if (unlikely(r != 0)) { 445926deccbSFrançois Tigeot radeon_wb_fini(rdev); 446926deccbSFrançois Tigeot return r; 447926deccbSFrançois Tigeot } 448926deccbSFrançois Tigeot r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT, 449f77dbd6cSFrançois Tigeot (u64 *)&rdev->wb.gpu_addr); 450926deccbSFrançois Tigeot if (r) { 451926deccbSFrançois Tigeot radeon_bo_unreserve(rdev->wb.wb_obj); 452926deccbSFrançois Tigeot dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r); 453926deccbSFrançois Tigeot radeon_wb_fini(rdev); 454926deccbSFrançois Tigeot return r; 455926deccbSFrançois Tigeot } 456926deccbSFrançois Tigeot wb_ptr = &rdev->wb.wb; 457926deccbSFrançois Tigeot r = radeon_bo_kmap(rdev->wb.wb_obj, wb_ptr); 458926deccbSFrançois Tigeot radeon_bo_unreserve(rdev->wb.wb_obj); 459926deccbSFrançois Tigeot if (r) { 460926deccbSFrançois Tigeot dev_warn(rdev->dev, "(%d) map WB bo failed\n", r); 461926deccbSFrançois Tigeot radeon_wb_fini(rdev); 462926deccbSFrançois Tigeot return r; 463926deccbSFrançois Tigeot } 464ee479021SImre Vadász /* clear wb memory */ 465ee479021SImre Vadász memset(*(void **)wb_ptr, 0, RADEON_GPU_PAGE_SIZE); 466f43cf1b1SMichael Neumann } 467f43cf1b1SMichael Neumann 468926deccbSFrançois Tigeot /* disable event_write fences */ 469926deccbSFrançois Tigeot rdev->wb.use_event = false; 470926deccbSFrançois Tigeot /* disabled via module param */ 471926deccbSFrançois Tigeot if (radeon_no_wb == 1) { 472926deccbSFrançois Tigeot rdev->wb.enabled = false; 473926deccbSFrançois Tigeot } else { 474926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP) { 475926deccbSFrançois Tigeot /* often unreliable on AGP */ 476926deccbSFrançois Tigeot rdev->wb.enabled = false; 477926deccbSFrançois Tigeot } else if (rdev->family < CHIP_R300) { 478926deccbSFrançois Tigeot /* often unreliable on pre-r300 */ 479926deccbSFrançois Tigeot rdev->wb.enabled = false; 480926deccbSFrançois Tigeot } else { 481926deccbSFrançois Tigeot rdev->wb.enabled = true; 482926deccbSFrançois Tigeot /* event_write fences are only available on r600+ */ 483926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600) { 484926deccbSFrançois Tigeot rdev->wb.use_event = true; 485926deccbSFrançois Tigeot } 486926deccbSFrançois Tigeot } 487926deccbSFrançois Tigeot } 488926deccbSFrançois Tigeot /* always use writeback/events on NI, APUs */ 489926deccbSFrançois Tigeot if (rdev->family >= CHIP_PALM) { 490926deccbSFrançois Tigeot rdev->wb.enabled = true; 491926deccbSFrançois Tigeot rdev->wb.use_event = true; 492926deccbSFrançois Tigeot } 493926deccbSFrançois Tigeot 494926deccbSFrançois Tigeot dev_info(rdev->dev, "WB %sabled\n", rdev->wb.enabled ? "en" : "dis"); 495926deccbSFrançois Tigeot 496926deccbSFrançois Tigeot return 0; 497926deccbSFrançois Tigeot } 498926deccbSFrançois Tigeot 499926deccbSFrançois Tigeot /** 500926deccbSFrançois Tigeot * radeon_vram_location - try to find VRAM location 501926deccbSFrançois Tigeot * @rdev: radeon device structure holding all necessary informations 502926deccbSFrançois Tigeot * @mc: memory controller structure holding memory informations 503926deccbSFrançois Tigeot * @base: base address at which to put VRAM 504926deccbSFrançois Tigeot * 505926deccbSFrançois Tigeot * Function will place try to place VRAM at base address provided 506926deccbSFrançois Tigeot * as parameter (which is so far either PCI aperture address or 507926deccbSFrançois Tigeot * for IGP TOM base address). 508926deccbSFrançois Tigeot * 509926deccbSFrançois Tigeot * If there is not enough space to fit the unvisible VRAM in the 32bits 510926deccbSFrançois Tigeot * address space then we limit the VRAM size to the aperture. 511926deccbSFrançois Tigeot * 512926deccbSFrançois Tigeot * If we are using AGP and if the AGP aperture doesn't allow us to have 513926deccbSFrançois Tigeot * room for all the VRAM than we restrict the VRAM to the PCI aperture 514926deccbSFrançois Tigeot * size and print a warning. 515926deccbSFrançois Tigeot * 516926deccbSFrançois Tigeot * This function will never fails, worst case are limiting VRAM. 517926deccbSFrançois Tigeot * 518926deccbSFrançois Tigeot * Note: GTT start, end, size should be initialized before calling this 519926deccbSFrançois Tigeot * function on AGP platform. 520926deccbSFrançois Tigeot * 521926deccbSFrançois Tigeot * Note: We don't explicitly enforce VRAM start to be aligned on VRAM size, 522926deccbSFrançois Tigeot * this shouldn't be a problem as we are using the PCI aperture as a reference. 523926deccbSFrançois Tigeot * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but 524926deccbSFrançois Tigeot * not IGP. 525926deccbSFrançois Tigeot * 526926deccbSFrançois Tigeot * Note: we use mc_vram_size as on some board we need to program the mc to 527926deccbSFrançois Tigeot * cover the whole aperture even if VRAM size is inferior to aperture size 528926deccbSFrançois Tigeot * Novell bug 204882 + along with lots of ubuntu ones 529926deccbSFrançois Tigeot * 530926deccbSFrançois Tigeot * Note: when limiting vram it's safe to overwritte real_vram_size because 531926deccbSFrançois Tigeot * we are not in case where real_vram_size is inferior to mc_vram_size (ie 532926deccbSFrançois Tigeot * note afected by bogus hw of Novell bug 204882 + along with lots of ubuntu 533926deccbSFrançois Tigeot * ones) 534926deccbSFrançois Tigeot * 535926deccbSFrançois Tigeot * Note: IGP TOM addr should be the same as the aperture addr, we don't 536926deccbSFrançois Tigeot * explicitly check for that thought. 537926deccbSFrançois Tigeot * 538926deccbSFrançois Tigeot * FIXME: when reducing VRAM size align new size on power of 2. 539926deccbSFrançois Tigeot */ 540926deccbSFrançois Tigeot void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base) 541926deccbSFrançois Tigeot { 542926deccbSFrançois Tigeot uint64_t limit = (uint64_t)radeon_vram_limit << 20; 543926deccbSFrançois Tigeot 544926deccbSFrançois Tigeot mc->vram_start = base; 545f43cf1b1SMichael Neumann if (mc->mc_vram_size > (rdev->mc.mc_mask - base + 1)) { 546926deccbSFrançois Tigeot dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); 547926deccbSFrançois Tigeot mc->real_vram_size = mc->aper_size; 548926deccbSFrançois Tigeot mc->mc_vram_size = mc->aper_size; 549926deccbSFrançois Tigeot } 550926deccbSFrançois Tigeot mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; 551926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_start <= mc->gtt_end) { 552926deccbSFrançois Tigeot dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); 553926deccbSFrançois Tigeot mc->real_vram_size = mc->aper_size; 554926deccbSFrançois Tigeot mc->mc_vram_size = mc->aper_size; 555926deccbSFrançois Tigeot } 556926deccbSFrançois Tigeot mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; 557926deccbSFrançois Tigeot if (limit && limit < mc->real_vram_size) 558926deccbSFrançois Tigeot mc->real_vram_size = limit; 559f77dbd6cSFrançois Tigeot dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n", 5604cd92098Szrj mc->mc_vram_size >> 20, mc->vram_start, 5614cd92098Szrj mc->vram_end, mc->real_vram_size >> 20); 562926deccbSFrançois Tigeot } 563926deccbSFrançois Tigeot 564926deccbSFrançois Tigeot /** 565926deccbSFrançois Tigeot * radeon_gtt_location - try to find GTT location 566926deccbSFrançois Tigeot * @rdev: radeon device structure holding all necessary informations 567926deccbSFrançois Tigeot * @mc: memory controller structure holding memory informations 568926deccbSFrançois Tigeot * 569926deccbSFrançois Tigeot * Function will place try to place GTT before or after VRAM. 570926deccbSFrançois Tigeot * 571926deccbSFrançois Tigeot * If GTT size is bigger than space left then we ajust GTT size. 572926deccbSFrançois Tigeot * Thus function will never fails. 573926deccbSFrançois Tigeot * 574926deccbSFrançois Tigeot * FIXME: when reducing GTT size align new size on power of 2. 575926deccbSFrançois Tigeot */ 576926deccbSFrançois Tigeot void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) 577926deccbSFrançois Tigeot { 578926deccbSFrançois Tigeot u64 size_af, size_bf; 579926deccbSFrançois Tigeot 580f43cf1b1SMichael Neumann size_af = ((rdev->mc.mc_mask - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align; 581926deccbSFrançois Tigeot size_bf = mc->vram_start & ~mc->gtt_base_align; 582926deccbSFrançois Tigeot if (size_bf > size_af) { 583926deccbSFrançois Tigeot if (mc->gtt_size > size_bf) { 584926deccbSFrançois Tigeot dev_warn(rdev->dev, "limiting GTT\n"); 585926deccbSFrançois Tigeot mc->gtt_size = size_bf; 586926deccbSFrançois Tigeot } 587926deccbSFrançois Tigeot mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size; 588926deccbSFrançois Tigeot } else { 589926deccbSFrançois Tigeot if (mc->gtt_size > size_af) { 590926deccbSFrançois Tigeot dev_warn(rdev->dev, "limiting GTT\n"); 591926deccbSFrançois Tigeot mc->gtt_size = size_af; 592926deccbSFrançois Tigeot } 593926deccbSFrançois Tigeot mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align; 594926deccbSFrançois Tigeot } 595926deccbSFrançois Tigeot mc->gtt_end = mc->gtt_start + mc->gtt_size - 1; 596f77dbd6cSFrançois Tigeot dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n", 5974cd92098Szrj mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end); 598926deccbSFrançois Tigeot } 599926deccbSFrançois Tigeot 600926deccbSFrançois Tigeot /* 601926deccbSFrançois Tigeot * GPU helpers function. 602926deccbSFrançois Tigeot */ 603926deccbSFrançois Tigeot /** 604926deccbSFrançois Tigeot * radeon_card_posted - check if the hw has already been initialized 605926deccbSFrançois Tigeot * 606926deccbSFrançois Tigeot * @rdev: radeon_device pointer 607926deccbSFrançois Tigeot * 608926deccbSFrançois Tigeot * Check if the asic has been initialized (all asics). 609926deccbSFrançois Tigeot * Used at driver startup. 610926deccbSFrançois Tigeot * Returns true if initialized or false if not. 611926deccbSFrançois Tigeot */ 612926deccbSFrançois Tigeot bool radeon_card_posted(struct radeon_device *rdev) 613926deccbSFrançois Tigeot { 614926deccbSFrançois Tigeot uint32_t reg; 615926deccbSFrançois Tigeot 616926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 617f43cf1b1SMichael Neumann /* required for EFI mode on macbook2,1 which uses an r5xx asic */ 618926deccbSFrançois Tigeot if (efi_enabled(EFI_BOOT) && 619c6f73aabSFrançois Tigeot (rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) && 620f43cf1b1SMichael Neumann (rdev->family < CHIP_R600)) 621926deccbSFrançois Tigeot return false; 622926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 623926deccbSFrançois Tigeot 624f43cf1b1SMichael Neumann if (ASIC_IS_NODCE(rdev)) 625f43cf1b1SMichael Neumann goto check_memsize; 626f43cf1b1SMichael Neumann 627926deccbSFrançois Tigeot /* first check CRTCs */ 628f43cf1b1SMichael Neumann if (ASIC_IS_DCE4(rdev)) { 629926deccbSFrançois Tigeot reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | 630926deccbSFrançois Tigeot RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); 631f43cf1b1SMichael Neumann if (rdev->num_crtc >= 4) { 632f43cf1b1SMichael Neumann reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | 633f43cf1b1SMichael Neumann RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); 634f43cf1b1SMichael Neumann } 635f43cf1b1SMichael Neumann if (rdev->num_crtc >= 6) { 636f43cf1b1SMichael Neumann reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | 637926deccbSFrançois Tigeot RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); 638f43cf1b1SMichael Neumann } 639926deccbSFrançois Tigeot if (reg & EVERGREEN_CRTC_MASTER_EN) 640926deccbSFrançois Tigeot return true; 641926deccbSFrançois Tigeot } else if (ASIC_IS_AVIVO(rdev)) { 642926deccbSFrançois Tigeot reg = RREG32(AVIVO_D1CRTC_CONTROL) | 643926deccbSFrançois Tigeot RREG32(AVIVO_D2CRTC_CONTROL); 644926deccbSFrançois Tigeot if (reg & AVIVO_CRTC_EN) { 645926deccbSFrançois Tigeot return true; 646926deccbSFrançois Tigeot } 647926deccbSFrançois Tigeot } else { 648926deccbSFrançois Tigeot reg = RREG32(RADEON_CRTC_GEN_CNTL) | 649926deccbSFrançois Tigeot RREG32(RADEON_CRTC2_GEN_CNTL); 650926deccbSFrançois Tigeot if (reg & RADEON_CRTC_EN) { 651926deccbSFrançois Tigeot return true; 652926deccbSFrançois Tigeot } 653926deccbSFrançois Tigeot } 654926deccbSFrançois Tigeot 655f43cf1b1SMichael Neumann check_memsize: 656926deccbSFrançois Tigeot /* then check MEM_SIZE, in case the crtcs are off */ 657926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600) 658926deccbSFrançois Tigeot reg = RREG32(R600_CONFIG_MEMSIZE); 659926deccbSFrançois Tigeot else 660926deccbSFrançois Tigeot reg = RREG32(RADEON_CONFIG_MEMSIZE); 661926deccbSFrançois Tigeot 662926deccbSFrançois Tigeot if (reg) 663926deccbSFrançois Tigeot return true; 664926deccbSFrançois Tigeot 665926deccbSFrançois Tigeot return false; 666926deccbSFrançois Tigeot 667926deccbSFrançois Tigeot } 668926deccbSFrançois Tigeot 669926deccbSFrançois Tigeot /** 670926deccbSFrançois Tigeot * radeon_update_bandwidth_info - update display bandwidth params 671926deccbSFrançois Tigeot * 672926deccbSFrançois Tigeot * @rdev: radeon_device pointer 673926deccbSFrançois Tigeot * 674926deccbSFrançois Tigeot * Used when sclk/mclk are switched or display modes are set. 675926deccbSFrançois Tigeot * params are used to calculate display watermarks (all asics) 676926deccbSFrançois Tigeot */ 677926deccbSFrançois Tigeot void radeon_update_bandwidth_info(struct radeon_device *rdev) 678926deccbSFrançois Tigeot { 679926deccbSFrançois Tigeot fixed20_12 a; 680926deccbSFrançois Tigeot u32 sclk = rdev->pm.current_sclk; 681926deccbSFrançois Tigeot u32 mclk = rdev->pm.current_mclk; 682926deccbSFrançois Tigeot 683926deccbSFrançois Tigeot /* sclk/mclk in Mhz */ 684926deccbSFrançois Tigeot a.full = dfixed_const(100); 685926deccbSFrançois Tigeot rdev->pm.sclk.full = dfixed_const(sclk); 686926deccbSFrançois Tigeot rdev->pm.sclk.full = dfixed_div(rdev->pm.sclk, a); 687926deccbSFrançois Tigeot rdev->pm.mclk.full = dfixed_const(mclk); 688926deccbSFrançois Tigeot rdev->pm.mclk.full = dfixed_div(rdev->pm.mclk, a); 689926deccbSFrançois Tigeot 690926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_IGP) { 691926deccbSFrançois Tigeot a.full = dfixed_const(16); 692926deccbSFrançois Tigeot /* core_bandwidth = sclk(Mhz) * 16 */ 693926deccbSFrançois Tigeot rdev->pm.core_bandwidth.full = dfixed_div(rdev->pm.sclk, a); 694926deccbSFrançois Tigeot } 695926deccbSFrançois Tigeot } 696926deccbSFrançois Tigeot 697926deccbSFrançois Tigeot /** 698926deccbSFrançois Tigeot * radeon_boot_test_post_card - check and possibly initialize the hw 699926deccbSFrançois Tigeot * 700926deccbSFrançois Tigeot * @rdev: radeon_device pointer 701926deccbSFrançois Tigeot * 702926deccbSFrançois Tigeot * Check if the asic is initialized and if not, attempt to initialize 703926deccbSFrançois Tigeot * it (all asics). 704926deccbSFrançois Tigeot * Returns true if initialized or false if not. 705926deccbSFrançois Tigeot */ 706926deccbSFrançois Tigeot bool radeon_boot_test_post_card(struct radeon_device *rdev) 707926deccbSFrançois Tigeot { 708926deccbSFrançois Tigeot if (radeon_card_posted(rdev)) 709926deccbSFrançois Tigeot return true; 710926deccbSFrançois Tigeot 711926deccbSFrançois Tigeot if (rdev->bios) { 712926deccbSFrançois Tigeot DRM_INFO("GPU not posted. posting now...\n"); 713926deccbSFrançois Tigeot if (rdev->is_atom_bios) 714926deccbSFrançois Tigeot atom_asic_init(rdev->mode_info.atom_context); 715926deccbSFrançois Tigeot else 716926deccbSFrançois Tigeot radeon_combios_asic_init(rdev->ddev); 717926deccbSFrançois Tigeot return true; 718926deccbSFrançois Tigeot } else { 719926deccbSFrançois Tigeot dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n"); 720926deccbSFrançois Tigeot return false; 721926deccbSFrançois Tigeot } 722926deccbSFrançois Tigeot } 723926deccbSFrançois Tigeot 724926deccbSFrançois Tigeot /** 725926deccbSFrançois Tigeot * radeon_dummy_page_init - init dummy page used by the driver 726926deccbSFrançois Tigeot * 727926deccbSFrançois Tigeot * @rdev: radeon_device pointer 728926deccbSFrançois Tigeot * 729926deccbSFrançois Tigeot * Allocate the dummy page used by the driver (all asics). 730926deccbSFrançois Tigeot * This dummy page is used by the driver as a filler for gart entries 731926deccbSFrançois Tigeot * when pages are taken out of the GART 732926deccbSFrançois Tigeot * Returns 0 on sucess, -ENOMEM on failure. 733926deccbSFrançois Tigeot */ 734926deccbSFrançois Tigeot int radeon_dummy_page_init(struct radeon_device *rdev) 735926deccbSFrançois Tigeot { 736926deccbSFrançois Tigeot if (rdev->dummy_page.dmah) 737926deccbSFrançois Tigeot return 0; 738926deccbSFrançois Tigeot rdev->dummy_page.dmah = drm_pci_alloc(rdev->ddev, 739b31e9d59SFrançois Tigeot PAGE_SIZE, PAGE_SIZE); 740926deccbSFrançois Tigeot if (rdev->dummy_page.dmah == NULL) 741926deccbSFrançois Tigeot return -ENOMEM; 74217afe8a4SSascha Wildner rdev->dummy_page.addr = 743dea697ccSImre Vadasz (dma_addr_t)rdev->dummy_page.dmah->busaddr; 744926deccbSFrançois Tigeot return 0; 745926deccbSFrançois Tigeot } 746926deccbSFrançois Tigeot 747926deccbSFrançois Tigeot /** 748926deccbSFrançois Tigeot * radeon_dummy_page_fini - free dummy page used by the driver 749926deccbSFrançois Tigeot * 750926deccbSFrançois Tigeot * @rdev: radeon_device pointer 751926deccbSFrançois Tigeot * 752926deccbSFrançois Tigeot * Frees the dummy page used by the driver (all asics). 753926deccbSFrançois Tigeot */ 754926deccbSFrançois Tigeot void radeon_dummy_page_fini(struct radeon_device *rdev) 755926deccbSFrançois Tigeot { 756926deccbSFrançois Tigeot if (rdev->dummy_page.dmah == NULL) 757926deccbSFrançois Tigeot return; 758926deccbSFrançois Tigeot drm_pci_free(rdev->ddev, rdev->dummy_page.dmah); 759926deccbSFrançois Tigeot rdev->dummy_page.dmah = NULL; 760926deccbSFrançois Tigeot rdev->dummy_page.addr = 0; 761926deccbSFrançois Tigeot } 762926deccbSFrançois Tigeot 763926deccbSFrançois Tigeot 764926deccbSFrançois Tigeot /* ATOM accessor methods */ 765926deccbSFrançois Tigeot /* 766926deccbSFrançois Tigeot * ATOM is an interpreted byte code stored in tables in the vbios. The 767926deccbSFrançois Tigeot * driver registers callbacks to access registers and the interpreter 768926deccbSFrançois Tigeot * in the driver parses the tables and executes then to program specific 769926deccbSFrançois Tigeot * actions (set display modes, asic init, etc.). See radeon_atombios.c, 770926deccbSFrançois Tigeot * atombios.h, and atom.c 771926deccbSFrançois Tigeot */ 772926deccbSFrançois Tigeot 773926deccbSFrançois Tigeot /** 774926deccbSFrançois Tigeot * cail_pll_read - read PLL register 775926deccbSFrançois Tigeot * 776926deccbSFrançois Tigeot * @info: atom card_info pointer 777926deccbSFrançois Tigeot * @reg: PLL register offset 778926deccbSFrançois Tigeot * 779926deccbSFrançois Tigeot * Provides a PLL register accessor for the atom interpreter (r4xx+). 780926deccbSFrançois Tigeot * Returns the value of the PLL register. 781926deccbSFrançois Tigeot */ 782926deccbSFrançois Tigeot static uint32_t cail_pll_read(struct card_info *info, uint32_t reg) 783926deccbSFrançois Tigeot { 784926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private; 785926deccbSFrançois Tigeot uint32_t r; 786926deccbSFrançois Tigeot 787926deccbSFrançois Tigeot r = rdev->pll_rreg(rdev, reg); 788926deccbSFrançois Tigeot return r; 789926deccbSFrançois Tigeot } 790926deccbSFrançois Tigeot 791926deccbSFrançois Tigeot /** 792926deccbSFrançois Tigeot * cail_pll_write - write PLL register 793926deccbSFrançois Tigeot * 794926deccbSFrançois Tigeot * @info: atom card_info pointer 795926deccbSFrançois Tigeot * @reg: PLL register offset 796926deccbSFrançois Tigeot * @val: value to write to the pll register 797926deccbSFrançois Tigeot * 798926deccbSFrançois Tigeot * Provides a PLL register accessor for the atom interpreter (r4xx+). 799926deccbSFrançois Tigeot */ 800926deccbSFrançois Tigeot static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val) 801926deccbSFrançois Tigeot { 802926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private; 803926deccbSFrançois Tigeot 804926deccbSFrançois Tigeot rdev->pll_wreg(rdev, reg, val); 805926deccbSFrançois Tigeot } 806926deccbSFrançois Tigeot 807926deccbSFrançois Tigeot /** 808926deccbSFrançois Tigeot * cail_mc_read - read MC (Memory Controller) register 809926deccbSFrançois Tigeot * 810926deccbSFrançois Tigeot * @info: atom card_info pointer 811926deccbSFrançois Tigeot * @reg: MC register offset 812926deccbSFrançois Tigeot * 813926deccbSFrançois Tigeot * Provides an MC register accessor for the atom interpreter (r4xx+). 814926deccbSFrançois Tigeot * Returns the value of the MC register. 815926deccbSFrançois Tigeot */ 816926deccbSFrançois Tigeot static uint32_t cail_mc_read(struct card_info *info, uint32_t reg) 817926deccbSFrançois Tigeot { 818926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private; 819926deccbSFrançois Tigeot uint32_t r; 820926deccbSFrançois Tigeot 821926deccbSFrançois Tigeot r = rdev->mc_rreg(rdev, reg); 822926deccbSFrançois Tigeot return r; 823926deccbSFrançois Tigeot } 824926deccbSFrançois Tigeot 825926deccbSFrançois Tigeot /** 826926deccbSFrançois Tigeot * cail_mc_write - write MC (Memory Controller) register 827926deccbSFrançois Tigeot * 828926deccbSFrançois Tigeot * @info: atom card_info pointer 829926deccbSFrançois Tigeot * @reg: MC register offset 830926deccbSFrançois Tigeot * @val: value to write to the pll register 831926deccbSFrançois Tigeot * 832926deccbSFrançois Tigeot * Provides a MC register accessor for the atom interpreter (r4xx+). 833926deccbSFrançois Tigeot */ 834926deccbSFrançois Tigeot static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val) 835926deccbSFrançois Tigeot { 836926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private; 837926deccbSFrançois Tigeot 838926deccbSFrançois Tigeot rdev->mc_wreg(rdev, reg, val); 839926deccbSFrançois Tigeot } 840926deccbSFrançois Tigeot 841926deccbSFrançois Tigeot /** 842926deccbSFrançois Tigeot * cail_reg_write - write MMIO register 843926deccbSFrançois Tigeot * 844926deccbSFrançois Tigeot * @info: atom card_info pointer 845926deccbSFrançois Tigeot * @reg: MMIO register offset 846926deccbSFrançois Tigeot * @val: value to write to the pll register 847926deccbSFrançois Tigeot * 848926deccbSFrançois Tigeot * Provides a MMIO register accessor for the atom interpreter (r4xx+). 849926deccbSFrançois Tigeot */ 850926deccbSFrançois Tigeot static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val) 851926deccbSFrançois Tigeot { 852926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private; 853926deccbSFrançois Tigeot 854926deccbSFrançois Tigeot WREG32(reg*4, val); 855926deccbSFrançois Tigeot } 856926deccbSFrançois Tigeot 857926deccbSFrançois Tigeot /** 858926deccbSFrançois Tigeot * cail_reg_read - read MMIO register 859926deccbSFrançois Tigeot * 860926deccbSFrançois Tigeot * @info: atom card_info pointer 861926deccbSFrançois Tigeot * @reg: MMIO register offset 862926deccbSFrançois Tigeot * 863926deccbSFrançois Tigeot * Provides an MMIO register accessor for the atom interpreter (r4xx+). 864926deccbSFrançois Tigeot * Returns the value of the MMIO register. 865926deccbSFrançois Tigeot */ 866926deccbSFrançois Tigeot static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) 867926deccbSFrançois Tigeot { 868926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private; 869926deccbSFrançois Tigeot uint32_t r; 870926deccbSFrançois Tigeot 871926deccbSFrançois Tigeot r = RREG32(reg*4); 872926deccbSFrançois Tigeot return r; 873926deccbSFrançois Tigeot } 874926deccbSFrançois Tigeot 875926deccbSFrançois Tigeot /** 876926deccbSFrançois Tigeot * cail_ioreg_write - write IO register 877926deccbSFrançois Tigeot * 878926deccbSFrançois Tigeot * @info: atom card_info pointer 879926deccbSFrançois Tigeot * @reg: IO register offset 880926deccbSFrançois Tigeot * @val: value to write to the pll register 881926deccbSFrançois Tigeot * 882926deccbSFrançois Tigeot * Provides a IO register accessor for the atom interpreter (r4xx+). 883926deccbSFrançois Tigeot */ 884926deccbSFrançois Tigeot static void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val) 885926deccbSFrançois Tigeot { 886926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private; 887926deccbSFrançois Tigeot 888926deccbSFrançois Tigeot WREG32_IO(reg*4, val); 889926deccbSFrançois Tigeot } 890926deccbSFrançois Tigeot 891926deccbSFrançois Tigeot /** 892926deccbSFrançois Tigeot * cail_ioreg_read - read IO register 893926deccbSFrançois Tigeot * 894926deccbSFrançois Tigeot * @info: atom card_info pointer 895926deccbSFrançois Tigeot * @reg: IO register offset 896926deccbSFrançois Tigeot * 897926deccbSFrançois Tigeot * Provides an IO register accessor for the atom interpreter (r4xx+). 898926deccbSFrançois Tigeot * Returns the value of the IO register. 899926deccbSFrançois Tigeot */ 900926deccbSFrançois Tigeot static uint32_t cail_ioreg_read(struct card_info *info, uint32_t reg) 901926deccbSFrançois Tigeot { 902926deccbSFrançois Tigeot struct radeon_device *rdev = info->dev->dev_private; 903926deccbSFrançois Tigeot uint32_t r; 904926deccbSFrançois Tigeot 905926deccbSFrançois Tigeot r = RREG32_IO(reg*4); 906926deccbSFrançois Tigeot return r; 907926deccbSFrançois Tigeot } 908926deccbSFrançois Tigeot 909926deccbSFrançois Tigeot /** 910926deccbSFrançois Tigeot * radeon_atombios_init - init the driver info and callbacks for atombios 911926deccbSFrançois Tigeot * 912926deccbSFrançois Tigeot * @rdev: radeon_device pointer 913926deccbSFrançois Tigeot * 914926deccbSFrançois Tigeot * Initializes the driver info and register access callbacks for the 915926deccbSFrançois Tigeot * ATOM interpreter (r4xx+). 916926deccbSFrançois Tigeot * Returns 0 on sucess, -ENOMEM on failure. 917926deccbSFrançois Tigeot * Called at driver startup. 918926deccbSFrançois Tigeot */ 919926deccbSFrançois Tigeot int radeon_atombios_init(struct radeon_device *rdev) 920926deccbSFrançois Tigeot { 921926deccbSFrançois Tigeot struct card_info *atom_card_info = 922c4ef309bSzrj kzalloc(sizeof(struct card_info), GFP_KERNEL); 923926deccbSFrançois Tigeot 924926deccbSFrançois Tigeot if (!atom_card_info) 925926deccbSFrançois Tigeot return -ENOMEM; 926926deccbSFrançois Tigeot 927926deccbSFrançois Tigeot rdev->mode_info.atom_card_info = atom_card_info; 928926deccbSFrançois Tigeot atom_card_info->dev = rdev->ddev; 929926deccbSFrançois Tigeot atom_card_info->reg_read = cail_reg_read; 930926deccbSFrançois Tigeot atom_card_info->reg_write = cail_reg_write; 931926deccbSFrançois Tigeot /* needed for iio ops */ 932926deccbSFrançois Tigeot if (rdev->rio_mem) { 933926deccbSFrançois Tigeot atom_card_info->ioreg_read = cail_ioreg_read; 934926deccbSFrançois Tigeot atom_card_info->ioreg_write = cail_ioreg_write; 935926deccbSFrançois Tigeot } else { 936926deccbSFrançois Tigeot DRM_ERROR("Unable to find PCI I/O BAR; using MMIO for ATOM IIO\n"); 937926deccbSFrançois Tigeot atom_card_info->ioreg_read = cail_reg_read; 938926deccbSFrançois Tigeot atom_card_info->ioreg_write = cail_reg_write; 939926deccbSFrançois Tigeot } 940926deccbSFrançois Tigeot atom_card_info->mc_read = cail_mc_read; 941926deccbSFrançois Tigeot atom_card_info->mc_write = cail_mc_write; 942926deccbSFrançois Tigeot atom_card_info->pll_read = cail_pll_read; 943926deccbSFrançois Tigeot atom_card_info->pll_write = cail_pll_write; 944926deccbSFrançois Tigeot 945926deccbSFrançois Tigeot rdev->mode_info.atom_context = atom_parse(atom_card_info, rdev->bios); 946b403bed8SMichael Neumann if (!rdev->mode_info.atom_context) { 947b403bed8SMichael Neumann radeon_atombios_fini(rdev); 948b403bed8SMichael Neumann return -ENOMEM; 949b403bed8SMichael Neumann } 950b403bed8SMichael Neumann 951591d5043SFrançois Tigeot lockinit(&rdev->mode_info.atom_context->mutex, "rmiacmtx", 0, LK_CANRECURSE); 952591d5043SFrançois Tigeot lockinit(&rdev->mode_info.atom_context->scratch_mutex, "rmiacsmtx", 0, LK_CANRECURSE); 953926deccbSFrançois Tigeot radeon_atom_initialize_bios_scratch_regs(rdev->ddev); 954926deccbSFrançois Tigeot atom_allocate_fb_scratch(rdev->mode_info.atom_context); 955926deccbSFrançois Tigeot return 0; 956926deccbSFrançois Tigeot } 957926deccbSFrançois Tigeot 958926deccbSFrançois Tigeot /** 959926deccbSFrançois Tigeot * radeon_atombios_fini - free the driver info and callbacks for atombios 960926deccbSFrançois Tigeot * 961926deccbSFrançois Tigeot * @rdev: radeon_device pointer 962926deccbSFrançois Tigeot * 963926deccbSFrançois Tigeot * Frees the driver info and register access callbacks for the ATOM 964926deccbSFrançois Tigeot * interpreter (r4xx+). 965926deccbSFrançois Tigeot * Called at driver shutdown. 966926deccbSFrançois Tigeot */ 967926deccbSFrançois Tigeot void radeon_atombios_fini(struct radeon_device *rdev) 968926deccbSFrançois Tigeot { 969926deccbSFrançois Tigeot if (rdev->mode_info.atom_context) { 970ee479021SImre Vadász /* prevents leaking 512 bytes */ 971ee479021SImre Vadász kfree(rdev->mode_info.atom_context->iio); 972ee479021SImre Vadász 973c4ef309bSzrj kfree(rdev->mode_info.atom_context->scratch); 974926deccbSFrançois Tigeot } 975c4ef309bSzrj kfree(rdev->mode_info.atom_context); 976b403bed8SMichael Neumann rdev->mode_info.atom_context = NULL; 977c4ef309bSzrj kfree(rdev->mode_info.atom_card_info); 978b403bed8SMichael Neumann rdev->mode_info.atom_card_info = NULL; 979926deccbSFrançois Tigeot } 980926deccbSFrançois Tigeot 981926deccbSFrançois Tigeot /* COMBIOS */ 982926deccbSFrançois Tigeot /* 983926deccbSFrançois Tigeot * COMBIOS is the bios format prior to ATOM. It provides 984926deccbSFrançois Tigeot * command tables similar to ATOM, but doesn't have a unified 985926deccbSFrançois Tigeot * parser. See radeon_combios.c 986926deccbSFrançois Tigeot */ 987926deccbSFrançois Tigeot 988926deccbSFrançois Tigeot /** 989926deccbSFrançois Tigeot * radeon_combios_init - init the driver info for combios 990926deccbSFrançois Tigeot * 991926deccbSFrançois Tigeot * @rdev: radeon_device pointer 992926deccbSFrançois Tigeot * 993926deccbSFrançois Tigeot * Initializes the driver info for combios (r1xx-r3xx). 994926deccbSFrançois Tigeot * Returns 0 on sucess. 995926deccbSFrançois Tigeot * Called at driver startup. 996926deccbSFrançois Tigeot */ 997926deccbSFrançois Tigeot int radeon_combios_init(struct radeon_device *rdev) 998926deccbSFrançois Tigeot { 999926deccbSFrançois Tigeot radeon_combios_initialize_bios_scratch_regs(rdev->ddev); 1000926deccbSFrançois Tigeot return 0; 1001926deccbSFrançois Tigeot } 1002926deccbSFrançois Tigeot 1003926deccbSFrançois Tigeot /** 1004926deccbSFrançois Tigeot * radeon_combios_fini - free the driver info for combios 1005926deccbSFrançois Tigeot * 1006926deccbSFrançois Tigeot * @rdev: radeon_device pointer 1007926deccbSFrançois Tigeot * 1008926deccbSFrançois Tigeot * Frees the driver info for combios (r1xx-r3xx). 1009926deccbSFrançois Tigeot * Called at driver shutdown. 1010926deccbSFrançois Tigeot */ 1011926deccbSFrançois Tigeot void radeon_combios_fini(struct radeon_device *rdev) 1012926deccbSFrançois Tigeot { 1013926deccbSFrançois Tigeot } 1014926deccbSFrançois Tigeot 1015926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1016926deccbSFrançois Tigeot /* if we get transitioned to only one device, take VGA back */ 1017926deccbSFrançois Tigeot /** 1018926deccbSFrançois Tigeot * radeon_vga_set_decode - enable/disable vga decode 1019926deccbSFrançois Tigeot * 1020926deccbSFrançois Tigeot * @cookie: radeon_device pointer 1021926deccbSFrançois Tigeot * @state: enable/disable vga decode 1022926deccbSFrançois Tigeot * 1023926deccbSFrançois Tigeot * Enable/disable vga decode (all asics). 1024926deccbSFrançois Tigeot * Returns VGA resource flags. 1025926deccbSFrançois Tigeot */ 1026926deccbSFrançois Tigeot static unsigned int radeon_vga_set_decode(void *cookie, bool state) 1027926deccbSFrançois Tigeot { 1028926deccbSFrançois Tigeot struct radeon_device *rdev = cookie; 1029926deccbSFrançois Tigeot radeon_vga_set_state(rdev, state); 1030926deccbSFrançois Tigeot if (state) 1031926deccbSFrançois Tigeot return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | 1032926deccbSFrançois Tigeot VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 1033926deccbSFrançois Tigeot else 1034926deccbSFrançois Tigeot return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 1035926deccbSFrançois Tigeot } 1036926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1037926deccbSFrançois Tigeot 1038926deccbSFrançois Tigeot /** 1039926deccbSFrançois Tigeot * radeon_check_pot_argument - check that argument is a power of two 1040926deccbSFrançois Tigeot * 1041926deccbSFrançois Tigeot * @arg: value to check 1042926deccbSFrançois Tigeot * 1043926deccbSFrançois Tigeot * Validates that a certain argument is a power of two (all asics). 1044926deccbSFrançois Tigeot * Returns true if argument is valid. 1045926deccbSFrançois Tigeot */ 1046926deccbSFrançois Tigeot static bool radeon_check_pot_argument(int arg) 1047926deccbSFrançois Tigeot { 1048926deccbSFrançois Tigeot return (arg & (arg - 1)) == 0; 1049926deccbSFrançois Tigeot } 1050926deccbSFrançois Tigeot 1051926deccbSFrançois Tigeot /** 1052926deccbSFrançois Tigeot * radeon_check_arguments - validate module params 1053926deccbSFrançois Tigeot * 1054926deccbSFrançois Tigeot * @rdev: radeon_device pointer 1055926deccbSFrançois Tigeot * 1056926deccbSFrançois Tigeot * Validates certain module parameters and updates 1057926deccbSFrançois Tigeot * the associated values used by the driver (all asics). 1058926deccbSFrançois Tigeot */ 1059926deccbSFrançois Tigeot static void radeon_check_arguments(struct radeon_device *rdev) 1060926deccbSFrançois Tigeot { 1061926deccbSFrançois Tigeot /* vramlimit must be a power of two */ 1062926deccbSFrançois Tigeot if (!radeon_check_pot_argument(radeon_vram_limit)) { 1063926deccbSFrançois Tigeot dev_warn(rdev->dev, "vram limit (%d) must be a power of 2\n", 1064926deccbSFrançois Tigeot radeon_vram_limit); 1065926deccbSFrançois Tigeot radeon_vram_limit = 0; 1066926deccbSFrançois Tigeot } 1067926deccbSFrançois Tigeot 10684cd92098Szrj if (radeon_gart_size == -1) { 1069ee479021SImre Vadász /* default to a larger gart size on newer asics */ 1070ee479021SImre Vadász if (rdev->family >= CHIP_RV770) 1071ee479021SImre Vadász radeon_gart_size = 1024; 1072ee479021SImre Vadász else 1073ee479021SImre Vadász radeon_gart_size = 512; 10744cd92098Szrj } 1075926deccbSFrançois Tigeot /* gtt size must be power of two and greater or equal to 32M */ 1076926deccbSFrançois Tigeot if (radeon_gart_size < 32) { 10774cd92098Szrj dev_warn(rdev->dev, "gart size (%d) too small\n", 1078926deccbSFrançois Tigeot radeon_gart_size); 1079ee479021SImre Vadász if (rdev->family >= CHIP_RV770) 1080ee479021SImre Vadász radeon_gart_size = 1024; 1081ee479021SImre Vadász else 1082ee479021SImre Vadász radeon_gart_size = 512; 1083926deccbSFrançois Tigeot } else if (!radeon_check_pot_argument(radeon_gart_size)) { 1084926deccbSFrançois Tigeot dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n", 1085926deccbSFrançois Tigeot radeon_gart_size); 1086ee479021SImre Vadász if (rdev->family >= CHIP_RV770) 1087ee479021SImre Vadász radeon_gart_size = 1024; 1088ee479021SImre Vadász else 1089ee479021SImre Vadász radeon_gart_size = 512; 1090926deccbSFrançois Tigeot } 1091926deccbSFrançois Tigeot rdev->mc.gtt_size = (uint64_t)radeon_gart_size << 20; 1092926deccbSFrançois Tigeot 1093926deccbSFrançois Tigeot /* AGP mode can only be -1, 1, 2, 4, 8 */ 1094926deccbSFrançois Tigeot switch (radeon_agpmode) { 1095926deccbSFrançois Tigeot case -1: 1096926deccbSFrançois Tigeot case 0: 1097926deccbSFrançois Tigeot case 1: 1098926deccbSFrançois Tigeot case 2: 1099926deccbSFrançois Tigeot case 4: 1100926deccbSFrançois Tigeot case 8: 1101926deccbSFrançois Tigeot break; 1102926deccbSFrançois Tigeot default: 1103926deccbSFrançois Tigeot dev_warn(rdev->dev, "invalid AGP mode %d (valid mode: " 1104926deccbSFrançois Tigeot "-1, 0, 1, 2, 4, 8)\n", radeon_agpmode); 1105926deccbSFrançois Tigeot radeon_agpmode = 0; 1106926deccbSFrançois Tigeot break; 1107926deccbSFrançois Tigeot } 1108c6f73aabSFrançois Tigeot 1109c6f73aabSFrançois Tigeot if (!radeon_check_pot_argument(radeon_vm_size)) { 1110c6f73aabSFrançois Tigeot dev_warn(rdev->dev, "VM size (%d) must be a power of 2\n", 1111c6f73aabSFrançois Tigeot radeon_vm_size); 1112c6f73aabSFrançois Tigeot radeon_vm_size = 4; 1113926deccbSFrançois Tigeot } 1114926deccbSFrançois Tigeot 1115c6f73aabSFrançois Tigeot if (radeon_vm_size < 1) { 1116ee479021SImre Vadász dev_warn(rdev->dev, "VM size (%d) to small, min is 1GB\n", 1117c6f73aabSFrançois Tigeot radeon_vm_size); 1118c6f73aabSFrançois Tigeot radeon_vm_size = 4; 1119c6f73aabSFrançois Tigeot } 1120c6f73aabSFrançois Tigeot 1121c6f73aabSFrançois Tigeot /* 1122c6f73aabSFrançois Tigeot * Max GPUVM size for Cayman, SI and CI are 40 bits. 1123926deccbSFrançois Tigeot */ 1124c6f73aabSFrançois Tigeot if (radeon_vm_size > 1024) { 1125c6f73aabSFrançois Tigeot dev_warn(rdev->dev, "VM size (%d) too large, max is 1TB\n", 1126c6f73aabSFrançois Tigeot radeon_vm_size); 1127c6f73aabSFrançois Tigeot radeon_vm_size = 4; 1128926deccbSFrançois Tigeot } 1129926deccbSFrançois Tigeot 1130c6f73aabSFrançois Tigeot /* defines number of bits in page table versus page directory, 1131c6f73aabSFrançois Tigeot * a page is 4KB so we have 12 bits offset, minimum 9 bits in the 1132c6f73aabSFrançois Tigeot * page table and the remaining bits are in the page directory */ 1133c6f73aabSFrançois Tigeot if (radeon_vm_block_size == -1) { 1134c6f73aabSFrançois Tigeot 1135c6f73aabSFrançois Tigeot /* Total bits covered by PD + PTs */ 1136591d5043SFrançois Tigeot unsigned bits = ilog2(radeon_vm_size) + 18; 1137c6f73aabSFrançois Tigeot 1138c6f73aabSFrançois Tigeot /* Make sure the PD is 4K in size up to 8GB address space. 1139c6f73aabSFrançois Tigeot Above that split equal between PD and PTs */ 1140c6f73aabSFrançois Tigeot if (radeon_vm_size <= 8) 1141c6f73aabSFrançois Tigeot radeon_vm_block_size = bits - 9; 1142c6f73aabSFrançois Tigeot else 1143c6f73aabSFrançois Tigeot radeon_vm_block_size = (bits + 3) / 2; 1144c6f73aabSFrançois Tigeot 1145c6f73aabSFrançois Tigeot } else if (radeon_vm_block_size < 9) { 1146c6f73aabSFrançois Tigeot dev_warn(rdev->dev, "VM page table size (%d) too small\n", 1147c6f73aabSFrançois Tigeot radeon_vm_block_size); 1148c6f73aabSFrançois Tigeot radeon_vm_block_size = 9; 1149926deccbSFrançois Tigeot } 1150c6f73aabSFrançois Tigeot 1151c6f73aabSFrançois Tigeot if (radeon_vm_block_size > 24 || 1152c6f73aabSFrançois Tigeot (radeon_vm_size * 1024) < (1ull << radeon_vm_block_size)) { 1153c6f73aabSFrançois Tigeot dev_warn(rdev->dev, "VM page table size (%d) too large\n", 1154c6f73aabSFrançois Tigeot radeon_vm_block_size); 1155c6f73aabSFrançois Tigeot radeon_vm_block_size = 9; 1156c6f73aabSFrançois Tigeot } 1157c6f73aabSFrançois Tigeot } 1158926deccbSFrançois Tigeot 1159926deccbSFrançois Tigeot /** 1160926deccbSFrançois Tigeot * radeon_switcheroo_set_state - set switcheroo state 1161926deccbSFrançois Tigeot * 1162926deccbSFrançois Tigeot * @pdev: pci dev pointer 1163ee479021SImre Vadász * @state: vga switcheroo state 1164926deccbSFrançois Tigeot * 1165926deccbSFrançois Tigeot * Callback for the switcheroo driver. Suspends or resumes the 1166926deccbSFrançois Tigeot * the asics before or after it is powered up using ACPI methods. 1167926deccbSFrançois Tigeot */ 1168926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1169926deccbSFrançois Tigeot static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) 1170926deccbSFrançois Tigeot { 1171926deccbSFrançois Tigeot struct drm_device *dev = pci_get_drvdata(pdev); 1172c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1173c6f73aabSFrançois Tigeot 1174c6f73aabSFrançois Tigeot if (radeon_is_px(dev) && state == VGA_SWITCHEROO_OFF) 1175c6f73aabSFrançois Tigeot return; 1176c6f73aabSFrançois Tigeot 1177926deccbSFrançois Tigeot if (state == VGA_SWITCHEROO_ON) { 1178926deccbSFrançois Tigeot unsigned d3_delay = dev->pdev->d3_delay; 1179926deccbSFrançois Tigeot 1180926deccbSFrançois Tigeot printk(KERN_INFO "radeon: switched on\n"); 1181926deccbSFrançois Tigeot /* don't suspend or resume card normally */ 1182926deccbSFrançois Tigeot dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; 1183926deccbSFrançois Tigeot 1184c6f73aabSFrançois Tigeot if (d3_delay < 20 && (rdev->px_quirk_flags & RADEON_PX_QUIRK_LONG_WAKEUP)) 1185926deccbSFrançois Tigeot dev->pdev->d3_delay = 20; 1186926deccbSFrançois Tigeot 1187c6f73aabSFrançois Tigeot radeon_resume_kms(dev, true, true); 1188926deccbSFrançois Tigeot 1189926deccbSFrançois Tigeot dev->pdev->d3_delay = d3_delay; 1190926deccbSFrançois Tigeot 1191926deccbSFrançois Tigeot dev->switch_power_state = DRM_SWITCH_POWER_ON; 1192926deccbSFrançois Tigeot drm_kms_helper_poll_enable(dev); 1193926deccbSFrançois Tigeot } else { 1194926deccbSFrançois Tigeot printk(KERN_INFO "radeon: switched off\n"); 1195926deccbSFrançois Tigeot drm_kms_helper_poll_disable(dev); 1196926deccbSFrançois Tigeot dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; 1197ee479021SImre Vadász radeon_suspend_kms(dev, true, true); 1198926deccbSFrançois Tigeot dev->switch_power_state = DRM_SWITCH_POWER_OFF; 1199926deccbSFrançois Tigeot } 1200926deccbSFrançois Tigeot } 1201926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1202926deccbSFrançois Tigeot 1203926deccbSFrançois Tigeot /** 1204926deccbSFrançois Tigeot * radeon_switcheroo_can_switch - see if switcheroo state can change 1205926deccbSFrançois Tigeot * 1206926deccbSFrançois Tigeot * @pdev: pci dev pointer 1207926deccbSFrançois Tigeot * 1208926deccbSFrançois Tigeot * Callback for the switcheroo driver. Check of the switcheroo 1209926deccbSFrançois Tigeot * state can be changed. 1210926deccbSFrançois Tigeot * Returns true if the state can be changed, false if not. 1211926deccbSFrançois Tigeot */ 1212926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1213926deccbSFrançois Tigeot static bool radeon_switcheroo_can_switch(struct pci_dev *pdev) 1214926deccbSFrançois Tigeot { 1215926deccbSFrançois Tigeot struct drm_device *dev = pci_get_drvdata(pdev); 1216926deccbSFrançois Tigeot 1217c6f73aabSFrançois Tigeot /* 1218c6f73aabSFrançois Tigeot * FIXME: open_count is protected by drm_global_mutex but that would lead to 1219c6f73aabSFrançois Tigeot * locking inversion with the driver load path. And the access here is 1220c6f73aabSFrançois Tigeot * completely racy anyway. So don't bother with locking for now. 1221c6f73aabSFrançois Tigeot */ 1222c6f73aabSFrançois Tigeot return dev->open_count == 0; 1223926deccbSFrançois Tigeot } 1224926deccbSFrançois Tigeot 1225926deccbSFrançois Tigeot static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { 1226926deccbSFrançois Tigeot .set_gpu_state = radeon_switcheroo_set_state, 1227926deccbSFrançois Tigeot .reprobe = NULL, 1228926deccbSFrançois Tigeot .can_switch = radeon_switcheroo_can_switch, 1229926deccbSFrançois Tigeot }; 1230926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1231926deccbSFrançois Tigeot 1232926deccbSFrançois Tigeot /** 1233926deccbSFrançois Tigeot * radeon_device_init - initialize the driver 1234926deccbSFrançois Tigeot * 1235926deccbSFrançois Tigeot * @rdev: radeon_device pointer 1236926deccbSFrançois Tigeot * @pdev: drm dev pointer 1237c6f73aabSFrançois Tigeot * @pdev: pci dev pointer 1238926deccbSFrançois Tigeot * @flags: driver flags 1239926deccbSFrançois Tigeot * 1240926deccbSFrançois Tigeot * Initializes the driver info and hw (all asics). 1241926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1242926deccbSFrançois Tigeot * Called at driver startup. 1243926deccbSFrançois Tigeot */ 1244926deccbSFrançois Tigeot int radeon_device_init(struct radeon_device *rdev, 1245926deccbSFrançois Tigeot struct drm_device *ddev, 1246c6f73aabSFrançois Tigeot struct pci_dev *pdev, 1247926deccbSFrançois Tigeot uint32_t flags) 1248926deccbSFrançois Tigeot { 1249926deccbSFrançois Tigeot int r, i; 1250926deccbSFrançois Tigeot int dma_bits; 1251c6f73aabSFrançois Tigeot #ifdef PM_TODO 1252c6f73aabSFrançois Tigeot bool runtime = false; 1253c6f73aabSFrançois Tigeot #endif 1254926deccbSFrançois Tigeot 1255926deccbSFrançois Tigeot rdev->shutdown = false; 1256fb572d17SFrançois Tigeot rdev->dev = &pdev->dev; 1257926deccbSFrançois Tigeot rdev->ddev = ddev; 1258c6f73aabSFrançois Tigeot rdev->pdev = pdev; 1259926deccbSFrançois Tigeot rdev->flags = flags; 1260926deccbSFrançois Tigeot rdev->family = flags & RADEON_FAMILY_MASK; 1261926deccbSFrançois Tigeot rdev->is_atom_bios = false; 1262926deccbSFrançois Tigeot rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT; 12634cd92098Szrj rdev->mc.gtt_size = 512 * 1024 * 1024; 1264926deccbSFrançois Tigeot rdev->accel_working = false; 1265926deccbSFrançois Tigeot rdev->fictitious_range_registered = false; 1266926deccbSFrançois Tigeot /* set up ring ids */ 1267926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) { 1268926deccbSFrançois Tigeot rdev->ring[i].idx = i; 1269926deccbSFrançois Tigeot } 1270926deccbSFrançois Tigeot 1271ee479021SImre Vadász DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", 1272c6f73aabSFrançois Tigeot radeon_family_name[rdev->family], pdev->vendor, pdev->device, 1273ee479021SImre Vadász pdev->subsystem_vendor, pdev->subsystem_device); 1274926deccbSFrançois Tigeot 1275926deccbSFrançois Tigeot /* mutex initialization are all done here so we 1276926deccbSFrançois Tigeot * can recall function without having locking issues */ 1277*1ca17f9bSFrançois Tigeot lockinit(&rdev->ring_lock, "drdrl", 0, LK_CANRECURSE); 1278*1ca17f9bSFrançois Tigeot lockinit(&rdev->dc_hw_i2c_mutex, "drddi2cm", 0, LK_CANRECURSE); 1279926deccbSFrançois Tigeot atomic_set(&rdev->ih.lock, 0); 1280fefad7a7SFrançois Tigeot lockinit(&rdev->gem.mutex, "radeon_gemmtx", 0, LK_CANRECURSE); 1281*1ca17f9bSFrançois Tigeot lockinit(&rdev->pm.mutex, "drdpmm", 0, LK_CANRECURSE); 1282fefad7a7SFrançois Tigeot 1283fefad7a7SFrançois Tigeot lockinit(&rdev->gpu_clock_mutex, "radeon_clockmtx", 0, LK_CANRECURSE); 1284fefad7a7SFrançois Tigeot lockinit(&rdev->srbm_mutex, "radeon_srbm_mutex", 0, LK_CANRECURSE); 1285*1ca17f9bSFrançois Tigeot lockinit(&rdev->pm.mclk_lock, "drpmml", 0, LK_CANRECURSE); 1286*1ca17f9bSFrançois Tigeot lockinit(&rdev->exclusive_lock, "drdel", 0, LK_CANRECURSE); 1287c6f73aabSFrançois Tigeot init_waitqueue_head(&rdev->irq.vblank_queue); 1288926deccbSFrançois Tigeot r = radeon_gem_init(rdev); 1289926deccbSFrançois Tigeot if (r) 1290926deccbSFrançois Tigeot return r; 1291c6f73aabSFrançois Tigeot 1292c6f73aabSFrançois Tigeot radeon_check_arguments(rdev); 1293926deccbSFrançois Tigeot /* Adjust VM size here. 1294c6f73aabSFrançois Tigeot * Max GPUVM size for cayman+ is 40 bits. 1295926deccbSFrançois Tigeot */ 1296c6f73aabSFrançois Tigeot rdev->vm_manager.max_pfn = radeon_vm_size << 18; 1297926deccbSFrançois Tigeot 1298926deccbSFrançois Tigeot /* Set asic functions */ 1299926deccbSFrançois Tigeot r = radeon_asic_init(rdev); 1300926deccbSFrançois Tigeot if (r) 1301926deccbSFrançois Tigeot return r; 1302926deccbSFrançois Tigeot 1303926deccbSFrançois Tigeot /* all of the newer IGP chips have an internal gart 1304926deccbSFrançois Tigeot * However some rs4xx report as AGP, so remove that here. 1305926deccbSFrançois Tigeot */ 1306926deccbSFrançois Tigeot if ((rdev->family >= CHIP_RS400) && 1307926deccbSFrançois Tigeot (rdev->flags & RADEON_IS_IGP)) { 1308926deccbSFrançois Tigeot rdev->flags &= ~RADEON_IS_AGP; 1309926deccbSFrançois Tigeot } 1310926deccbSFrançois Tigeot 1311926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) { 1312926deccbSFrançois Tigeot radeon_agp_disable(rdev); 1313926deccbSFrançois Tigeot } 1314926deccbSFrançois Tigeot 1315f43cf1b1SMichael Neumann /* Set the internal MC address mask 1316f43cf1b1SMichael Neumann * This is the max address of the GPU's 1317f43cf1b1SMichael Neumann * internal address space. 1318f43cf1b1SMichael Neumann */ 1319f43cf1b1SMichael Neumann if (rdev->family >= CHIP_CAYMAN) 1320f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xffffffffffULL; /* 40 bit MC */ 1321f43cf1b1SMichael Neumann else if (rdev->family >= CHIP_CEDAR) 1322f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xfffffffffULL; /* 36 bit MC */ 1323f43cf1b1SMichael Neumann else 1324f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xffffffffULL; /* 32 bit MC */ 1325f43cf1b1SMichael Neumann 1326926deccbSFrançois Tigeot /* set DMA mask + need_dma32 flags. 1327926deccbSFrançois Tigeot * PCIE - can handle 40-bits. 1328926deccbSFrançois Tigeot * IGP - can handle 40-bits 1329926deccbSFrançois Tigeot * AGP - generally dma32 is safest 1330926deccbSFrançois Tigeot * PCI - dma32 for legacy pci gart, 40 bits on newer asics 1331926deccbSFrançois Tigeot */ 1332926deccbSFrançois Tigeot rdev->need_dma32 = false; 1333926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP) 1334926deccbSFrançois Tigeot rdev->need_dma32 = true; 1335926deccbSFrançois Tigeot if ((rdev->flags & RADEON_IS_PCI) && 1336926deccbSFrançois Tigeot (rdev->family <= CHIP_RS740)) 1337926deccbSFrançois Tigeot rdev->need_dma32 = true; 1338926deccbSFrançois Tigeot 1339926deccbSFrançois Tigeot dma_bits = rdev->need_dma32 ? 32 : 40; 1340926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1341926deccbSFrançois Tigeot r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); 1342926deccbSFrançois Tigeot if (r) { 1343926deccbSFrançois Tigeot rdev->need_dma32 = true; 1344926deccbSFrançois Tigeot dma_bits = 32; 1345926deccbSFrançois Tigeot printk(KERN_WARNING "radeon: No suitable DMA available.\n"); 1346926deccbSFrançois Tigeot } 1347926deccbSFrançois Tigeot r = pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); 1348926deccbSFrançois Tigeot if (r) { 1349926deccbSFrançois Tigeot pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(32)); 1350926deccbSFrançois Tigeot printk(KERN_WARNING "radeon: No coherent DMA available.\n"); 1351926deccbSFrançois Tigeot } 1352926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1353926deccbSFrançois Tigeot 1354926deccbSFrançois Tigeot /* Registers mapping */ 1355926deccbSFrançois Tigeot /* TODO: block userspace mapping of io register */ 1356ee479021SImre Vadász spin_init(&rdev->mmio_idx_lock, "radeon_mpio"); 1357ee479021SImre Vadász spin_init(&rdev->smc_idx_lock, "radeon_smc"); 1358ee479021SImre Vadász spin_init(&rdev->pll_idx_lock, "radeon_pll"); 1359ee479021SImre Vadász spin_init(&rdev->mc_idx_lock, "radeon_mc"); 1360ee479021SImre Vadász spin_init(&rdev->pcie_idx_lock, "radeon_pcie"); 1361ee479021SImre Vadász spin_init(&rdev->pciep_idx_lock, "radeon_pciep"); 1362ee479021SImre Vadász spin_init(&rdev->pif_idx_lock, "radeon_pif"); 1363ee479021SImre Vadász spin_init(&rdev->cg_idx_lock, "radeon_cg"); 1364ee479021SImre Vadász spin_init(&rdev->uvd_idx_lock, "radeon_uvd"); 1365ee479021SImre Vadász spin_init(&rdev->rcu_idx_lock, "radeon_rcu"); 1366ee479021SImre Vadász spin_init(&rdev->didt_idx_lock, "radeon_didt"); 1367ee479021SImre Vadász spin_init(&rdev->end_idx_lock, "radeon_end"); 136857e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) { 136957e252bfSMichael Neumann rdev->rmmio_rid = PCIR_BAR(5); 137057e252bfSMichael Neumann } else { 1371926deccbSFrançois Tigeot rdev->rmmio_rid = PCIR_BAR(2); 137257e252bfSMichael Neumann } 1373fb572d17SFrançois Tigeot rdev->rmmio = bus_alloc_resource_any(rdev->dev->bsddev, SYS_RES_MEMORY, 1374926deccbSFrançois Tigeot &rdev->rmmio_rid, RF_ACTIVE | RF_SHAREABLE); 1375926deccbSFrançois Tigeot if (rdev->rmmio == NULL) { 1376926deccbSFrançois Tigeot return -ENOMEM; 1377926deccbSFrançois Tigeot } 1378926deccbSFrançois Tigeot rdev->rmmio_base = rman_get_start(rdev->rmmio); 1379926deccbSFrançois Tigeot rdev->rmmio_size = rman_get_size(rdev->rmmio); 1380926deccbSFrançois Tigeot DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base); 1381926deccbSFrançois Tigeot DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size); 1382926deccbSFrançois Tigeot 138357e252bfSMichael Neumann /* doorbell bar mapping */ 138457e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) 138557e252bfSMichael Neumann radeon_doorbell_init(rdev); 138657e252bfSMichael Neumann 1387926deccbSFrançois Tigeot /* io port mapping */ 1388926deccbSFrançois Tigeot for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) { 1389926deccbSFrançois Tigeot uint32_t data; 1390926deccbSFrançois Tigeot 1391fb572d17SFrançois Tigeot data = pci_read_config(rdev->dev->bsddev, PCIR_BAR(i), 4); 1392926deccbSFrançois Tigeot if (PCI_BAR_IO(data)) { 1393926deccbSFrançois Tigeot rdev->rio_rid = PCIR_BAR(i); 1394fb572d17SFrançois Tigeot rdev->rio_mem = bus_alloc_resource_any(rdev->dev->bsddev, 1395926deccbSFrançois Tigeot SYS_RES_IOPORT, &rdev->rio_rid, 1396926deccbSFrançois Tigeot RF_ACTIVE | RF_SHAREABLE); 1397926deccbSFrançois Tigeot break; 1398926deccbSFrançois Tigeot } 1399926deccbSFrançois Tigeot } 1400926deccbSFrançois Tigeot if (rdev->rio_mem == NULL) 1401926deccbSFrançois Tigeot DRM_ERROR("Unable to find PCI I/O BAR\n"); 1402926deccbSFrançois Tigeot 1403c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 1404c6f73aabSFrançois Tigeot radeon_device_handle_px_quirks(rdev); 1405c6f73aabSFrançois Tigeot 1406926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1407926deccbSFrançois Tigeot /* if we have > 1 VGA cards, then disable the radeon VGA resources */ 1408926deccbSFrançois Tigeot /* this will fail for cards that aren't VGA class devices, just 1409926deccbSFrançois Tigeot * ignore it */ 1410926deccbSFrançois Tigeot vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); 1411c6f73aabSFrançois Tigeot 1412c6f73aabSFrançois Tigeot #ifdef PM_TODO 1413c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 1414c6f73aabSFrançois Tigeot runtime = true; 1415c6f73aabSFrançois Tigeot vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime); 1416c6f73aabSFrançois Tigeot if (runtime) 1417fb572d17SFrançois Tigeot vga_switcheroo_init_domain_pm_ops(rdev->dev->bsddev, &rdev->vga_pm_domain); 1418c6f73aabSFrançois Tigeot #endif 1419926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1420926deccbSFrançois Tigeot 1421926deccbSFrançois Tigeot r = radeon_init(rdev); 1422926deccbSFrançois Tigeot if (r) 1423c6f73aabSFrançois Tigeot goto failed; 1424926deccbSFrançois Tigeot 1425f43cf1b1SMichael Neumann r = radeon_gem_debugfs_init(rdev); 1426f43cf1b1SMichael Neumann if (r) { 1427f43cf1b1SMichael Neumann DRM_ERROR("registering gem debugfs failed (%d).\n", r); 1428f43cf1b1SMichael Neumann } 1429f43cf1b1SMichael Neumann 1430926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) { 1431926deccbSFrançois Tigeot /* Acceleration not working on AGP card try again 1432926deccbSFrançois Tigeot * with fallback to PCI or PCIE GART 1433926deccbSFrançois Tigeot */ 1434926deccbSFrançois Tigeot radeon_asic_reset(rdev); 1435926deccbSFrançois Tigeot radeon_fini(rdev); 1436926deccbSFrançois Tigeot radeon_agp_disable(rdev); 1437926deccbSFrançois Tigeot r = radeon_init(rdev); 1438926deccbSFrançois Tigeot if (r) 1439c6f73aabSFrançois Tigeot goto failed; 1440926deccbSFrançois Tigeot } 1441926deccbSFrançois Tigeot 1442591d5043SFrançois Tigeot r = radeon_ib_ring_tests(rdev); 1443591d5043SFrançois Tigeot if (r) 1444591d5043SFrançois Tigeot DRM_ERROR("ib ring test failed (%d).\n", r); 1445591d5043SFrançois Tigeot 1446f77dbd6cSFrançois Tigeot DRM_INFO("%s: Taking over the fictitious range 0x%lx-0x%llx\n", 1447926deccbSFrançois Tigeot __func__, (uintmax_t)rdev->mc.aper_base, 1448926deccbSFrançois Tigeot (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size); 1449926deccbSFrançois Tigeot r = vm_phys_fictitious_reg_range( 1450926deccbSFrançois Tigeot rdev->mc.aper_base, 1451926deccbSFrançois Tigeot rdev->mc.aper_base + rdev->mc.visible_vram_size, 1452926deccbSFrançois Tigeot VM_MEMATTR_WRITE_COMBINING); 1453926deccbSFrançois Tigeot if (r != 0) { 1454926deccbSFrançois Tigeot DRM_ERROR("Failed to register fictitious range " 1455f77dbd6cSFrançois Tigeot "0x%lx-0x%llx (%d).\n", (uintmax_t)rdev->mc.aper_base, 1456926deccbSFrançois Tigeot (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size, r); 1457926deccbSFrançois Tigeot return (-r); 1458926deccbSFrançois Tigeot } 1459926deccbSFrançois Tigeot rdev->fictitious_range_registered = true; 1460926deccbSFrançois Tigeot 1461926deccbSFrançois Tigeot if ((radeon_testing & 1)) { 14624cd92098Szrj if (rdev->accel_working) 1463926deccbSFrançois Tigeot radeon_test_moves(rdev); 14644cd92098Szrj else 14654cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping move tests\n"); 1466926deccbSFrançois Tigeot } 1467926deccbSFrançois Tigeot if ((radeon_testing & 2)) { 14684cd92098Szrj if (rdev->accel_working) 1469926deccbSFrançois Tigeot radeon_test_syncing(rdev); 14704cd92098Szrj else 14714cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping sync tests\n"); 1472926deccbSFrançois Tigeot } 1473926deccbSFrançois Tigeot if (radeon_benchmarking) { 14744cd92098Szrj if (rdev->accel_working) 1475926deccbSFrançois Tigeot radeon_benchmark(rdev, radeon_benchmarking); 14764cd92098Szrj else 14774cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n"); 1478926deccbSFrançois Tigeot } 1479926deccbSFrançois Tigeot return 0; 1480c6f73aabSFrançois Tigeot 1481c6f73aabSFrançois Tigeot failed: 1482c6f73aabSFrançois Tigeot #ifdef DRM_BDSM 1483c6f73aabSFrançois Tigeot if (runtime) 1484c6f73aabSFrançois Tigeot vga_switcheroo_fini_domain_pm_ops(rdev->dev); 1485c6f73aabSFrançois Tigeot #endif 1486c6f73aabSFrançois Tigeot return r; 1487926deccbSFrançois Tigeot } 1488926deccbSFrançois Tigeot 1489926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1490926deccbSFrançois Tigeot static void radeon_debugfs_remove_files(struct radeon_device *rdev); 1491926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1492926deccbSFrançois Tigeot 1493926deccbSFrançois Tigeot /** 1494926deccbSFrançois Tigeot * radeon_device_fini - tear down the driver 1495926deccbSFrançois Tigeot * 1496926deccbSFrançois Tigeot * @rdev: radeon_device pointer 1497926deccbSFrançois Tigeot * 1498926deccbSFrançois Tigeot * Tear down the driver info (all asics). 1499926deccbSFrançois Tigeot * Called at driver shutdown. 1500926deccbSFrançois Tigeot */ 1501926deccbSFrançois Tigeot void radeon_device_fini(struct radeon_device *rdev) 1502926deccbSFrançois Tigeot { 1503926deccbSFrançois Tigeot DRM_INFO("radeon: finishing device.\n"); 1504926deccbSFrançois Tigeot rdev->shutdown = true; 1505926deccbSFrançois Tigeot /* evict vram memory */ 1506926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev); 1507926deccbSFrançois Tigeot 1508926deccbSFrançois Tigeot if (rdev->fictitious_range_registered) { 1509926deccbSFrançois Tigeot vm_phys_fictitious_unreg_range( 1510926deccbSFrançois Tigeot rdev->mc.aper_base, 1511926deccbSFrançois Tigeot rdev->mc.aper_base + rdev->mc.visible_vram_size); 1512926deccbSFrançois Tigeot } 1513926deccbSFrançois Tigeot 1514926deccbSFrançois Tigeot radeon_fini(rdev); 1515926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1516926deccbSFrançois Tigeot vga_switcheroo_unregister_client(rdev->pdev); 1517c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 1518c6f73aabSFrançois Tigeot vga_switcheroo_fini_domain_pm_ops(rdev->dev); 1519926deccbSFrançois Tigeot vga_client_register(rdev->pdev, NULL, NULL, NULL); 1520926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1521926deccbSFrançois Tigeot 1522926deccbSFrançois Tigeot if (rdev->rio_mem) 1523fb572d17SFrançois Tigeot bus_release_resource(rdev->dev->bsddev, SYS_RES_IOPORT, rdev->rio_rid, 1524926deccbSFrançois Tigeot rdev->rio_mem); 1525926deccbSFrançois Tigeot rdev->rio_mem = NULL; 1526fb572d17SFrançois Tigeot bus_release_resource(rdev->dev->bsddev, SYS_RES_MEMORY, rdev->rmmio_rid, 1527926deccbSFrançois Tigeot rdev->rmmio); 1528926deccbSFrançois Tigeot rdev->rmmio = NULL; 152957e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) 153057e252bfSMichael Neumann radeon_doorbell_fini(rdev); 1531926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1532926deccbSFrançois Tigeot radeon_debugfs_remove_files(rdev); 1533926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1534926deccbSFrançois Tigeot } 1535926deccbSFrançois Tigeot 1536926deccbSFrançois Tigeot 1537926deccbSFrançois Tigeot /* 1538926deccbSFrançois Tigeot * Suspend & resume. 1539926deccbSFrançois Tigeot */ 1540926deccbSFrançois Tigeot /** 1541926deccbSFrançois Tigeot * radeon_suspend_kms - initiate device suspend 1542926deccbSFrançois Tigeot * 1543926deccbSFrançois Tigeot * @pdev: drm dev pointer 1544926deccbSFrançois Tigeot * @state: suspend state 1545926deccbSFrançois Tigeot * 1546926deccbSFrançois Tigeot * Puts the hw in the suspend state (all asics). 1547926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1548926deccbSFrançois Tigeot * Called at driver suspend. 1549926deccbSFrançois Tigeot */ 1550ee479021SImre Vadász int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) 1551926deccbSFrançois Tigeot { 1552926deccbSFrançois Tigeot struct radeon_device *rdev; 1553926deccbSFrançois Tigeot struct drm_crtc *crtc; 1554926deccbSFrançois Tigeot struct drm_connector *connector; 1555926deccbSFrançois Tigeot int i, r; 1556926deccbSFrançois Tigeot 1557926deccbSFrançois Tigeot if (dev == NULL || dev->dev_private == NULL) { 1558926deccbSFrançois Tigeot return -ENODEV; 1559926deccbSFrançois Tigeot } 1560c6f73aabSFrançois Tigeot 1561926deccbSFrançois Tigeot rdev = dev->dev_private; 1562926deccbSFrançois Tigeot 1563926deccbSFrançois Tigeot if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 1564926deccbSFrançois Tigeot return 0; 1565926deccbSFrançois Tigeot 1566926deccbSFrançois Tigeot drm_kms_helper_poll_disable(dev); 1567926deccbSFrançois Tigeot 1568926deccbSFrançois Tigeot /* turn off display hw */ 1569926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1570926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); 1571926deccbSFrançois Tigeot } 1572926deccbSFrançois Tigeot 1573ee479021SImre Vadász /* unpin the front buffers */ 1574926deccbSFrançois Tigeot list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 1575ba55f2f5SFrançois Tigeot struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb); 1576926deccbSFrançois Tigeot struct radeon_bo *robj; 1577926deccbSFrançois Tigeot 1578926deccbSFrançois Tigeot if (rfb == NULL || rfb->obj == NULL) { 1579926deccbSFrançois Tigeot continue; 1580926deccbSFrançois Tigeot } 1581926deccbSFrançois Tigeot robj = gem_to_radeon_bo(rfb->obj); 1582926deccbSFrançois Tigeot /* don't unpin kernel fb objects */ 1583926deccbSFrançois Tigeot if (!radeon_fbdev_robj_is_fb(rdev, robj)) { 1584926deccbSFrançois Tigeot r = radeon_bo_reserve(robj, false); 1585926deccbSFrançois Tigeot if (r == 0) { 1586926deccbSFrançois Tigeot radeon_bo_unpin(robj); 1587926deccbSFrançois Tigeot radeon_bo_unreserve(robj); 1588926deccbSFrançois Tigeot } 1589926deccbSFrançois Tigeot } 1590926deccbSFrançois Tigeot } 1591926deccbSFrançois Tigeot /* evict vram memory */ 1592926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev); 1593926deccbSFrançois Tigeot 1594926deccbSFrançois Tigeot /* wait for gpu to finish processing current batch */ 1595926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) { 1596c6f73aabSFrançois Tigeot r = radeon_fence_wait_empty(rdev, i); 1597926deccbSFrançois Tigeot if (r) { 1598926deccbSFrançois Tigeot /* delay GPU reset to resume */ 1599c6f73aabSFrançois Tigeot radeon_fence_driver_force_completion(rdev, i); 1600926deccbSFrançois Tigeot } 1601926deccbSFrançois Tigeot } 1602926deccbSFrançois Tigeot 1603926deccbSFrançois Tigeot radeon_save_bios_scratch_regs(rdev); 1604926deccbSFrançois Tigeot 1605926deccbSFrançois Tigeot radeon_suspend(rdev); 1606926deccbSFrançois Tigeot radeon_hpd_fini(rdev); 1607926deccbSFrançois Tigeot /* evict remaining vram memory */ 1608926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev); 1609926deccbSFrançois Tigeot 1610926deccbSFrançois Tigeot radeon_agp_suspend(rdev); 1611926deccbSFrançois Tigeot 1612fb572d17SFrançois Tigeot pci_save_state(device_get_parent(rdev->dev->bsddev)); 1613926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1614ee479021SImre Vadász if (suspend) { 1615926deccbSFrançois Tigeot /* Shut down the device */ 1616926deccbSFrançois Tigeot pci_disable_device(dev->pdev); 1617926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1618fb572d17SFrançois Tigeot pci_set_powerstate(dev->dev->bsddev, PCI_POWERSTATE_D3); 1619926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1620926deccbSFrançois Tigeot } 1621c6f73aabSFrançois Tigeot #endif 1622c6f73aabSFrançois Tigeot if (fbcon) { 1623c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP 1624926deccbSFrançois Tigeot console_lock(); 1625926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1626926deccbSFrançois Tigeot radeon_fbdev_set_suspend(rdev, 1); 1627926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1628926deccbSFrançois Tigeot console_unlock(); 1629926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1630c6f73aabSFrançois Tigeot } 1631926deccbSFrançois Tigeot return 0; 1632926deccbSFrançois Tigeot } 1633926deccbSFrançois Tigeot 1634926deccbSFrançois Tigeot /** 1635926deccbSFrançois Tigeot * radeon_resume_kms - initiate device resume 1636926deccbSFrançois Tigeot * 1637926deccbSFrançois Tigeot * @pdev: drm dev pointer 1638926deccbSFrançois Tigeot * 1639926deccbSFrançois Tigeot * Bring the hw back to operating state (all asics). 1640926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1641926deccbSFrançois Tigeot * Called at driver resume. 1642926deccbSFrançois Tigeot */ 1643c6f73aabSFrançois Tigeot int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) 1644926deccbSFrançois Tigeot { 1645926deccbSFrançois Tigeot struct drm_connector *connector; 1646926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1647926deccbSFrançois Tigeot int r; 1648926deccbSFrançois Tigeot 1649926deccbSFrançois Tigeot if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 1650926deccbSFrançois Tigeot return 0; 1651926deccbSFrançois Tigeot 1652926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1653c6f73aabSFrançois Tigeot if (fbcon) { 1654926deccbSFrançois Tigeot console_lock(); 1655c6f73aabSFrançois Tigeot } 1656926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1657c6f73aabSFrançois Tigeot if (resume) { 1658fb572d17SFrançois Tigeot pci_set_powerstate(dev->dev->bsddev, PCI_POWERSTATE_D0); 1659fb572d17SFrançois Tigeot pci_restore_state(device_get_parent(rdev->dev->bsddev)); 1660926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1661926deccbSFrançois Tigeot if (pci_enable_device(dev->pdev)) { 1662c6f73aabSFrançois Tigeot if (fbcon) 1663926deccbSFrançois Tigeot console_unlock(); 1664926deccbSFrançois Tigeot return -1; 1665926deccbSFrançois Tigeot } 1666926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1667c6f73aabSFrançois Tigeot } 1668926deccbSFrançois Tigeot /* resume AGP if in use */ 1669926deccbSFrançois Tigeot radeon_agp_resume(rdev); 1670926deccbSFrançois Tigeot radeon_resume(rdev); 1671926deccbSFrançois Tigeot 1672926deccbSFrançois Tigeot r = radeon_ib_ring_tests(rdev); 1673926deccbSFrançois Tigeot if (r) 1674926deccbSFrançois Tigeot DRM_ERROR("ib ring test failed (%d).\n", r); 1675926deccbSFrançois Tigeot 1676c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 1677c6f73aabSFrançois Tigeot /* do dpm late init */ 1678c6f73aabSFrançois Tigeot r = radeon_pm_late_init(rdev); 1679c6f73aabSFrançois Tigeot if (r) { 1680c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = false; 1681c6f73aabSFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); 1682c6f73aabSFrançois Tigeot } 1683c6f73aabSFrançois Tigeot } else { 1684c6f73aabSFrançois Tigeot /* resume old pm late */ 1685926deccbSFrançois Tigeot radeon_pm_resume(rdev); 1686c6f73aabSFrançois Tigeot } 1687926deccbSFrançois Tigeot 1688c6f73aabSFrançois Tigeot radeon_restore_bios_scratch_regs(rdev); 1689926deccbSFrançois Tigeot 1690926deccbSFrançois Tigeot /* init dig PHYs, disp eng pll */ 1691926deccbSFrançois Tigeot if (rdev->is_atom_bios) { 1692926deccbSFrançois Tigeot radeon_atom_encoder_init(rdev); 1693926deccbSFrançois Tigeot radeon_atom_disp_eng_pll_init(rdev); 1694926deccbSFrançois Tigeot /* turn on the BL */ 1695926deccbSFrançois Tigeot if (rdev->mode_info.bl_encoder) { 1696926deccbSFrançois Tigeot u8 bl_level = radeon_get_backlight_level(rdev, 1697926deccbSFrançois Tigeot rdev->mode_info.bl_encoder); 1698926deccbSFrançois Tigeot radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, 1699926deccbSFrançois Tigeot bl_level); 1700926deccbSFrançois Tigeot } 1701926deccbSFrançois Tigeot } 1702926deccbSFrançois Tigeot /* reset hpd state */ 1703926deccbSFrançois Tigeot radeon_hpd_init(rdev); 1704926deccbSFrançois Tigeot /* blat the mode back in */ 1705c6f73aabSFrançois Tigeot if (fbcon) { 1706926deccbSFrançois Tigeot drm_helper_resume_force_mode(dev); 1707926deccbSFrançois Tigeot /* turn on display hw */ 1708926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1709926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); 1710926deccbSFrançois Tigeot } 1711c6f73aabSFrançois Tigeot } 1712926deccbSFrançois Tigeot 1713926deccbSFrançois Tigeot drm_kms_helper_poll_enable(dev); 1714c6f73aabSFrançois Tigeot 1715c6f73aabSFrançois Tigeot /* set the power state here in case we are a PX system or headless */ 1716c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 1717c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1718c6f73aabSFrançois Tigeot 1719c6f73aabSFrançois Tigeot if (fbcon) { 1720c6f73aabSFrançois Tigeot radeon_fbdev_set_suspend(rdev, 0); 1721c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP 1722c6f73aabSFrançois Tigeot console_unlock(); 1723c6f73aabSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1724c6f73aabSFrançois Tigeot } 1725c6f73aabSFrançois Tigeot 1726926deccbSFrançois Tigeot return 0; 1727926deccbSFrançois Tigeot } 1728926deccbSFrançois Tigeot 1729926deccbSFrançois Tigeot /** 1730926deccbSFrançois Tigeot * radeon_gpu_reset - reset the asic 1731926deccbSFrançois Tigeot * 1732926deccbSFrançois Tigeot * @rdev: radeon device pointer 1733926deccbSFrançois Tigeot * 1734926deccbSFrançois Tigeot * Attempt the reset the GPU if it has hung (all asics). 1735926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1736926deccbSFrançois Tigeot */ 1737926deccbSFrançois Tigeot int radeon_gpu_reset(struct radeon_device *rdev) 1738926deccbSFrançois Tigeot { 1739926deccbSFrançois Tigeot unsigned ring_sizes[RADEON_NUM_RINGS]; 1740926deccbSFrançois Tigeot uint32_t *ring_data[RADEON_NUM_RINGS]; 1741926deccbSFrançois Tigeot 1742926deccbSFrançois Tigeot bool saved = false; 1743926deccbSFrançois Tigeot 1744926deccbSFrançois Tigeot int i, r; 1745926deccbSFrançois Tigeot int resched; 1746926deccbSFrançois Tigeot 1747926deccbSFrançois Tigeot lockmgr(&rdev->exclusive_lock, LK_EXCLUSIVE); 1748c6f73aabSFrançois Tigeot 1749c6f73aabSFrançois Tigeot if (!rdev->needs_reset) { 1750c6f73aabSFrançois Tigeot lockmgr(&rdev->exclusive_lock, LK_RELEASE); 1751c6f73aabSFrançois Tigeot return 0; 1752c6f73aabSFrançois Tigeot } 1753c6f73aabSFrançois Tigeot 1754926deccbSFrançois Tigeot radeon_save_bios_scratch_regs(rdev); 1755926deccbSFrançois Tigeot /* block TTM */ 1756926deccbSFrançois Tigeot resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); 1757926deccbSFrançois Tigeot radeon_suspend(rdev); 1758c6f73aabSFrançois Tigeot radeon_hpd_fini(rdev); 1759926deccbSFrançois Tigeot 1760926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) { 1761926deccbSFrançois Tigeot ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i], 1762926deccbSFrançois Tigeot &ring_data[i]); 1763926deccbSFrançois Tigeot if (ring_sizes[i]) { 1764926deccbSFrançois Tigeot saved = true; 1765926deccbSFrançois Tigeot dev_info(rdev->dev, "Saved %d dwords of commands " 1766926deccbSFrançois Tigeot "on ring %d.\n", ring_sizes[i], i); 1767926deccbSFrançois Tigeot } 1768926deccbSFrançois Tigeot } 1769926deccbSFrançois Tigeot 1770926deccbSFrançois Tigeot r = radeon_asic_reset(rdev); 1771926deccbSFrançois Tigeot if (!r) { 1772926deccbSFrançois Tigeot dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n"); 1773926deccbSFrançois Tigeot radeon_resume(rdev); 1774926deccbSFrançois Tigeot } 1775926deccbSFrançois Tigeot 1776926deccbSFrançois Tigeot radeon_restore_bios_scratch_regs(rdev); 1777926deccbSFrançois Tigeot 1778926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) { 1779591d5043SFrançois Tigeot if (!r && ring_data[i]) { 1780926deccbSFrançois Tigeot radeon_ring_restore(rdev, &rdev->ring[i], 1781926deccbSFrançois Tigeot ring_sizes[i], ring_data[i]); 1782926deccbSFrançois Tigeot } else { 1783c6f73aabSFrançois Tigeot radeon_fence_driver_force_completion(rdev, i); 1784c4ef309bSzrj kfree(ring_data[i]); 1785926deccbSFrançois Tigeot } 1786926deccbSFrançois Tigeot } 1787926deccbSFrançois Tigeot 1788c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 1789c6f73aabSFrançois Tigeot /* do dpm late init */ 1790c6f73aabSFrançois Tigeot r = radeon_pm_late_init(rdev); 1791c6f73aabSFrançois Tigeot if (r) { 1792c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = false; 1793c6f73aabSFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); 1794c6f73aabSFrançois Tigeot } 1795c6f73aabSFrançois Tigeot } else { 1796c6f73aabSFrançois Tigeot /* resume old pm late */ 179757e252bfSMichael Neumann radeon_pm_resume(rdev); 1798c6f73aabSFrançois Tigeot } 1799c6f73aabSFrançois Tigeot 1800c6f73aabSFrançois Tigeot /* init dig PHYs, disp eng pll */ 1801c6f73aabSFrançois Tigeot if (rdev->is_atom_bios) { 1802c6f73aabSFrançois Tigeot radeon_atom_encoder_init(rdev); 1803c6f73aabSFrançois Tigeot radeon_atom_disp_eng_pll_init(rdev); 1804c6f73aabSFrançois Tigeot /* turn on the BL */ 1805c6f73aabSFrançois Tigeot if (rdev->mode_info.bl_encoder) { 1806c6f73aabSFrançois Tigeot u8 bl_level = radeon_get_backlight_level(rdev, 1807c6f73aabSFrançois Tigeot rdev->mode_info.bl_encoder); 1808c6f73aabSFrançois Tigeot radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, 1809c6f73aabSFrançois Tigeot bl_level); 1810c6f73aabSFrançois Tigeot } 1811c6f73aabSFrançois Tigeot } 1812c6f73aabSFrançois Tigeot /* reset hpd state */ 1813c6f73aabSFrançois Tigeot radeon_hpd_init(rdev); 1814c6f73aabSFrançois Tigeot 1815591d5043SFrançois Tigeot ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); 1816591d5043SFrançois Tigeot 1817591d5043SFrançois Tigeot rdev->in_reset = true; 1818591d5043SFrançois Tigeot rdev->needs_reset = false; 1819591d5043SFrançois Tigeot 1820591d5043SFrançois Tigeot #if 0 1821591d5043SFrançois Tigeot downgrade_write(&rdev->exclusive_lock); 1822591d5043SFrançois Tigeot #endif 1823591d5043SFrançois Tigeot 1824926deccbSFrançois Tigeot drm_helper_resume_force_mode(rdev->ddev); 1825926deccbSFrançois Tigeot 1826c6f73aabSFrançois Tigeot /* set the power state here in case we are a PX system or headless */ 1827c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 1828c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1829c6f73aabSFrançois Tigeot 1830591d5043SFrançois Tigeot if (!r) { 1831591d5043SFrançois Tigeot r = radeon_ib_ring_tests(rdev); 1832591d5043SFrançois Tigeot if (r && saved) 1833591d5043SFrançois Tigeot r = -EAGAIN; 1834591d5043SFrançois Tigeot } else { 1835926deccbSFrançois Tigeot /* bad news, how to tell it to userspace ? */ 1836926deccbSFrançois Tigeot dev_info(rdev->dev, "GPU reset failed\n"); 1837926deccbSFrançois Tigeot } 1838926deccbSFrançois Tigeot 1839591d5043SFrançois Tigeot rdev->needs_reset = r == -EAGAIN; 1840591d5043SFrançois Tigeot rdev->in_reset = false; 1841591d5043SFrançois Tigeot 1842926deccbSFrançois Tigeot lockmgr(&rdev->exclusive_lock, LK_RELEASE); 1843926deccbSFrançois Tigeot return r; 1844926deccbSFrançois Tigeot } 1845926deccbSFrançois Tigeot 1846926deccbSFrançois Tigeot 1847926deccbSFrançois Tigeot /* 1848926deccbSFrançois Tigeot * Debugfs 1849926deccbSFrançois Tigeot */ 1850926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1851926deccbSFrançois Tigeot int radeon_debugfs_add_files(struct radeon_device *rdev, 1852926deccbSFrançois Tigeot struct drm_info_list *files, 1853926deccbSFrançois Tigeot unsigned nfiles) 1854926deccbSFrançois Tigeot { 1855926deccbSFrançois Tigeot unsigned i; 1856926deccbSFrançois Tigeot 1857926deccbSFrançois Tigeot for (i = 0; i < rdev->debugfs_count; i++) { 1858926deccbSFrançois Tigeot if (rdev->debugfs[i].files == files) { 1859926deccbSFrançois Tigeot /* Already registered */ 1860926deccbSFrançois Tigeot return 0; 1861926deccbSFrançois Tigeot } 1862926deccbSFrançois Tigeot } 1863926deccbSFrançois Tigeot 1864926deccbSFrançois Tigeot i = rdev->debugfs_count + 1; 1865926deccbSFrançois Tigeot if (i > RADEON_DEBUGFS_MAX_COMPONENTS) { 1866926deccbSFrançois Tigeot DRM_ERROR("Reached maximum number of debugfs components.\n"); 1867926deccbSFrançois Tigeot DRM_ERROR("Report so we increase " 1868926deccbSFrançois Tigeot "RADEON_DEBUGFS_MAX_COMPONENTS.\n"); 1869926deccbSFrançois Tigeot return -EINVAL; 1870926deccbSFrançois Tigeot } 1871926deccbSFrançois Tigeot rdev->debugfs[rdev->debugfs_count].files = files; 1872926deccbSFrançois Tigeot rdev->debugfs[rdev->debugfs_count].num_files = nfiles; 1873926deccbSFrançois Tigeot rdev->debugfs_count = i; 1874926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1875926deccbSFrançois Tigeot drm_debugfs_create_files(files, nfiles, 1876926deccbSFrançois Tigeot rdev->ddev->control->debugfs_root, 1877926deccbSFrançois Tigeot rdev->ddev->control); 1878926deccbSFrançois Tigeot drm_debugfs_create_files(files, nfiles, 1879926deccbSFrançois Tigeot rdev->ddev->primary->debugfs_root, 1880926deccbSFrançois Tigeot rdev->ddev->primary); 1881926deccbSFrançois Tigeot #endif 1882926deccbSFrançois Tigeot return 0; 1883926deccbSFrançois Tigeot } 1884926deccbSFrançois Tigeot 1885926deccbSFrançois Tigeot static void radeon_debugfs_remove_files(struct radeon_device *rdev) 1886926deccbSFrançois Tigeot { 1887926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1888926deccbSFrançois Tigeot unsigned i; 1889926deccbSFrançois Tigeot 1890926deccbSFrançois Tigeot for (i = 0; i < rdev->debugfs_count; i++) { 1891926deccbSFrançois Tigeot drm_debugfs_remove_files(rdev->debugfs[i].files, 1892926deccbSFrançois Tigeot rdev->debugfs[i].num_files, 1893926deccbSFrançois Tigeot rdev->ddev->control); 1894926deccbSFrançois Tigeot drm_debugfs_remove_files(rdev->debugfs[i].files, 1895926deccbSFrançois Tigeot rdev->debugfs[i].num_files, 1896926deccbSFrançois Tigeot rdev->ddev->primary); 1897926deccbSFrançois Tigeot } 1898926deccbSFrançois Tigeot #endif 1899926deccbSFrançois Tigeot } 1900926deccbSFrançois Tigeot 1901926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1902926deccbSFrançois Tigeot int radeon_debugfs_init(struct drm_minor *minor) 1903926deccbSFrançois Tigeot { 1904926deccbSFrançois Tigeot return 0; 1905926deccbSFrançois Tigeot } 1906926deccbSFrançois Tigeot 1907926deccbSFrançois Tigeot void radeon_debugfs_cleanup(struct drm_minor *minor) 1908926deccbSFrançois Tigeot { 1909926deccbSFrançois Tigeot } 1910926deccbSFrançois Tigeot #endif 1911b6771645Szrj #endif /* DUMBBELL_WIP */ 1912