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> 33926deccbSFrançois Tigeot #include <uapi_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, 449926deccbSFrançois Tigeot &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 } 464926deccbSFrançois Tigeot /* clear wb memory */ 465926deccbSFrançois Tigeot 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; 559926deccbSFrançois Tigeot dev_info(rdev->dev, "VRAM: %juM 0x%016jX - 0x%016jX (%juM 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; 596926deccbSFrançois Tigeot dev_info(rdev->dev, "GTT: %juM 0x%016jX - 0x%016jX\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) { 9705d6a9071Szrj /* prevents leaking 512 bytes */ 9715d6a9071Szrj kfree(rdev->mode_info.atom_context->iio); 9725d6a9071Szrj 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) { 10694cd92098Szrj /* default to a larger gart size on newer asics */ 10704cd92098Szrj if (rdev->family >= CHIP_RV770) 10714cd92098Szrj radeon_gart_size = 1024; 10724cd92098Szrj else 10734cd92098Szrj 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); 10794cd92098Szrj if (rdev->family >= CHIP_RV770) 10804cd92098Szrj radeon_gart_size = 1024; 10814cd92098Szrj else 1082926deccbSFrançois Tigeot 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); 10864cd92098Szrj if (rdev->family >= CHIP_RV770) 10874cd92098Szrj radeon_gart_size = 1024; 10884cd92098Szrj else 1089926deccbSFrançois Tigeot 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) { 1116c6f73aabSFrançois Tigeot 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 1163926deccbSFrançois Tigeot * @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; 1197c6f73aabSFrançois Tigeot radeon_suspend_kms(dev, true, true); 1198926deccbSFrançois Tigeot dev->switch_power_state = DRM_SWITCH_POWER_OFF; 1199926deccbSFrançois Tigeot } 1200926deccbSFrançois Tigeot } 1201926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1202926deccbSFrançois Tigeot 1203926deccbSFrançois Tigeot /** 1204926deccbSFrançois Tigeot * radeon_switcheroo_can_switch - see if switcheroo state can change 1205926deccbSFrançois Tigeot * 1206926deccbSFrançois Tigeot * @pdev: pci dev pointer 1207926deccbSFrançois Tigeot * 1208926deccbSFrançois Tigeot * Callback for the switcheroo driver. Check of the switcheroo 1209926deccbSFrançois Tigeot * state can be changed. 1210926deccbSFrançois Tigeot * Returns true if the state can be changed, false if not. 1211926deccbSFrançois Tigeot */ 1212926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1213926deccbSFrançois Tigeot static bool radeon_switcheroo_can_switch(struct pci_dev *pdev) 1214926deccbSFrançois Tigeot { 1215926deccbSFrançois Tigeot struct drm_device *dev = pci_get_drvdata(pdev); 1216926deccbSFrançois Tigeot 1217c6f73aabSFrançois Tigeot /* 1218c6f73aabSFrançois Tigeot * FIXME: open_count is protected by drm_global_mutex but that would lead to 1219c6f73aabSFrançois Tigeot * locking inversion with the driver load path. And the access here is 1220c6f73aabSFrançois Tigeot * completely racy anyway. So don't bother with locking for now. 1221c6f73aabSFrançois Tigeot */ 1222c6f73aabSFrançois Tigeot return dev->open_count == 0; 1223926deccbSFrançois Tigeot } 1224926deccbSFrançois Tigeot 1225926deccbSFrançois Tigeot static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { 1226926deccbSFrançois Tigeot .set_gpu_state = radeon_switcheroo_set_state, 1227926deccbSFrançois Tigeot .reprobe = NULL, 1228926deccbSFrançois Tigeot .can_switch = radeon_switcheroo_can_switch, 1229926deccbSFrançois Tigeot }; 1230926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1231926deccbSFrançois Tigeot 1232926deccbSFrançois Tigeot /** 1233926deccbSFrançois Tigeot * radeon_device_init - initialize the driver 1234926deccbSFrançois Tigeot * 1235926deccbSFrançois Tigeot * @rdev: radeon_device pointer 1236926deccbSFrançois Tigeot * @pdev: drm dev pointer 1237c6f73aabSFrançois Tigeot * @pdev: pci dev pointer 1238926deccbSFrançois Tigeot * @flags: driver flags 1239926deccbSFrançois Tigeot * 1240926deccbSFrançois Tigeot * Initializes the driver info and hw (all asics). 1241926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1242926deccbSFrançois Tigeot * Called at driver startup. 1243926deccbSFrançois Tigeot */ 1244926deccbSFrançois Tigeot int radeon_device_init(struct radeon_device *rdev, 1245926deccbSFrançois Tigeot struct drm_device *ddev, 1246c6f73aabSFrançois Tigeot struct pci_dev *pdev, 1247926deccbSFrançois Tigeot uint32_t flags) 1248926deccbSFrançois Tigeot { 1249926deccbSFrançois Tigeot int r, i; 1250926deccbSFrançois Tigeot int dma_bits; 1251c6f73aabSFrançois Tigeot #ifdef PM_TODO 1252c6f73aabSFrançois Tigeot bool runtime = false; 1253c6f73aabSFrançois Tigeot #endif 1254926deccbSFrançois Tigeot 1255926deccbSFrançois Tigeot rdev->shutdown = false; 1256fb572d17SFrançois Tigeot rdev->dev = &pdev->dev; 1257926deccbSFrançois Tigeot rdev->ddev = ddev; 1258c6f73aabSFrançois Tigeot rdev->pdev = pdev; 1259926deccbSFrançois Tigeot rdev->flags = flags; 1260926deccbSFrançois Tigeot rdev->family = flags & RADEON_FAMILY_MASK; 1261926deccbSFrançois Tigeot rdev->is_atom_bios = false; 1262926deccbSFrançois Tigeot rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT; 12634cd92098Szrj rdev->mc.gtt_size = 512 * 1024 * 1024; 1264926deccbSFrançois Tigeot rdev->accel_working = false; 1265926deccbSFrançois Tigeot rdev->fictitious_range_registered = false; 1266926deccbSFrançois Tigeot /* set up ring ids */ 1267926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) { 1268926deccbSFrançois Tigeot rdev->ring[i].idx = i; 1269926deccbSFrançois Tigeot } 1270926deccbSFrançois Tigeot 1271926deccbSFrançois Tigeot DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", 1272c6f73aabSFrançois Tigeot radeon_family_name[rdev->family], pdev->vendor, pdev->device, 1273c6f73aabSFrançois Tigeot pdev->subsystem_vendor, pdev->subsystem_device); 1274926deccbSFrançois Tigeot 1275926deccbSFrançois Tigeot /* mutex initialization are all done here so we 1276926deccbSFrançois Tigeot * can recall function without having locking issues */ 1277926deccbSFrançois Tigeot lockinit(&rdev->ring_lock, "drm__radeon_device__ring_lock", 0, 1278926deccbSFrançois Tigeot LK_CANRECURSE); 1279926deccbSFrançois Tigeot lockinit(&rdev->dc_hw_i2c_mutex, 1280926deccbSFrançois Tigeot "drm__radeon_device__dc_hw_i2c_mutex", 0, LK_CANRECURSE); 1281926deccbSFrançois Tigeot atomic_set(&rdev->ih.lock, 0); 1282*fefad7a7SFrançois Tigeot lockinit(&rdev->gem.mutex, "radeon_gemmtx", 0, LK_CANRECURSE); 1283926deccbSFrançois Tigeot lockinit(&rdev->pm.mutex, "drm__radeon_device__pm__mutex", 0, 1284926deccbSFrançois Tigeot LK_CANRECURSE); 1285*fefad7a7SFrançois Tigeot 1286*fefad7a7SFrançois Tigeot lockinit(&rdev->gpu_clock_mutex, "radeon_clockmtx", 0, LK_CANRECURSE); 1287*fefad7a7SFrançois Tigeot lockinit(&rdev->srbm_mutex, "radeon_srbm_mutex", 0, LK_CANRECURSE); 1288926deccbSFrançois Tigeot lockinit(&rdev->pm.mclk_lock, "drm__radeon_device__pm__mclk_lock", 0, 1289926deccbSFrançois Tigeot LK_CANRECURSE); 1290926deccbSFrançois Tigeot lockinit(&rdev->exclusive_lock, "drm__radeon_device__exclusive_lock", 1291926deccbSFrançois Tigeot 0, LK_CANRECURSE); 1292c6f73aabSFrançois Tigeot init_waitqueue_head(&rdev->irq.vblank_queue); 1293926deccbSFrançois Tigeot r = radeon_gem_init(rdev); 1294926deccbSFrançois Tigeot if (r) 1295926deccbSFrançois Tigeot return r; 1296c6f73aabSFrançois Tigeot 1297c6f73aabSFrançois Tigeot radeon_check_arguments(rdev); 1298926deccbSFrançois Tigeot /* Adjust VM size here. 1299c6f73aabSFrançois Tigeot * Max GPUVM size for cayman+ is 40 bits. 1300926deccbSFrançois Tigeot */ 1301c6f73aabSFrançois Tigeot rdev->vm_manager.max_pfn = radeon_vm_size << 18; 1302926deccbSFrançois Tigeot 1303926deccbSFrançois Tigeot /* Set asic functions */ 1304926deccbSFrançois Tigeot r = radeon_asic_init(rdev); 1305926deccbSFrançois Tigeot if (r) 1306926deccbSFrançois Tigeot return r; 1307926deccbSFrançois Tigeot 1308926deccbSFrançois Tigeot /* all of the newer IGP chips have an internal gart 1309926deccbSFrançois Tigeot * However some rs4xx report as AGP, so remove that here. 1310926deccbSFrançois Tigeot */ 1311926deccbSFrançois Tigeot if ((rdev->family >= CHIP_RS400) && 1312926deccbSFrançois Tigeot (rdev->flags & RADEON_IS_IGP)) { 1313926deccbSFrançois Tigeot rdev->flags &= ~RADEON_IS_AGP; 1314926deccbSFrançois Tigeot } 1315926deccbSFrançois Tigeot 1316926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) { 1317926deccbSFrançois Tigeot radeon_agp_disable(rdev); 1318926deccbSFrançois Tigeot } 1319926deccbSFrançois Tigeot 1320f43cf1b1SMichael Neumann /* Set the internal MC address mask 1321f43cf1b1SMichael Neumann * This is the max address of the GPU's 1322f43cf1b1SMichael Neumann * internal address space. 1323f43cf1b1SMichael Neumann */ 1324f43cf1b1SMichael Neumann if (rdev->family >= CHIP_CAYMAN) 1325f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xffffffffffULL; /* 40 bit MC */ 1326f43cf1b1SMichael Neumann else if (rdev->family >= CHIP_CEDAR) 1327f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xfffffffffULL; /* 36 bit MC */ 1328f43cf1b1SMichael Neumann else 1329f43cf1b1SMichael Neumann rdev->mc.mc_mask = 0xffffffffULL; /* 32 bit MC */ 1330f43cf1b1SMichael Neumann 1331926deccbSFrançois Tigeot /* set DMA mask + need_dma32 flags. 1332926deccbSFrançois Tigeot * PCIE - can handle 40-bits. 1333926deccbSFrançois Tigeot * IGP - can handle 40-bits 1334926deccbSFrançois Tigeot * AGP - generally dma32 is safest 1335926deccbSFrançois Tigeot * PCI - dma32 for legacy pci gart, 40 bits on newer asics 1336926deccbSFrançois Tigeot */ 1337926deccbSFrançois Tigeot rdev->need_dma32 = false; 1338926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP) 1339926deccbSFrançois Tigeot rdev->need_dma32 = true; 1340926deccbSFrançois Tigeot if ((rdev->flags & RADEON_IS_PCI) && 1341926deccbSFrançois Tigeot (rdev->family <= CHIP_RS740)) 1342926deccbSFrançois Tigeot rdev->need_dma32 = true; 1343926deccbSFrançois Tigeot 1344926deccbSFrançois Tigeot dma_bits = rdev->need_dma32 ? 32 : 40; 1345926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1346926deccbSFrançois Tigeot r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); 1347926deccbSFrançois Tigeot if (r) { 1348926deccbSFrançois Tigeot rdev->need_dma32 = true; 1349926deccbSFrançois Tigeot dma_bits = 32; 1350926deccbSFrançois Tigeot printk(KERN_WARNING "radeon: No suitable DMA available.\n"); 1351926deccbSFrançois Tigeot } 1352926deccbSFrançois Tigeot r = pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); 1353926deccbSFrançois Tigeot if (r) { 1354926deccbSFrançois Tigeot pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(32)); 1355926deccbSFrançois Tigeot printk(KERN_WARNING "radeon: No coherent DMA available.\n"); 1356926deccbSFrançois Tigeot } 1357926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1358926deccbSFrançois Tigeot 1359926deccbSFrançois Tigeot /* Registers mapping */ 1360926deccbSFrançois Tigeot /* TODO: block userspace mapping of io register */ 1361ba87a4abSSascha Wildner spin_init(&rdev->mmio_idx_lock, "radeon_mpio"); 1362c6f73aabSFrançois Tigeot spin_init(&rdev->smc_idx_lock, "radeon_smc"); 1363c6f73aabSFrançois Tigeot spin_init(&rdev->pll_idx_lock, "radeon_pll"); 1364c6f73aabSFrançois Tigeot spin_init(&rdev->mc_idx_lock, "radeon_mc"); 1365c6f73aabSFrançois Tigeot spin_init(&rdev->pcie_idx_lock, "radeon_pcie"); 1366c6f73aabSFrançois Tigeot spin_init(&rdev->pciep_idx_lock, "radeon_pciep"); 1367c6f73aabSFrançois Tigeot spin_init(&rdev->pif_idx_lock, "radeon_pif"); 1368c6f73aabSFrançois Tigeot spin_init(&rdev->cg_idx_lock, "radeon_cg"); 1369c6f73aabSFrançois Tigeot spin_init(&rdev->uvd_idx_lock, "radeon_uvd"); 1370c6f73aabSFrançois Tigeot spin_init(&rdev->rcu_idx_lock, "radeon_rcu"); 1371c6f73aabSFrançois Tigeot spin_init(&rdev->didt_idx_lock, "radeon_didt"); 1372c6f73aabSFrançois Tigeot spin_init(&rdev->end_idx_lock, "radeon_end"); 137357e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) { 137457e252bfSMichael Neumann rdev->rmmio_rid = PCIR_BAR(5); 137557e252bfSMichael Neumann } else { 1376926deccbSFrançois Tigeot rdev->rmmio_rid = PCIR_BAR(2); 137757e252bfSMichael Neumann } 1378fb572d17SFrançois Tigeot rdev->rmmio = bus_alloc_resource_any(rdev->dev->bsddev, SYS_RES_MEMORY, 1379926deccbSFrançois Tigeot &rdev->rmmio_rid, RF_ACTIVE | RF_SHAREABLE); 1380926deccbSFrançois Tigeot if (rdev->rmmio == NULL) { 1381926deccbSFrançois Tigeot return -ENOMEM; 1382926deccbSFrançois Tigeot } 1383926deccbSFrançois Tigeot rdev->rmmio_base = rman_get_start(rdev->rmmio); 1384926deccbSFrançois Tigeot rdev->rmmio_size = rman_get_size(rdev->rmmio); 1385926deccbSFrançois Tigeot DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base); 1386926deccbSFrançois Tigeot DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size); 1387926deccbSFrançois Tigeot 138857e252bfSMichael Neumann /* doorbell bar mapping */ 138957e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) 139057e252bfSMichael Neumann radeon_doorbell_init(rdev); 139157e252bfSMichael Neumann 1392926deccbSFrançois Tigeot /* io port mapping */ 1393926deccbSFrançois Tigeot for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) { 1394926deccbSFrançois Tigeot uint32_t data; 1395926deccbSFrançois Tigeot 1396fb572d17SFrançois Tigeot data = pci_read_config(rdev->dev->bsddev, PCIR_BAR(i), 4); 1397926deccbSFrançois Tigeot if (PCI_BAR_IO(data)) { 1398926deccbSFrançois Tigeot rdev->rio_rid = PCIR_BAR(i); 1399fb572d17SFrançois Tigeot rdev->rio_mem = bus_alloc_resource_any(rdev->dev->bsddev, 1400926deccbSFrançois Tigeot SYS_RES_IOPORT, &rdev->rio_rid, 1401926deccbSFrançois Tigeot RF_ACTIVE | RF_SHAREABLE); 1402926deccbSFrançois Tigeot break; 1403926deccbSFrançois Tigeot } 1404926deccbSFrançois Tigeot } 1405926deccbSFrançois Tigeot if (rdev->rio_mem == NULL) 1406926deccbSFrançois Tigeot DRM_ERROR("Unable to find PCI I/O BAR\n"); 1407926deccbSFrançois Tigeot 1408926deccbSFrançois Tigeot rdev->tq = taskqueue_create("radeonkms", M_WAITOK, 1409926deccbSFrançois Tigeot taskqueue_thread_enqueue, &rdev->tq); 1410926deccbSFrançois Tigeot taskqueue_start_threads(&rdev->tq, 1, 0, -1, "radeon taskq"); 1411926deccbSFrançois Tigeot 1412c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 1413c6f73aabSFrançois Tigeot radeon_device_handle_px_quirks(rdev); 1414c6f73aabSFrançois Tigeot 1415926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1416926deccbSFrançois Tigeot /* if we have > 1 VGA cards, then disable the radeon VGA resources */ 1417926deccbSFrançois Tigeot /* this will fail for cards that aren't VGA class devices, just 1418926deccbSFrançois Tigeot * ignore it */ 1419926deccbSFrançois Tigeot vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); 1420c6f73aabSFrançois Tigeot 1421c6f73aabSFrançois Tigeot #ifdef PM_TODO 1422c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 1423c6f73aabSFrançois Tigeot runtime = true; 1424c6f73aabSFrançois Tigeot vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime); 1425c6f73aabSFrançois Tigeot if (runtime) 1426fb572d17SFrançois Tigeot vga_switcheroo_init_domain_pm_ops(rdev->dev->bsddev, &rdev->vga_pm_domain); 1427c6f73aabSFrançois Tigeot #endif 1428926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1429926deccbSFrançois Tigeot 1430926deccbSFrançois Tigeot r = radeon_init(rdev); 1431926deccbSFrançois Tigeot if (r) 1432c6f73aabSFrançois Tigeot goto failed; 1433926deccbSFrançois Tigeot 1434f43cf1b1SMichael Neumann r = radeon_gem_debugfs_init(rdev); 1435f43cf1b1SMichael Neumann if (r) { 1436f43cf1b1SMichael Neumann DRM_ERROR("registering gem debugfs failed (%d).\n", r); 1437f43cf1b1SMichael Neumann } 1438f43cf1b1SMichael Neumann 1439926deccbSFrançois Tigeot if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) { 1440926deccbSFrançois Tigeot /* Acceleration not working on AGP card try again 1441926deccbSFrançois Tigeot * with fallback to PCI or PCIE GART 1442926deccbSFrançois Tigeot */ 1443926deccbSFrançois Tigeot radeon_asic_reset(rdev); 1444926deccbSFrançois Tigeot radeon_fini(rdev); 1445926deccbSFrançois Tigeot radeon_agp_disable(rdev); 1446926deccbSFrançois Tigeot r = radeon_init(rdev); 1447926deccbSFrançois Tigeot if (r) 1448c6f73aabSFrançois Tigeot goto failed; 1449926deccbSFrançois Tigeot } 1450926deccbSFrançois Tigeot 1451591d5043SFrançois Tigeot r = radeon_ib_ring_tests(rdev); 1452591d5043SFrançois Tigeot if (r) 1453591d5043SFrançois Tigeot DRM_ERROR("ib ring test failed (%d).\n", r); 1454591d5043SFrançois Tigeot 1455926deccbSFrançois Tigeot DRM_INFO("%s: Taking over the fictitious range 0x%jx-0x%jx\n", 1456926deccbSFrançois Tigeot __func__, (uintmax_t)rdev->mc.aper_base, 1457926deccbSFrançois Tigeot (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size); 1458926deccbSFrançois Tigeot r = vm_phys_fictitious_reg_range( 1459926deccbSFrançois Tigeot rdev->mc.aper_base, 1460926deccbSFrançois Tigeot rdev->mc.aper_base + rdev->mc.visible_vram_size, 1461926deccbSFrançois Tigeot VM_MEMATTR_WRITE_COMBINING); 1462926deccbSFrançois Tigeot if (r != 0) { 1463926deccbSFrançois Tigeot DRM_ERROR("Failed to register fictitious range " 1464926deccbSFrançois Tigeot "0x%jx-0x%jx (%d).\n", (uintmax_t)rdev->mc.aper_base, 1465926deccbSFrançois Tigeot (uintmax_t)rdev->mc.aper_base + rdev->mc.visible_vram_size, r); 1466926deccbSFrançois Tigeot return (-r); 1467926deccbSFrançois Tigeot } 1468926deccbSFrançois Tigeot rdev->fictitious_range_registered = true; 1469926deccbSFrançois Tigeot 1470926deccbSFrançois Tigeot if ((radeon_testing & 1)) { 14714cd92098Szrj if (rdev->accel_working) 1472926deccbSFrançois Tigeot radeon_test_moves(rdev); 14734cd92098Szrj else 14744cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping move tests\n"); 1475926deccbSFrançois Tigeot } 1476926deccbSFrançois Tigeot if ((radeon_testing & 2)) { 14774cd92098Szrj if (rdev->accel_working) 1478926deccbSFrançois Tigeot radeon_test_syncing(rdev); 14794cd92098Szrj else 14804cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping sync tests\n"); 1481926deccbSFrançois Tigeot } 1482926deccbSFrançois Tigeot if (radeon_benchmarking) { 14834cd92098Szrj if (rdev->accel_working) 1484926deccbSFrançois Tigeot radeon_benchmark(rdev, radeon_benchmarking); 14854cd92098Szrj else 14864cd92098Szrj DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n"); 1487926deccbSFrançois Tigeot } 1488926deccbSFrançois Tigeot return 0; 1489c6f73aabSFrançois Tigeot 1490c6f73aabSFrançois Tigeot failed: 1491c6f73aabSFrançois Tigeot #ifdef DRM_BDSM 1492c6f73aabSFrançois Tigeot if (runtime) 1493c6f73aabSFrançois Tigeot vga_switcheroo_fini_domain_pm_ops(rdev->dev); 1494c6f73aabSFrançois Tigeot #endif 1495c6f73aabSFrançois Tigeot return r; 1496926deccbSFrançois Tigeot } 1497926deccbSFrançois Tigeot 1498926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1499926deccbSFrançois Tigeot static void radeon_debugfs_remove_files(struct radeon_device *rdev); 1500926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1501926deccbSFrançois Tigeot 1502926deccbSFrançois Tigeot /** 1503926deccbSFrançois Tigeot * radeon_device_fini - tear down the driver 1504926deccbSFrançois Tigeot * 1505926deccbSFrançois Tigeot * @rdev: radeon_device pointer 1506926deccbSFrançois Tigeot * 1507926deccbSFrançois Tigeot * Tear down the driver info (all asics). 1508926deccbSFrançois Tigeot * Called at driver shutdown. 1509926deccbSFrançois Tigeot */ 1510926deccbSFrançois Tigeot void radeon_device_fini(struct radeon_device *rdev) 1511926deccbSFrançois Tigeot { 1512926deccbSFrançois Tigeot DRM_INFO("radeon: finishing device.\n"); 1513926deccbSFrançois Tigeot rdev->shutdown = true; 1514926deccbSFrançois Tigeot /* evict vram memory */ 1515926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev); 1516926deccbSFrançois Tigeot 1517926deccbSFrançois Tigeot if (rdev->fictitious_range_registered) { 1518926deccbSFrançois Tigeot vm_phys_fictitious_unreg_range( 1519926deccbSFrançois Tigeot rdev->mc.aper_base, 1520926deccbSFrançois Tigeot rdev->mc.aper_base + rdev->mc.visible_vram_size); 1521926deccbSFrançois Tigeot } 1522926deccbSFrançois Tigeot 1523926deccbSFrançois Tigeot radeon_fini(rdev); 1524926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1525926deccbSFrançois Tigeot vga_switcheroo_unregister_client(rdev->pdev); 1526c6f73aabSFrançois Tigeot if (rdev->flags & RADEON_IS_PX) 1527c6f73aabSFrançois Tigeot vga_switcheroo_fini_domain_pm_ops(rdev->dev); 1528926deccbSFrançois Tigeot vga_client_register(rdev->pdev, NULL, NULL, NULL); 1529926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1530926deccbSFrançois Tigeot 1531926deccbSFrançois Tigeot if (rdev->tq != NULL) { 1532926deccbSFrançois Tigeot taskqueue_free(rdev->tq); 1533926deccbSFrançois Tigeot rdev->tq = NULL; 1534926deccbSFrançois Tigeot } 1535926deccbSFrançois Tigeot 1536926deccbSFrançois Tigeot if (rdev->rio_mem) 1537fb572d17SFrançois Tigeot bus_release_resource(rdev->dev->bsddev, SYS_RES_IOPORT, rdev->rio_rid, 1538926deccbSFrançois Tigeot rdev->rio_mem); 1539926deccbSFrançois Tigeot rdev->rio_mem = NULL; 1540fb572d17SFrançois Tigeot bus_release_resource(rdev->dev->bsddev, SYS_RES_MEMORY, rdev->rmmio_rid, 1541926deccbSFrançois Tigeot rdev->rmmio); 1542926deccbSFrançois Tigeot rdev->rmmio = NULL; 154357e252bfSMichael Neumann if (rdev->family >= CHIP_BONAIRE) 154457e252bfSMichael Neumann radeon_doorbell_fini(rdev); 1545926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1546926deccbSFrançois Tigeot radeon_debugfs_remove_files(rdev); 1547926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1548926deccbSFrançois Tigeot } 1549926deccbSFrançois Tigeot 1550926deccbSFrançois Tigeot 1551926deccbSFrançois Tigeot /* 1552926deccbSFrançois Tigeot * Suspend & resume. 1553926deccbSFrançois Tigeot */ 1554926deccbSFrançois Tigeot /** 1555926deccbSFrançois Tigeot * radeon_suspend_kms - initiate device suspend 1556926deccbSFrançois Tigeot * 1557926deccbSFrançois Tigeot * @pdev: drm dev pointer 1558926deccbSFrançois Tigeot * @state: suspend state 1559926deccbSFrançois Tigeot * 1560926deccbSFrançois Tigeot * Puts the hw in the suspend state (all asics). 1561926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1562926deccbSFrançois Tigeot * Called at driver suspend. 1563926deccbSFrançois Tigeot */ 1564c6f73aabSFrançois Tigeot int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) 1565926deccbSFrançois Tigeot { 1566926deccbSFrançois Tigeot struct radeon_device *rdev; 1567926deccbSFrançois Tigeot struct drm_crtc *crtc; 1568926deccbSFrançois Tigeot struct drm_connector *connector; 1569926deccbSFrançois Tigeot int i, r; 1570926deccbSFrançois Tigeot 1571926deccbSFrançois Tigeot if (dev == NULL || dev->dev_private == NULL) { 1572926deccbSFrançois Tigeot return -ENODEV; 1573926deccbSFrançois Tigeot } 1574c6f73aabSFrançois Tigeot 1575926deccbSFrançois Tigeot rdev = dev->dev_private; 1576926deccbSFrançois Tigeot 1577926deccbSFrançois Tigeot if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 1578926deccbSFrançois Tigeot return 0; 1579926deccbSFrançois Tigeot 1580926deccbSFrançois Tigeot drm_kms_helper_poll_disable(dev); 1581926deccbSFrançois Tigeot 1582926deccbSFrançois Tigeot /* turn off display hw */ 1583926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1584926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); 1585926deccbSFrançois Tigeot } 1586926deccbSFrançois Tigeot 1587926deccbSFrançois Tigeot /* unpin the front buffers */ 1588926deccbSFrançois Tigeot list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 1589ba55f2f5SFrançois Tigeot struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb); 1590926deccbSFrançois Tigeot struct radeon_bo *robj; 1591926deccbSFrançois Tigeot 1592926deccbSFrançois Tigeot if (rfb == NULL || rfb->obj == NULL) { 1593926deccbSFrançois Tigeot continue; 1594926deccbSFrançois Tigeot } 1595926deccbSFrançois Tigeot robj = gem_to_radeon_bo(rfb->obj); 1596926deccbSFrançois Tigeot /* don't unpin kernel fb objects */ 1597926deccbSFrançois Tigeot if (!radeon_fbdev_robj_is_fb(rdev, robj)) { 1598926deccbSFrançois Tigeot r = radeon_bo_reserve(robj, false); 1599926deccbSFrançois Tigeot if (r == 0) { 1600926deccbSFrançois Tigeot radeon_bo_unpin(robj); 1601926deccbSFrançois Tigeot radeon_bo_unreserve(robj); 1602926deccbSFrançois Tigeot } 1603926deccbSFrançois Tigeot } 1604926deccbSFrançois Tigeot } 1605926deccbSFrançois Tigeot /* evict vram memory */ 1606926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev); 1607926deccbSFrançois Tigeot 1608926deccbSFrançois Tigeot /* wait for gpu to finish processing current batch */ 1609926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; i++) { 1610c6f73aabSFrançois Tigeot r = radeon_fence_wait_empty(rdev, i); 1611926deccbSFrançois Tigeot if (r) { 1612926deccbSFrançois Tigeot /* delay GPU reset to resume */ 1613c6f73aabSFrançois Tigeot radeon_fence_driver_force_completion(rdev, i); 1614926deccbSFrançois Tigeot } 1615926deccbSFrançois Tigeot } 1616926deccbSFrançois Tigeot 1617926deccbSFrançois Tigeot radeon_save_bios_scratch_regs(rdev); 1618926deccbSFrançois Tigeot 1619926deccbSFrançois Tigeot radeon_suspend(rdev); 1620926deccbSFrançois Tigeot radeon_hpd_fini(rdev); 1621926deccbSFrançois Tigeot /* evict remaining vram memory */ 1622926deccbSFrançois Tigeot radeon_bo_evict_vram(rdev); 1623926deccbSFrançois Tigeot 1624926deccbSFrançois Tigeot radeon_agp_suspend(rdev); 1625926deccbSFrançois Tigeot 1626fb572d17SFrançois Tigeot pci_save_state(device_get_parent(rdev->dev->bsddev)); 1627926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1628c6f73aabSFrançois Tigeot if (suspend) { 1629926deccbSFrançois Tigeot /* Shut down the device */ 1630926deccbSFrançois Tigeot pci_disable_device(dev->pdev); 1631926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1632fb572d17SFrançois Tigeot pci_set_powerstate(dev->dev->bsddev, PCI_POWERSTATE_D3); 1633926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1634926deccbSFrançois Tigeot } 1635c6f73aabSFrançois Tigeot #endif 1636c6f73aabSFrançois Tigeot if (fbcon) { 1637c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP 1638926deccbSFrançois Tigeot console_lock(); 1639926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1640926deccbSFrançois Tigeot radeon_fbdev_set_suspend(rdev, 1); 1641926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1642926deccbSFrançois Tigeot console_unlock(); 1643926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1644c6f73aabSFrançois Tigeot } 1645926deccbSFrançois Tigeot return 0; 1646926deccbSFrançois Tigeot } 1647926deccbSFrançois Tigeot 1648926deccbSFrançois Tigeot /** 1649926deccbSFrançois Tigeot * radeon_resume_kms - initiate device resume 1650926deccbSFrançois Tigeot * 1651926deccbSFrançois Tigeot * @pdev: drm dev pointer 1652926deccbSFrançois Tigeot * 1653926deccbSFrançois Tigeot * Bring the hw back to operating state (all asics). 1654926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1655926deccbSFrançois Tigeot * Called at driver resume. 1656926deccbSFrançois Tigeot */ 1657c6f73aabSFrançois Tigeot int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) 1658926deccbSFrançois Tigeot { 1659926deccbSFrançois Tigeot struct drm_connector *connector; 1660926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1661926deccbSFrançois Tigeot int r; 1662926deccbSFrançois Tigeot 1663926deccbSFrançois Tigeot if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 1664926deccbSFrançois Tigeot return 0; 1665926deccbSFrançois Tigeot 1666926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1667c6f73aabSFrançois Tigeot if (fbcon) { 1668926deccbSFrançois Tigeot console_lock(); 1669c6f73aabSFrançois Tigeot } 1670926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1671c6f73aabSFrançois Tigeot if (resume) { 1672fb572d17SFrançois Tigeot pci_set_powerstate(dev->dev->bsddev, PCI_POWERSTATE_D0); 1673fb572d17SFrançois Tigeot pci_restore_state(device_get_parent(rdev->dev->bsddev)); 1674926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1675926deccbSFrançois Tigeot if (pci_enable_device(dev->pdev)) { 1676c6f73aabSFrançois Tigeot if (fbcon) 1677926deccbSFrançois Tigeot console_unlock(); 1678926deccbSFrançois Tigeot return -1; 1679926deccbSFrançois Tigeot } 1680926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1681c6f73aabSFrançois Tigeot } 1682926deccbSFrançois Tigeot /* resume AGP if in use */ 1683926deccbSFrançois Tigeot radeon_agp_resume(rdev); 1684926deccbSFrançois Tigeot radeon_resume(rdev); 1685926deccbSFrançois Tigeot 1686926deccbSFrançois Tigeot r = radeon_ib_ring_tests(rdev); 1687926deccbSFrançois Tigeot if (r) 1688926deccbSFrançois Tigeot DRM_ERROR("ib ring test failed (%d).\n", r); 1689926deccbSFrançois Tigeot 1690c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 1691c6f73aabSFrançois Tigeot /* do dpm late init */ 1692c6f73aabSFrançois Tigeot r = radeon_pm_late_init(rdev); 1693c6f73aabSFrançois Tigeot if (r) { 1694c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = false; 1695c6f73aabSFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); 1696c6f73aabSFrançois Tigeot } 1697c6f73aabSFrançois Tigeot } else { 1698c6f73aabSFrançois Tigeot /* resume old pm late */ 1699926deccbSFrançois Tigeot radeon_pm_resume(rdev); 1700c6f73aabSFrançois Tigeot } 1701926deccbSFrançois Tigeot 1702c6f73aabSFrançois Tigeot radeon_restore_bios_scratch_regs(rdev); 1703926deccbSFrançois Tigeot 1704926deccbSFrançois Tigeot /* init dig PHYs, disp eng pll */ 1705926deccbSFrançois Tigeot if (rdev->is_atom_bios) { 1706926deccbSFrançois Tigeot radeon_atom_encoder_init(rdev); 1707926deccbSFrançois Tigeot radeon_atom_disp_eng_pll_init(rdev); 1708926deccbSFrançois Tigeot /* turn on the BL */ 1709926deccbSFrançois Tigeot if (rdev->mode_info.bl_encoder) { 1710926deccbSFrançois Tigeot u8 bl_level = radeon_get_backlight_level(rdev, 1711926deccbSFrançois Tigeot rdev->mode_info.bl_encoder); 1712926deccbSFrançois Tigeot radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, 1713926deccbSFrançois Tigeot bl_level); 1714926deccbSFrançois Tigeot } 1715926deccbSFrançois Tigeot } 1716926deccbSFrançois Tigeot /* reset hpd state */ 1717926deccbSFrançois Tigeot radeon_hpd_init(rdev); 1718926deccbSFrançois Tigeot /* blat the mode back in */ 1719c6f73aabSFrançois Tigeot if (fbcon) { 1720926deccbSFrançois Tigeot drm_helper_resume_force_mode(dev); 1721926deccbSFrançois Tigeot /* turn on display hw */ 1722926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1723926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); 1724926deccbSFrançois Tigeot } 1725c6f73aabSFrançois Tigeot } 1726926deccbSFrançois Tigeot 1727926deccbSFrançois Tigeot drm_kms_helper_poll_enable(dev); 1728c6f73aabSFrançois Tigeot 1729c6f73aabSFrançois Tigeot /* set the power state here in case we are a PX system or headless */ 1730c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 1731c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1732c6f73aabSFrançois Tigeot 1733c6f73aabSFrançois Tigeot if (fbcon) { 1734c6f73aabSFrançois Tigeot radeon_fbdev_set_suspend(rdev, 0); 1735c6f73aabSFrançois Tigeot #ifdef DUMBBELL_WIP 1736c6f73aabSFrançois Tigeot console_unlock(); 1737c6f73aabSFrançois Tigeot #endif /* DUMBBELL_WIP */ 1738c6f73aabSFrançois Tigeot } 1739c6f73aabSFrançois Tigeot 1740926deccbSFrançois Tigeot return 0; 1741926deccbSFrançois Tigeot } 1742926deccbSFrançois Tigeot 1743926deccbSFrançois Tigeot /** 1744926deccbSFrançois Tigeot * radeon_gpu_reset - reset the asic 1745926deccbSFrançois Tigeot * 1746926deccbSFrançois Tigeot * @rdev: radeon device pointer 1747926deccbSFrançois Tigeot * 1748926deccbSFrançois Tigeot * Attempt the reset the GPU if it has hung (all asics). 1749926deccbSFrançois Tigeot * Returns 0 for success or an error on failure. 1750926deccbSFrançois Tigeot */ 1751926deccbSFrançois Tigeot int radeon_gpu_reset(struct radeon_device *rdev) 1752926deccbSFrançois Tigeot { 1753926deccbSFrançois Tigeot unsigned ring_sizes[RADEON_NUM_RINGS]; 1754926deccbSFrançois Tigeot uint32_t *ring_data[RADEON_NUM_RINGS]; 1755926deccbSFrançois Tigeot 1756926deccbSFrançois Tigeot bool saved = false; 1757926deccbSFrançois Tigeot 1758926deccbSFrançois Tigeot int i, r; 1759926deccbSFrançois Tigeot int resched; 1760926deccbSFrançois Tigeot 1761926deccbSFrançois Tigeot lockmgr(&rdev->exclusive_lock, LK_EXCLUSIVE); 1762c6f73aabSFrançois Tigeot 1763c6f73aabSFrançois Tigeot if (!rdev->needs_reset) { 1764c6f73aabSFrançois Tigeot lockmgr(&rdev->exclusive_lock, LK_RELEASE); 1765c6f73aabSFrançois Tigeot return 0; 1766c6f73aabSFrançois Tigeot } 1767c6f73aabSFrançois Tigeot 1768926deccbSFrançois Tigeot radeon_save_bios_scratch_regs(rdev); 1769926deccbSFrançois Tigeot /* block TTM */ 1770926deccbSFrançois Tigeot resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); 1771926deccbSFrançois Tigeot radeon_suspend(rdev); 1772c6f73aabSFrançois Tigeot radeon_hpd_fini(rdev); 1773926deccbSFrançois Tigeot 1774926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) { 1775926deccbSFrançois Tigeot ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i], 1776926deccbSFrançois Tigeot &ring_data[i]); 1777926deccbSFrançois Tigeot if (ring_sizes[i]) { 1778926deccbSFrançois Tigeot saved = true; 1779926deccbSFrançois Tigeot dev_info(rdev->dev, "Saved %d dwords of commands " 1780926deccbSFrançois Tigeot "on ring %d.\n", ring_sizes[i], i); 1781926deccbSFrançois Tigeot } 1782926deccbSFrançois Tigeot } 1783926deccbSFrançois Tigeot 1784926deccbSFrançois Tigeot r = radeon_asic_reset(rdev); 1785926deccbSFrançois Tigeot if (!r) { 1786926deccbSFrançois Tigeot dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n"); 1787926deccbSFrançois Tigeot radeon_resume(rdev); 1788926deccbSFrançois Tigeot } 1789926deccbSFrançois Tigeot 1790926deccbSFrançois Tigeot radeon_restore_bios_scratch_regs(rdev); 1791926deccbSFrançois Tigeot 1792926deccbSFrançois Tigeot for (i = 0; i < RADEON_NUM_RINGS; ++i) { 1793591d5043SFrançois Tigeot if (!r && ring_data[i]) { 1794926deccbSFrançois Tigeot radeon_ring_restore(rdev, &rdev->ring[i], 1795926deccbSFrançois Tigeot ring_sizes[i], ring_data[i]); 1796926deccbSFrançois Tigeot } else { 1797c6f73aabSFrançois Tigeot radeon_fence_driver_force_completion(rdev, i); 1798c4ef309bSzrj kfree(ring_data[i]); 1799926deccbSFrançois Tigeot } 1800926deccbSFrançois Tigeot } 1801926deccbSFrançois Tigeot 1802c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 1803c6f73aabSFrançois Tigeot /* do dpm late init */ 1804c6f73aabSFrançois Tigeot r = radeon_pm_late_init(rdev); 1805c6f73aabSFrançois Tigeot if (r) { 1806c6f73aabSFrançois Tigeot rdev->pm.dpm_enabled = false; 1807c6f73aabSFrançois Tigeot DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); 1808c6f73aabSFrançois Tigeot } 1809c6f73aabSFrançois Tigeot } else { 1810c6f73aabSFrançois Tigeot /* resume old pm late */ 181157e252bfSMichael Neumann radeon_pm_resume(rdev); 1812c6f73aabSFrançois Tigeot } 1813c6f73aabSFrançois Tigeot 1814c6f73aabSFrançois Tigeot /* init dig PHYs, disp eng pll */ 1815c6f73aabSFrançois Tigeot if (rdev->is_atom_bios) { 1816c6f73aabSFrançois Tigeot radeon_atom_encoder_init(rdev); 1817c6f73aabSFrançois Tigeot radeon_atom_disp_eng_pll_init(rdev); 1818c6f73aabSFrançois Tigeot /* turn on the BL */ 1819c6f73aabSFrançois Tigeot if (rdev->mode_info.bl_encoder) { 1820c6f73aabSFrançois Tigeot u8 bl_level = radeon_get_backlight_level(rdev, 1821c6f73aabSFrançois Tigeot rdev->mode_info.bl_encoder); 1822c6f73aabSFrançois Tigeot radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, 1823c6f73aabSFrançois Tigeot bl_level); 1824c6f73aabSFrançois Tigeot } 1825c6f73aabSFrançois Tigeot } 1826c6f73aabSFrançois Tigeot /* reset hpd state */ 1827c6f73aabSFrançois Tigeot radeon_hpd_init(rdev); 1828c6f73aabSFrançois Tigeot 1829591d5043SFrançois Tigeot ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); 1830591d5043SFrançois Tigeot 1831591d5043SFrançois Tigeot rdev->in_reset = true; 1832591d5043SFrançois Tigeot rdev->needs_reset = false; 1833591d5043SFrançois Tigeot 1834591d5043SFrançois Tigeot #if 0 1835591d5043SFrançois Tigeot downgrade_write(&rdev->exclusive_lock); 1836591d5043SFrançois Tigeot #endif 1837591d5043SFrançois Tigeot 1838926deccbSFrançois Tigeot drm_helper_resume_force_mode(rdev->ddev); 1839926deccbSFrançois Tigeot 1840c6f73aabSFrançois Tigeot /* set the power state here in case we are a PX system or headless */ 1841c6f73aabSFrançois Tigeot if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 1842c6f73aabSFrançois Tigeot radeon_pm_compute_clocks(rdev); 1843c6f73aabSFrançois Tigeot 1844591d5043SFrançois Tigeot if (!r) { 1845591d5043SFrançois Tigeot r = radeon_ib_ring_tests(rdev); 1846591d5043SFrançois Tigeot if (r && saved) 1847591d5043SFrançois Tigeot r = -EAGAIN; 1848591d5043SFrançois Tigeot } else { 1849926deccbSFrançois Tigeot /* bad news, how to tell it to userspace ? */ 1850926deccbSFrançois Tigeot dev_info(rdev->dev, "GPU reset failed\n"); 1851926deccbSFrançois Tigeot } 1852926deccbSFrançois Tigeot 1853591d5043SFrançois Tigeot rdev->needs_reset = r == -EAGAIN; 1854591d5043SFrançois Tigeot rdev->in_reset = false; 1855591d5043SFrançois Tigeot 1856926deccbSFrançois Tigeot lockmgr(&rdev->exclusive_lock, LK_RELEASE); 1857926deccbSFrançois Tigeot return r; 1858926deccbSFrançois Tigeot } 1859926deccbSFrançois Tigeot 1860926deccbSFrançois Tigeot 1861926deccbSFrançois Tigeot /* 1862926deccbSFrançois Tigeot * Debugfs 1863926deccbSFrançois Tigeot */ 1864926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP 1865926deccbSFrançois Tigeot int radeon_debugfs_add_files(struct radeon_device *rdev, 1866926deccbSFrançois Tigeot struct drm_info_list *files, 1867926deccbSFrançois Tigeot unsigned nfiles) 1868926deccbSFrançois Tigeot { 1869926deccbSFrançois Tigeot unsigned i; 1870926deccbSFrançois Tigeot 1871926deccbSFrançois Tigeot for (i = 0; i < rdev->debugfs_count; i++) { 1872926deccbSFrançois Tigeot if (rdev->debugfs[i].files == files) { 1873926deccbSFrançois Tigeot /* Already registered */ 1874926deccbSFrançois Tigeot return 0; 1875926deccbSFrançois Tigeot } 1876926deccbSFrançois Tigeot } 1877926deccbSFrançois Tigeot 1878926deccbSFrançois Tigeot i = rdev->debugfs_count + 1; 1879926deccbSFrançois Tigeot if (i > RADEON_DEBUGFS_MAX_COMPONENTS) { 1880926deccbSFrançois Tigeot DRM_ERROR("Reached maximum number of debugfs components.\n"); 1881926deccbSFrançois Tigeot DRM_ERROR("Report so we increase " 1882926deccbSFrançois Tigeot "RADEON_DEBUGFS_MAX_COMPONENTS.\n"); 1883926deccbSFrançois Tigeot return -EINVAL; 1884926deccbSFrançois Tigeot } 1885926deccbSFrançois Tigeot rdev->debugfs[rdev->debugfs_count].files = files; 1886926deccbSFrançois Tigeot rdev->debugfs[rdev->debugfs_count].num_files = nfiles; 1887926deccbSFrançois Tigeot rdev->debugfs_count = i; 1888926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1889926deccbSFrançois Tigeot drm_debugfs_create_files(files, nfiles, 1890926deccbSFrançois Tigeot rdev->ddev->control->debugfs_root, 1891926deccbSFrançois Tigeot rdev->ddev->control); 1892926deccbSFrançois Tigeot drm_debugfs_create_files(files, nfiles, 1893926deccbSFrançois Tigeot rdev->ddev->primary->debugfs_root, 1894926deccbSFrançois Tigeot rdev->ddev->primary); 1895926deccbSFrançois Tigeot #endif 1896926deccbSFrançois Tigeot return 0; 1897926deccbSFrançois Tigeot } 1898926deccbSFrançois Tigeot 1899926deccbSFrançois Tigeot static void radeon_debugfs_remove_files(struct radeon_device *rdev) 1900926deccbSFrançois Tigeot { 1901926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1902926deccbSFrançois Tigeot unsigned i; 1903926deccbSFrançois Tigeot 1904926deccbSFrançois Tigeot for (i = 0; i < rdev->debugfs_count; i++) { 1905926deccbSFrançois Tigeot drm_debugfs_remove_files(rdev->debugfs[i].files, 1906926deccbSFrançois Tigeot rdev->debugfs[i].num_files, 1907926deccbSFrançois Tigeot rdev->ddev->control); 1908926deccbSFrançois Tigeot drm_debugfs_remove_files(rdev->debugfs[i].files, 1909926deccbSFrançois Tigeot rdev->debugfs[i].num_files, 1910926deccbSFrançois Tigeot rdev->ddev->primary); 1911926deccbSFrançois Tigeot } 1912926deccbSFrançois Tigeot #endif 1913926deccbSFrançois Tigeot } 1914926deccbSFrançois Tigeot 1915926deccbSFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1916926deccbSFrançois Tigeot int radeon_debugfs_init(struct drm_minor *minor) 1917926deccbSFrançois Tigeot { 1918926deccbSFrançois Tigeot return 0; 1919926deccbSFrançois Tigeot } 1920926deccbSFrançois Tigeot 1921926deccbSFrançois Tigeot void radeon_debugfs_cleanup(struct drm_minor *minor) 1922926deccbSFrançois Tigeot { 1923926deccbSFrançois Tigeot } 1924926deccbSFrançois Tigeot #endif 1925b6771645Szrj #endif /* DUMBBELL_WIP */ 1926