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 } 1270*1cfef1a5SFrançois Tigeot rdev->fence_context = fence_context_alloc(RADEON_NUM_RINGS); 1271926deccbSFrançois Tigeot 1272ee479021SImre Vadász DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", 1273c6f73aabSFrançois Tigeot radeon_family_name[rdev->family], pdev->vendor, pdev->device, 1274ee479021SImre Vadász pdev->subsystem_vendor, pdev->subsystem_device); 1275926deccbSFrançois Tigeot 1276926deccbSFrançois Tigeot /* mutex initialization are all done here so we 1277926deccbSFrançois Tigeot * can recall function without having locking issues */ 12781ca17f9bSFrançois Tigeot lockinit(&rdev->ring_lock, "drdrl", 0, LK_CANRECURSE); 12791ca17f9bSFrançois Tigeot lockinit(&rdev->dc_hw_i2c_mutex, "drddi2cm", 0, LK_CANRECURSE); 1280926deccbSFrançois Tigeot atomic_set(&rdev->ih.lock, 0); 1281fefad7a7SFrançois Tigeot lockinit(&rdev->gem.mutex, "radeon_gemmtx", 0, LK_CANRECURSE); 12821ca17f9bSFrançois Tigeot lockinit(&rdev->pm.mutex, "drdpmm", 0, LK_CANRECURSE); 1283fefad7a7SFrançois Tigeot 1284fefad7a7SFrançois Tigeot lockinit(&rdev->gpu_clock_mutex, "radeon_clockmtx", 0, LK_CANRECURSE); 1285fefad7a7SFrançois Tigeot lockinit(&rdev->srbm_mutex, "radeon_srbm_mutex", 0, LK_CANRECURSE); 12861ca17f9bSFrançois Tigeot lockinit(&rdev->pm.mclk_lock, "drpmml", 0, LK_CANRECURSE); 12871ca17f9bSFrançois Tigeot lockinit(&rdev->exclusive_lock, "drdel", 0, LK_CANRECURSE); 1288c6f73aabSFrançois Tigeot init_waitqueue_head(&rdev->irq.vblank_queue); 1289*1cfef1a5SFrançois Tigeot lockinit(&rdev->mn_lock, "drrml", 0, LK_CANRECURSE); 1290*1cfef1a5SFrançois Tigeot hash_init(rdev->mn_hash); 1291926deccbSFrançois Tigeot r = radeon_gem_init(rdev); 1292926deccbSFrançois Tigeot if (r) 1293926deccbSFrançois Tigeot return r; 1294c6f73aabSFrançois Tigeot 1295c6f73aabSFrançois Tigeot radeon_check_arguments(rdev); 1296926deccbSFrançois Tigeot /* Adjust VM size here. 1297c6f73aabSFrançois Tigeot * Max GPUVM size for cayman+ is 40 bits. 1298926deccbSFrançois Tigeot */ 1299c6f73aabSFrançois Tigeot rdev->vm_manager.max_pfn = radeon_vm_size << 18; 1300926deccbSFrançois Tigeot 1301926deccbSFrançois Tigeot /* Set asic functions */ 1302926deccbSFrançois Tigeot r = radeon_asic_init(rdev); 1303926deccbSFrançois Tigeot if (r) 1304926deccbSFrançois Tigeot return r; 1305926deccbSFrançois Tigeot 1306926deccbSFrançois Tigeot /* all of the newer IGP chips have an internal gart 1307926deccbSFrançois Tigeot * However some rs4xx report as AGP, so remove that here. 1308926deccbSFrançois Tigeot */ 1309926deccbSFrançois Tigeot if ((rdev->family >= CHIP_RS400) && 1310926deccbSFrançois Tigeot (rdev->flags & RADEON_IS_IGP)) { 1311926deccbSFrançois Tigeot rdev->flags &= ~RADEON_IS_AGP; 1312926deccbSFrançois Tigeot } 1313926deccbSFrançois Tigeot 1314926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) { 1315926deccbSFrançois Tigeot radeon_agp_disable(rdev); 1316926deccbSFrançois Tigeot } 1317926deccbSFrançois Tigeot 1318f43cf1b1SMichael Neumann /* Set the internal MC address mask 1319f43cf1b1SMichael Neumann * This is the max address of the GPU's 1320f43cf1b1SMichael Neumann * internal address space. 1321f43cf1b1SMichael Neumann */ 1322f43cf1b1SMichael Neumann if (rdev->family >= CHIP_CAYMAN) 1323f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xffffffffffULL; /* 40 bit MC */ 1324f43cf1b1SMichael Neumann else if (rdev->family >= CHIP_CEDAR) 1325f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xfffffffffULL; /* 36 bit MC */ 1326f43cf1b1SMichael Neumann else 1327f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xffffffffULL; /* 32 bit MC */ 1328f43cf1b1SMichael Neumann 1329926deccbSFrançois Tigeot /* set DMA mask + need_dma32 flags. 1330926deccbSFrançois Tigeot * PCIE - can handle 40-bits. 1331926deccbSFrançois Tigeot * IGP - can handle 40-bits 1332926deccbSFrançois Tigeot * AGP - generally dma32 is safest 1333926deccbSFrançois Tigeot * PCI - dma32 for legacy pci gart, 40 bits on newer asics 1334926deccbSFrançois Tigeot */ 1335926deccbSFrançois Tigeot rdev->need_dma32 = false; 1336926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP) 1337926deccbSFrançois Tigeot rdev->need_dma32 = true; 1338926deccbSFrançois Tigeot if ((rdev->flags & RADEON_IS_PCI) && 1339926deccbSFrançois Tigeot (rdev->family <= CHIP_RS740)) 1340926deccbSFrançois Tigeot rdev->need_dma32 = true; 1341926deccbSFrançois Tigeot 1342926deccbSFrançois Tigeot dma_bits = rdev->need_dma32 ? 32 : 40; 1343926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1344926deccbSFrançois Tigeot r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); 1345926deccbSFrançois Tigeot if (r) { 1346926deccbSFrançois Tigeot rdev->need_dma32 = true; 1347926deccbSFrançois Tigeot dma_bits = 32; 1348926deccbSFrançois Tigeot printk(KERN_WARNING "radeon: No suitable DMA available.\n"); 1349926deccbSFrançois Tigeot } 1350926deccbSFrançois Tigeot r = pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); 1351926deccbSFrançois Tigeot if (r) { 1352926deccbSFrançois Tigeot pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(32)); 1353926deccbSFrançois Tigeot printk(KERN_WARNING "radeon: No coherent DMA available.\n"); 1354926deccbSFrançois Tigeot } 1355926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1356926deccbSFrançois Tigeot 1357926deccbSFrançois Tigeot /* Registers mapping */ 1358926deccbSFrançois Tigeot /* TODO: block userspace mapping of io register */ 1359ee479021SImre Vadász spin_init(&rdev->mmio_idx_lock, "radeon_mpio"); 1360ee479021SImre Vadász spin_init(&rdev->smc_idx_lock, "radeon_smc"); 1361ee479021SImre Vadász spin_init(&rdev->pll_idx_lock, "radeon_pll"); 1362ee479021SImre Vadász spin_init(&rdev->mc_idx_lock, "radeon_mc"); 1363ee479021SImre Vadász spin_init(&rdev->pcie_idx_lock, "radeon_pcie"); 1364ee479021SImre Vadász spin_init(&rdev->pciep_idx_lock, "radeon_pciep"); 1365ee479021SImre Vadász spin_init(&rdev->pif_idx_lock, "radeon_pif"); 1366ee479021SImre Vadász spin_init(&rdev->cg_idx_lock, "radeon_cg"); 1367ee479021SImre Vadász spin_init(&rdev->uvd_idx_lock, "radeon_uvd"); 1368ee479021SImre Vadász spin_init(&rdev->rcu_idx_lock, "radeon_rcu"); 1369ee479021SImre Vadász spin_init(&rdev->didt_idx_lock, "radeon_didt"); 1370ee479021SImre Vadász spin_init(&rdev->end_idx_lock, "radeon_end"); 137157e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) { 137257e252bfSMichael Neumann rdev->rmmio_rid = PCIR_BAR(5); 137357e252bfSMichael Neumann } else { 1374926deccbSFrançois Tigeot rdev->rmmio_rid = PCIR_BAR(2); 137557e252bfSMichael Neumann } 1376fb572d17SFrançois Tigeot rdev->rmmio = bus_alloc_resource_any(rdev->dev->bsddev, SYS_RES_MEMORY, 1377926deccbSFrançois Tigeot &rdev->rmmio_rid, RF_ACTIVE | RF_SHAREABLE); 1378926deccbSFrançois Tigeot if (rdev->rmmio == NULL) { 1379926deccbSFrançois Tigeot return -ENOMEM; 1380926deccbSFrançois Tigeot } 1381926deccbSFrançois Tigeot rdev->rmmio_base = rman_get_start(rdev->rmmio); 1382926deccbSFrançois Tigeot rdev->rmmio_size = rman_get_size(rdev->rmmio); 1383926deccbSFrançois Tigeot DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base); 1384926deccbSFrançois Tigeot DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size); 1385926deccbSFrançois Tigeot 138657e252bfSMichael Neumann /* doorbell bar mapping */ 138757e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) 138857e252bfSMichael Neumann radeon_doorbell_init(rdev); 138957e252bfSMichael Neumann 1390926deccbSFrançois Tigeot /* io port mapping */ 1391926deccbSFrançois Tigeot for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) { 1392926deccbSFrançois Tigeot uint32_t data; 1393926deccbSFrançois Tigeot 1394fb572d17SFrançois Tigeot data = pci_read_config(rdev->dev->bsddev, PCIR_BAR(i), 4); 1395926deccbSFrançois Tigeot if (PCI_BAR_IO(data)) { 1396926deccbSFrançois Tigeot rdev->rio_rid = PCIR_BAR(i); 1397fb572d17SFrançois Tigeot rdev->rio_mem = bus_alloc_resource_any(rdev->dev->bsddev, 1398926deccbSFrançois Tigeot SYS_RES_IOPORT, &rdev->rio_rid, 1399926deccbSFrançois Tigeot RF_ACTIVE | RF_SHAREABLE); 1400926deccbSFrançois Tigeot break; 1401926deccbSFrançois Tigeot } 1402926deccbSFrançois Tigeot } 1403926deccbSFrançois Tigeot if (rdev->rio_mem == NULL) 1404926deccbSFrançois Tigeot DRM_ERROR("Unable to find PCI I/O BAR\n"); 1405926deccbSFrançois Tigeot 1406c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 1407c6f73aabSFrançois Tigeot radeon_device_handle_px_quirks(rdev); 1408c6f73aabSFrançois Tigeot 1409926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1410926deccbSFrançois Tigeot /* if we have > 1 VGA cards, then disable the radeon VGA resources */ 1411926deccbSFrançois Tigeot /* this will fail for cards that aren't VGA class devices, just 1412926deccbSFrançois Tigeot * ignore it */ 1413926deccbSFrançois Tigeot vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); 1414c6f73aabSFrançois Tigeot 1415c6f73aabSFrançois Tigeot #ifdef PM_TODO 1416c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 1417c6f73aabSFrançois Tigeot runtime = true; 1418c6f73aabSFrançois Tigeot vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime); 1419c6f73aabSFrançois Tigeot if (runtime) 1420fb572d17SFrançois Tigeot vga_switcheroo_init_domain_pm_ops(rdev->dev->bsddev, &rdev->vga_pm_domain); 1421c6f73aabSFrançois Tigeot #endif 1422926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1423926deccbSFrançois Tigeot 1424926deccbSFrançois Tigeot r = radeon_init(rdev); 1425926deccbSFrançois Tigeot if (r) 1426c6f73aabSFrançois Tigeot goto failed; 1427926deccbSFrançois Tigeot 1428f43cf1b1SMichael Neumann r = radeon_gem_debugfs_init(rdev); 1429f43cf1b1SMichael Neumann if (r) { 1430f43cf1b1SMichael Neumann DRM_ERROR("registering gem debugfs failed (%d).\n", r); 1431f43cf1b1SMichael Neumann } 1432f43cf1b1SMichael Neumann 1433926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) { 1434926deccbSFrançois Tigeot /* Acceleration not working on AGP card try again 1435926deccbSFrançois Tigeot * with fallback to PCI or PCIE GART 1436926deccbSFrançois Tigeot */ 1437926deccbSFrançois Tigeot radeon_asic_reset(rdev); 1438926deccbSFrançois Tigeot radeon_fini(rdev); 1439926deccbSFrançois Tigeot radeon_agp_disable(rdev); 1440926deccbSFrançois Tigeot r = radeon_init(rdev); 1441926deccbSFrançois Tigeot if (r) 1442c6f73aabSFrançois Tigeot goto failed; 1443926deccbSFrançois Tigeot } 1444926deccbSFrançois Tigeot 1445591d5043SFrançois Tigeot r = radeon_ib_ring_tests(rdev); 1446591d5043SFrançois Tigeot if (r) 1447591d5043SFrançois Tigeot DRM_ERROR("ib ring test failed (%d).\n", r); 1448591d5043SFrançois Tigeot 1449f77dbd6cSFrançois Tigeot DRM_INFO("%s: Taking over the fictitious range 0x%lx-0x%llx\n", 1450926deccbSFrançois Tigeot __func__, (uintmax_t)rdev->mc.aper_base, 1451926deccbSFrançois Tigeot (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size); 1452926deccbSFrançois Tigeot r = vm_phys_fictitious_reg_range( 1453926deccbSFrançois Tigeot rdev->mc.aper_base, 1454926deccbSFrançois Tigeot rdev->mc.aper_base + rdev->mc.visible_vram_size, 1455926deccbSFrançois Tigeot VM_MEMATTR_WRITE_COMBINING); 1456926deccbSFrançois Tigeot if (r != 0) { 1457926deccbSFrançois Tigeot DRM_ERROR("Failed to register fictitious range " 1458f77dbd6cSFrançois Tigeot "0x%lx-0x%llx (%d).\n", (uintmax_t)rdev->mc.aper_base, 1459926deccbSFrançois Tigeot (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size, r); 1460926deccbSFrançois Tigeot return (-r); 1461926deccbSFrançois Tigeot } 1462926deccbSFrançois Tigeot rdev->fictitious_range_registered = true; 1463926deccbSFrançois Tigeot 1464926deccbSFrançois Tigeot if ((radeon_testing & 1)) { 14654cd92098Szrj if (rdev->accel_working) 1466926deccbSFrançois Tigeot radeon_test_moves(rdev); 14674cd92098Szrj else 14684cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping move tests\n"); 1469926deccbSFrançois Tigeot } 1470926deccbSFrançois Tigeot if ((radeon_testing & 2)) { 14714cd92098Szrj if (rdev->accel_working) 1472926deccbSFrançois Tigeot radeon_test_syncing(rdev); 14734cd92098Szrj else 14744cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping sync tests\n"); 1475926deccbSFrançois Tigeot } 1476926deccbSFrançois Tigeot if (radeon_benchmarking) { 14774cd92098Szrj if (rdev->accel_working) 1478926deccbSFrançois Tigeot radeon_benchmark(rdev, radeon_benchmarking); 14794cd92098Szrj else 14804cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n"); 1481926deccbSFrançois Tigeot } 1482926deccbSFrançois Tigeot return 0; 1483c6f73aabSFrançois Tigeot 1484c6f73aabSFrançois Tigeot failed: 1485c6f73aabSFrançois Tigeot #ifdef DRM_BDSM 1486c6f73aabSFrançois Tigeot if (runtime) 1487c6f73aabSFrançois Tigeot vga_switcheroo_fini_domain_pm_ops(rdev->dev); 1488c6f73aabSFrançois Tigeot #endif 1489c6f73aabSFrançois Tigeot return r; 1490926deccbSFrançois Tigeot } 1491926deccbSFrançois Tigeot 1492926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1493926deccbSFrançois Tigeot static void radeon_debugfs_remove_files(struct radeon_device *rdev); 1494926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1495926deccbSFrançois Tigeot 1496926deccbSFrançois Tigeot /** 1497926deccbSFrançois Tigeot * radeon_device_fini - tear down the driver 1498926deccbSFrançois Tigeot * 1499926deccbSFrançois Tigeot * @rdev: radeon_device pointer 1500926deccbSFrançois Tigeot * 1501926deccbSFrançois Tigeot * Tear down the driver info (all asics). 1502926deccbSFrançois Tigeot * Called at driver shutdown. 1503926deccbSFrançois Tigeot */ 1504926deccbSFrançois Tigeot void radeon_device_fini(struct radeon_device *rdev) 1505926deccbSFrançois Tigeot { 1506926deccbSFrançois Tigeot DRM_INFO("radeon: finishing device.\n"); 1507926deccbSFrançois Tigeot rdev->shutdown = true; 1508926deccbSFrançois Tigeot /* evict vram memory */ 1509926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev); 1510926deccbSFrançois Tigeot 1511926deccbSFrançois Tigeot if (rdev->fictitious_range_registered) { 1512926deccbSFrançois Tigeot vm_phys_fictitious_unreg_range( 1513926deccbSFrançois Tigeot rdev->mc.aper_base, 1514926deccbSFrançois Tigeot rdev->mc.aper_base + rdev->mc.visible_vram_size); 1515926deccbSFrançois Tigeot } 1516926deccbSFrançois Tigeot 1517926deccbSFrançois Tigeot radeon_fini(rdev); 1518926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1519926deccbSFrançois Tigeot vga_switcheroo_unregister_client(rdev->pdev); 1520c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 1521c6f73aabSFrançois Tigeot vga_switcheroo_fini_domain_pm_ops(rdev->dev); 1522926deccbSFrançois Tigeot vga_client_register(rdev->pdev, NULL, NULL, NULL); 1523926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1524926deccbSFrançois Tigeot 1525926deccbSFrançois Tigeot if (rdev->rio_mem) 1526fb572d17SFrançois Tigeot bus_release_resource(rdev->dev->bsddev, SYS_RES_IOPORT, rdev->rio_rid, 1527926deccbSFrançois Tigeot rdev->rio_mem); 1528926deccbSFrançois Tigeot rdev->rio_mem = NULL; 1529fb572d17SFrançois Tigeot bus_release_resource(rdev->dev->bsddev, SYS_RES_MEMORY, rdev->rmmio_rid, 1530926deccbSFrançois Tigeot rdev->rmmio); 1531926deccbSFrançois Tigeot rdev->rmmio = NULL; 153257e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) 153357e252bfSMichael Neumann radeon_doorbell_fini(rdev); 1534926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1535926deccbSFrançois Tigeot radeon_debugfs_remove_files(rdev); 1536926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1537926deccbSFrançois Tigeot } 1538926deccbSFrançois Tigeot 1539926deccbSFrançois Tigeot 1540926deccbSFrançois Tigeot /* 1541926deccbSFrançois Tigeot * Suspend & resume. 1542926deccbSFrançois Tigeot */ 1543926deccbSFrançois Tigeot /** 1544926deccbSFrançois Tigeot * radeon_suspend_kms - initiate device suspend 1545926deccbSFrançois Tigeot * 1546926deccbSFrançois Tigeot * @pdev: drm dev pointer 1547926deccbSFrançois Tigeot * @state: suspend state 1548926deccbSFrançois Tigeot * 1549926deccbSFrançois Tigeot * Puts the hw in the suspend state (all asics). 1550926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1551926deccbSFrançois Tigeot * Called at driver suspend. 1552926deccbSFrançois Tigeot */ 1553ee479021SImre Vadász int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) 1554926deccbSFrançois Tigeot { 1555926deccbSFrançois Tigeot struct radeon_device *rdev; 1556926deccbSFrançois Tigeot struct drm_crtc *crtc; 1557926deccbSFrançois Tigeot struct drm_connector *connector; 1558926deccbSFrançois Tigeot int i, r; 1559926deccbSFrançois Tigeot 1560926deccbSFrançois Tigeot if (dev == NULL || dev->dev_private == NULL) { 1561926deccbSFrançois Tigeot return -ENODEV; 1562926deccbSFrançois Tigeot } 1563c6f73aabSFrançois Tigeot 1564926deccbSFrançois Tigeot rdev = dev->dev_private; 1565926deccbSFrançois Tigeot 1566926deccbSFrançois Tigeot if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 1567926deccbSFrançois Tigeot return 0; 1568926deccbSFrançois Tigeot 1569926deccbSFrançois Tigeot drm_kms_helper_poll_disable(dev); 1570926deccbSFrançois Tigeot 1571926deccbSFrançois Tigeot /* turn off display hw */ 1572926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1573926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); 1574926deccbSFrançois Tigeot } 1575926deccbSFrançois Tigeot 1576ee479021SImre Vadász /* unpin the front buffers */ 1577926deccbSFrançois Tigeot list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 1578ba55f2f5SFrançois Tigeot struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb); 1579926deccbSFrançois Tigeot struct radeon_bo *robj; 1580926deccbSFrançois Tigeot 1581926deccbSFrançois Tigeot if (rfb == NULL || rfb->obj == NULL) { 1582926deccbSFrançois Tigeot continue; 1583926deccbSFrançois Tigeot } 1584926deccbSFrançois Tigeot robj = gem_to_radeon_bo(rfb->obj); 1585926deccbSFrançois Tigeot /* don't unpin kernel fb objects */ 1586926deccbSFrançois Tigeot if (!radeon_fbdev_robj_is_fb(rdev, robj)) { 1587926deccbSFrançois Tigeot r = radeon_bo_reserve(robj, false); 1588926deccbSFrançois Tigeot if (r == 0) { 1589926deccbSFrançois Tigeot radeon_bo_unpin(robj); 1590926deccbSFrançois Tigeot radeon_bo_unreserve(robj); 1591926deccbSFrançois Tigeot } 1592926deccbSFrançois Tigeot } 1593926deccbSFrançois Tigeot } 1594926deccbSFrançois Tigeot /* evict vram memory */ 1595926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev); 1596926deccbSFrançois Tigeot 1597926deccbSFrançois Tigeot /* wait for gpu to finish processing current batch */ 1598926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) { 1599c6f73aabSFrançois Tigeot r = radeon_fence_wait_empty(rdev, i); 1600926deccbSFrançois Tigeot if (r) { 1601926deccbSFrançois Tigeot /* delay GPU reset to resume */ 1602c6f73aabSFrançois Tigeot radeon_fence_driver_force_completion(rdev, i); 1603926deccbSFrançois Tigeot } 1604926deccbSFrançois Tigeot } 1605926deccbSFrançois Tigeot 1606926deccbSFrançois Tigeot radeon_save_bios_scratch_regs(rdev); 1607926deccbSFrançois Tigeot 1608926deccbSFrançois Tigeot radeon_suspend(rdev); 1609926deccbSFrançois Tigeot radeon_hpd_fini(rdev); 1610926deccbSFrançois Tigeot /* evict remaining vram memory */ 1611926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev); 1612926deccbSFrançois Tigeot 1613926deccbSFrançois Tigeot radeon_agp_suspend(rdev); 1614926deccbSFrançois Tigeot 1615fb572d17SFrançois Tigeot pci_save_state(device_get_parent(rdev->dev->bsddev)); 1616926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1617ee479021SImre Vadász if (suspend) { 1618926deccbSFrançois Tigeot /* Shut down the device */ 1619926deccbSFrançois Tigeot pci_disable_device(dev->pdev); 1620926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1621fb572d17SFrançois Tigeot pci_set_powerstate(dev->dev->bsddev, PCI_POWERSTATE_D3); 1622926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1623926deccbSFrançois Tigeot } 1624c6f73aabSFrançois Tigeot #endif 1625c6f73aabSFrançois Tigeot if (fbcon) { 1626c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP 1627926deccbSFrançois Tigeot console_lock(); 1628926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1629926deccbSFrançois Tigeot radeon_fbdev_set_suspend(rdev, 1); 1630926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1631926deccbSFrançois Tigeot console_unlock(); 1632926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1633c6f73aabSFrançois Tigeot } 1634926deccbSFrançois Tigeot return 0; 1635926deccbSFrançois Tigeot } 1636926deccbSFrançois Tigeot 1637926deccbSFrançois Tigeot /** 1638926deccbSFrançois Tigeot * radeon_resume_kms - initiate device resume 1639926deccbSFrançois Tigeot * 1640926deccbSFrançois Tigeot * @pdev: drm dev pointer 1641926deccbSFrançois Tigeot * 1642926deccbSFrançois Tigeot * Bring the hw back to operating state (all asics). 1643926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1644926deccbSFrançois Tigeot * Called at driver resume. 1645926deccbSFrançois Tigeot */ 1646c6f73aabSFrançois Tigeot int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) 1647926deccbSFrançois Tigeot { 1648926deccbSFrançois Tigeot struct drm_connector *connector; 1649926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1650926deccbSFrançois Tigeot int r; 1651926deccbSFrançois Tigeot 1652926deccbSFrançois Tigeot if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 1653926deccbSFrançois Tigeot return 0; 1654926deccbSFrançois Tigeot 1655926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1656c6f73aabSFrançois Tigeot if (fbcon) { 1657926deccbSFrançois Tigeot console_lock(); 1658c6f73aabSFrançois Tigeot } 1659926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1660c6f73aabSFrançois Tigeot if (resume) { 1661fb572d17SFrançois Tigeot pci_set_powerstate(dev->dev->bsddev, PCI_POWERSTATE_D0); 1662fb572d17SFrançois Tigeot pci_restore_state(device_get_parent(rdev->dev->bsddev)); 1663926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1664926deccbSFrançois Tigeot if (pci_enable_device(dev->pdev)) { 1665c6f73aabSFrançois Tigeot if (fbcon) 1666926deccbSFrançois Tigeot console_unlock(); 1667926deccbSFrançois Tigeot return -1; 1668926deccbSFrançois Tigeot } 1669926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1670c6f73aabSFrançois Tigeot } 1671926deccbSFrançois Tigeot /* resume AGP if in use */ 1672926deccbSFrançois Tigeot radeon_agp_resume(rdev); 1673926deccbSFrançois Tigeot radeon_resume(rdev); 1674926deccbSFrançois Tigeot 1675926deccbSFrançois Tigeot r = radeon_ib_ring_tests(rdev); 1676926deccbSFrançois Tigeot if (r) 1677926deccbSFrançois Tigeot DRM_ERROR("ib ring test failed (%d).\n", r); 1678926deccbSFrançois Tigeot 1679c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 1680c6f73aabSFrançois Tigeot /* do dpm late init */ 1681c6f73aabSFrançois Tigeot r = radeon_pm_late_init(rdev); 1682c6f73aabSFrançois Tigeot if (r) { 1683c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = false; 1684c6f73aabSFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); 1685c6f73aabSFrançois Tigeot } 1686c6f73aabSFrançois Tigeot } else { 1687c6f73aabSFrançois Tigeot /* resume old pm late */ 1688926deccbSFrançois Tigeot radeon_pm_resume(rdev); 1689c6f73aabSFrançois Tigeot } 1690926deccbSFrançois Tigeot 1691c6f73aabSFrançois Tigeot radeon_restore_bios_scratch_regs(rdev); 1692926deccbSFrançois Tigeot 1693926deccbSFrançois Tigeot /* init dig PHYs, disp eng pll */ 1694926deccbSFrançois Tigeot if (rdev->is_atom_bios) { 1695926deccbSFrançois Tigeot radeon_atom_encoder_init(rdev); 1696926deccbSFrançois Tigeot radeon_atom_disp_eng_pll_init(rdev); 1697926deccbSFrançois Tigeot /* turn on the BL */ 1698926deccbSFrançois Tigeot if (rdev->mode_info.bl_encoder) { 1699926deccbSFrançois Tigeot u8 bl_level = radeon_get_backlight_level(rdev, 1700926deccbSFrançois Tigeot rdev->mode_info.bl_encoder); 1701926deccbSFrançois Tigeot radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, 1702926deccbSFrançois Tigeot bl_level); 1703926deccbSFrançois Tigeot } 1704926deccbSFrançois Tigeot } 1705926deccbSFrançois Tigeot /* reset hpd state */ 1706926deccbSFrançois Tigeot radeon_hpd_init(rdev); 1707926deccbSFrançois Tigeot /* blat the mode back in */ 1708c6f73aabSFrançois Tigeot if (fbcon) { 1709926deccbSFrançois Tigeot drm_helper_resume_force_mode(dev); 1710926deccbSFrançois Tigeot /* turn on display hw */ 1711926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1712926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); 1713926deccbSFrançois Tigeot } 1714c6f73aabSFrançois Tigeot } 1715926deccbSFrançois Tigeot 1716926deccbSFrançois Tigeot drm_kms_helper_poll_enable(dev); 1717c6f73aabSFrançois Tigeot 1718c6f73aabSFrançois Tigeot /* set the power state here in case we are a PX system or headless */ 1719c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 1720c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1721c6f73aabSFrançois Tigeot 1722c6f73aabSFrançois Tigeot if (fbcon) { 1723c6f73aabSFrançois Tigeot radeon_fbdev_set_suspend(rdev, 0); 1724c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP 1725c6f73aabSFrançois Tigeot console_unlock(); 1726c6f73aabSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1727c6f73aabSFrançois Tigeot } 1728c6f73aabSFrançois Tigeot 1729926deccbSFrançois Tigeot return 0; 1730926deccbSFrançois Tigeot } 1731926deccbSFrançois Tigeot 1732926deccbSFrançois Tigeot /** 1733926deccbSFrançois Tigeot * radeon_gpu_reset - reset the asic 1734926deccbSFrançois Tigeot * 1735926deccbSFrançois Tigeot * @rdev: radeon device pointer 1736926deccbSFrançois Tigeot * 1737926deccbSFrançois Tigeot * Attempt the reset the GPU if it has hung (all asics). 1738926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1739926deccbSFrançois Tigeot */ 1740926deccbSFrançois Tigeot int radeon_gpu_reset(struct radeon_device *rdev) 1741926deccbSFrançois Tigeot { 1742926deccbSFrançois Tigeot unsigned ring_sizes[RADEON_NUM_RINGS]; 1743926deccbSFrançois Tigeot uint32_t *ring_data[RADEON_NUM_RINGS]; 1744926deccbSFrançois Tigeot 1745926deccbSFrançois Tigeot bool saved = false; 1746926deccbSFrançois Tigeot 1747926deccbSFrançois Tigeot int i, r; 1748926deccbSFrançois Tigeot int resched; 1749926deccbSFrançois Tigeot 1750926deccbSFrançois Tigeot lockmgr(&rdev->exclusive_lock, LK_EXCLUSIVE); 1751c6f73aabSFrançois Tigeot 1752c6f73aabSFrançois Tigeot if (!rdev->needs_reset) { 1753c6f73aabSFrançois Tigeot lockmgr(&rdev->exclusive_lock, LK_RELEASE); 1754c6f73aabSFrançois Tigeot return 0; 1755c6f73aabSFrançois Tigeot } 1756c6f73aabSFrançois Tigeot 1757926deccbSFrançois Tigeot radeon_save_bios_scratch_regs(rdev); 1758926deccbSFrançois Tigeot /* block TTM */ 1759926deccbSFrançois Tigeot resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); 1760926deccbSFrançois Tigeot radeon_suspend(rdev); 1761c6f73aabSFrançois Tigeot radeon_hpd_fini(rdev); 1762926deccbSFrançois Tigeot 1763926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) { 1764926deccbSFrançois Tigeot ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i], 1765926deccbSFrançois Tigeot &ring_data[i]); 1766926deccbSFrançois Tigeot if (ring_sizes[i]) { 1767926deccbSFrançois Tigeot saved = true; 1768926deccbSFrançois Tigeot dev_info(rdev->dev, "Saved %d dwords of commands " 1769926deccbSFrançois Tigeot "on ring %d.\n", ring_sizes[i], i); 1770926deccbSFrançois Tigeot } 1771926deccbSFrançois Tigeot } 1772926deccbSFrançois Tigeot 1773926deccbSFrançois Tigeot r = radeon_asic_reset(rdev); 1774926deccbSFrançois Tigeot if (!r) { 1775926deccbSFrançois Tigeot dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n"); 1776926deccbSFrançois Tigeot radeon_resume(rdev); 1777926deccbSFrançois Tigeot } 1778926deccbSFrançois Tigeot 1779926deccbSFrançois Tigeot radeon_restore_bios_scratch_regs(rdev); 1780926deccbSFrançois Tigeot 1781926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) { 1782591d5043SFrançois Tigeot if (!r && ring_data[i]) { 1783926deccbSFrançois Tigeot radeon_ring_restore(rdev, &rdev->ring[i], 1784926deccbSFrançois Tigeot ring_sizes[i], ring_data[i]); 1785926deccbSFrançois Tigeot } else { 1786c6f73aabSFrançois Tigeot radeon_fence_driver_force_completion(rdev, i); 1787c4ef309bSzrj kfree(ring_data[i]); 1788926deccbSFrançois Tigeot } 1789926deccbSFrançois Tigeot } 1790926deccbSFrançois Tigeot 1791c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 1792c6f73aabSFrançois Tigeot /* do dpm late init */ 1793c6f73aabSFrançois Tigeot r = radeon_pm_late_init(rdev); 1794c6f73aabSFrançois Tigeot if (r) { 1795c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = false; 1796c6f73aabSFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); 1797c6f73aabSFrançois Tigeot } 1798c6f73aabSFrançois Tigeot } else { 1799c6f73aabSFrançois Tigeot /* resume old pm late */ 180057e252bfSMichael Neumann radeon_pm_resume(rdev); 1801c6f73aabSFrançois Tigeot } 1802c6f73aabSFrançois Tigeot 1803c6f73aabSFrançois Tigeot /* init dig PHYs, disp eng pll */ 1804c6f73aabSFrançois Tigeot if (rdev->is_atom_bios) { 1805c6f73aabSFrançois Tigeot radeon_atom_encoder_init(rdev); 1806c6f73aabSFrançois Tigeot radeon_atom_disp_eng_pll_init(rdev); 1807c6f73aabSFrançois Tigeot /* turn on the BL */ 1808c6f73aabSFrançois Tigeot if (rdev->mode_info.bl_encoder) { 1809c6f73aabSFrançois Tigeot u8 bl_level = radeon_get_backlight_level(rdev, 1810c6f73aabSFrançois Tigeot rdev->mode_info.bl_encoder); 1811c6f73aabSFrançois Tigeot radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, 1812c6f73aabSFrançois Tigeot bl_level); 1813c6f73aabSFrançois Tigeot } 1814c6f73aabSFrançois Tigeot } 1815c6f73aabSFrançois Tigeot /* reset hpd state */ 1816c6f73aabSFrançois Tigeot radeon_hpd_init(rdev); 1817c6f73aabSFrançois Tigeot 1818591d5043SFrançois Tigeot ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); 1819591d5043SFrançois Tigeot 1820591d5043SFrançois Tigeot rdev->in_reset = true; 1821591d5043SFrançois Tigeot rdev->needs_reset = false; 1822591d5043SFrançois Tigeot 1823591d5043SFrançois Tigeot #if 0 1824591d5043SFrançois Tigeot downgrade_write(&rdev->exclusive_lock); 1825591d5043SFrançois Tigeot #endif 1826591d5043SFrançois Tigeot 1827926deccbSFrançois Tigeot drm_helper_resume_force_mode(rdev->ddev); 1828926deccbSFrançois Tigeot 1829c6f73aabSFrançois Tigeot /* set the power state here in case we are a PX system or headless */ 1830c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 1831c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1832c6f73aabSFrançois Tigeot 1833591d5043SFrançois Tigeot if (!r) { 1834591d5043SFrançois Tigeot r = radeon_ib_ring_tests(rdev); 1835591d5043SFrançois Tigeot if (r && saved) 1836591d5043SFrançois Tigeot r = -EAGAIN; 1837591d5043SFrançois Tigeot } else { 1838926deccbSFrançois Tigeot /* bad news, how to tell it to userspace ? */ 1839926deccbSFrançois Tigeot dev_info(rdev->dev, "GPU reset failed\n"); 1840926deccbSFrançois Tigeot } 1841926deccbSFrançois Tigeot 1842591d5043SFrançois Tigeot rdev->needs_reset = r == -EAGAIN; 1843591d5043SFrançois Tigeot rdev->in_reset = false; 1844591d5043SFrançois Tigeot 1845926deccbSFrançois Tigeot lockmgr(&rdev->exclusive_lock, LK_RELEASE); 1846926deccbSFrançois Tigeot return r; 1847926deccbSFrançois Tigeot } 1848926deccbSFrançois Tigeot 1849926deccbSFrançois Tigeot 1850926deccbSFrançois Tigeot /* 1851926deccbSFrançois Tigeot * Debugfs 1852926deccbSFrançois Tigeot */ 1853926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1854926deccbSFrançois Tigeot int radeon_debugfs_add_files(struct radeon_device *rdev, 1855926deccbSFrançois Tigeot struct drm_info_list *files, 1856926deccbSFrançois Tigeot unsigned nfiles) 1857926deccbSFrançois Tigeot { 1858926deccbSFrançois Tigeot unsigned i; 1859926deccbSFrançois Tigeot 1860926deccbSFrançois Tigeot for (i = 0; i < rdev->debugfs_count; i++) { 1861926deccbSFrançois Tigeot if (rdev->debugfs[i].files == files) { 1862926deccbSFrançois Tigeot /* Already registered */ 1863926deccbSFrançois Tigeot return 0; 1864926deccbSFrançois Tigeot } 1865926deccbSFrançois Tigeot } 1866926deccbSFrançois Tigeot 1867926deccbSFrançois Tigeot i = rdev->debugfs_count + 1; 1868926deccbSFrançois Tigeot if (i > RADEON_DEBUGFS_MAX_COMPONENTS) { 1869926deccbSFrançois Tigeot DRM_ERROR("Reached maximum number of debugfs components.\n"); 1870926deccbSFrançois Tigeot DRM_ERROR("Report so we increase " 1871926deccbSFrançois Tigeot "RADEON_DEBUGFS_MAX_COMPONENTS.\n"); 1872926deccbSFrançois Tigeot return -EINVAL; 1873926deccbSFrançois Tigeot } 1874926deccbSFrançois Tigeot rdev->debugfs[rdev->debugfs_count].files = files; 1875926deccbSFrançois Tigeot rdev->debugfs[rdev->debugfs_count].num_files = nfiles; 1876926deccbSFrançois Tigeot rdev->debugfs_count = i; 1877926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1878926deccbSFrançois Tigeot drm_debugfs_create_files(files, nfiles, 1879926deccbSFrançois Tigeot rdev->ddev->control->debugfs_root, 1880926deccbSFrançois Tigeot rdev->ddev->control); 1881926deccbSFrançois Tigeot drm_debugfs_create_files(files, nfiles, 1882926deccbSFrançois Tigeot rdev->ddev->primary->debugfs_root, 1883926deccbSFrançois Tigeot rdev->ddev->primary); 1884926deccbSFrançois Tigeot #endif 1885926deccbSFrançois Tigeot return 0; 1886926deccbSFrançois Tigeot } 1887926deccbSFrançois Tigeot 1888926deccbSFrançois Tigeot static void radeon_debugfs_remove_files(struct radeon_device *rdev) 1889926deccbSFrançois Tigeot { 1890926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1891926deccbSFrançois Tigeot unsigned i; 1892926deccbSFrançois Tigeot 1893926deccbSFrançois Tigeot for (i = 0; i < rdev->debugfs_count; i++) { 1894926deccbSFrançois Tigeot drm_debugfs_remove_files(rdev->debugfs[i].files, 1895926deccbSFrançois Tigeot rdev->debugfs[i].num_files, 1896926deccbSFrançois Tigeot rdev->ddev->control); 1897926deccbSFrançois Tigeot drm_debugfs_remove_files(rdev->debugfs[i].files, 1898926deccbSFrançois Tigeot rdev->debugfs[i].num_files, 1899926deccbSFrançois Tigeot rdev->ddev->primary); 1900926deccbSFrançois Tigeot } 1901926deccbSFrançois Tigeot #endif 1902926deccbSFrançois Tigeot } 1903926deccbSFrançois Tigeot 1904926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1905926deccbSFrançois Tigeot int radeon_debugfs_init(struct drm_minor *minor) 1906926deccbSFrançois Tigeot { 1907926deccbSFrançois Tigeot return 0; 1908926deccbSFrançois Tigeot } 1909926deccbSFrançois Tigeot 1910926deccbSFrançois Tigeot void radeon_debugfs_cleanup(struct drm_minor *minor) 1911926deccbSFrançois Tigeot { 1912926deccbSFrançois Tigeot } 1913926deccbSFrançois Tigeot #endif 1914b6771645Szrj #endif /* DUMBBELL_WIP */ 1915