162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc. 462306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1462306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1762306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1862306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1962306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 2062306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2162306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2262306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Authors: Dave Airlie 2562306a36Sopenharmony_ci * Alex Deucher 2662306a36Sopenharmony_ci * Jerome Glisse 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/console.h> 3062306a36Sopenharmony_ci#include <linux/efi.h> 3162306a36Sopenharmony_ci#include <linux/pci.h> 3262306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3362306a36Sopenharmony_ci#include <linux/slab.h> 3462306a36Sopenharmony_ci#include <linux/vga_switcheroo.h> 3562306a36Sopenharmony_ci#include <linux/vgaarb.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <drm/drm_cache.h> 3862306a36Sopenharmony_ci#include <drm/drm_crtc_helper.h> 3962306a36Sopenharmony_ci#include <drm/drm_device.h> 4062306a36Sopenharmony_ci#include <drm/drm_file.h> 4162306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 4262306a36Sopenharmony_ci#include <drm/drm_probe_helper.h> 4362306a36Sopenharmony_ci#include <drm/radeon_drm.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "radeon_device.h" 4662306a36Sopenharmony_ci#include "radeon_reg.h" 4762306a36Sopenharmony_ci#include "radeon.h" 4862306a36Sopenharmony_ci#include "atom.h" 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic const char radeon_family_name[][16] = { 5162306a36Sopenharmony_ci "R100", 5262306a36Sopenharmony_ci "RV100", 5362306a36Sopenharmony_ci "RS100", 5462306a36Sopenharmony_ci "RV200", 5562306a36Sopenharmony_ci "RS200", 5662306a36Sopenharmony_ci "R200", 5762306a36Sopenharmony_ci "RV250", 5862306a36Sopenharmony_ci "RS300", 5962306a36Sopenharmony_ci "RV280", 6062306a36Sopenharmony_ci "R300", 6162306a36Sopenharmony_ci "R350", 6262306a36Sopenharmony_ci "RV350", 6362306a36Sopenharmony_ci "RV380", 6462306a36Sopenharmony_ci "R420", 6562306a36Sopenharmony_ci "R423", 6662306a36Sopenharmony_ci "RV410", 6762306a36Sopenharmony_ci "RS400", 6862306a36Sopenharmony_ci "RS480", 6962306a36Sopenharmony_ci "RS600", 7062306a36Sopenharmony_ci "RS690", 7162306a36Sopenharmony_ci "RS740", 7262306a36Sopenharmony_ci "RV515", 7362306a36Sopenharmony_ci "R520", 7462306a36Sopenharmony_ci "RV530", 7562306a36Sopenharmony_ci "RV560", 7662306a36Sopenharmony_ci "RV570", 7762306a36Sopenharmony_ci "R580", 7862306a36Sopenharmony_ci "R600", 7962306a36Sopenharmony_ci "RV610", 8062306a36Sopenharmony_ci "RV630", 8162306a36Sopenharmony_ci "RV670", 8262306a36Sopenharmony_ci "RV620", 8362306a36Sopenharmony_ci "RV635", 8462306a36Sopenharmony_ci "RS780", 8562306a36Sopenharmony_ci "RS880", 8662306a36Sopenharmony_ci "RV770", 8762306a36Sopenharmony_ci "RV730", 8862306a36Sopenharmony_ci "RV710", 8962306a36Sopenharmony_ci "RV740", 9062306a36Sopenharmony_ci "CEDAR", 9162306a36Sopenharmony_ci "REDWOOD", 9262306a36Sopenharmony_ci "JUNIPER", 9362306a36Sopenharmony_ci "CYPRESS", 9462306a36Sopenharmony_ci "HEMLOCK", 9562306a36Sopenharmony_ci "PALM", 9662306a36Sopenharmony_ci "SUMO", 9762306a36Sopenharmony_ci "SUMO2", 9862306a36Sopenharmony_ci "BARTS", 9962306a36Sopenharmony_ci "TURKS", 10062306a36Sopenharmony_ci "CAICOS", 10162306a36Sopenharmony_ci "CAYMAN", 10262306a36Sopenharmony_ci "ARUBA", 10362306a36Sopenharmony_ci "TAHITI", 10462306a36Sopenharmony_ci "PITCAIRN", 10562306a36Sopenharmony_ci "VERDE", 10662306a36Sopenharmony_ci "OLAND", 10762306a36Sopenharmony_ci "HAINAN", 10862306a36Sopenharmony_ci "BONAIRE", 10962306a36Sopenharmony_ci "KAVERI", 11062306a36Sopenharmony_ci "KABINI", 11162306a36Sopenharmony_ci "HAWAII", 11262306a36Sopenharmony_ci "MULLINS", 11362306a36Sopenharmony_ci "LAST", 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#if defined(CONFIG_VGA_SWITCHEROO) 11762306a36Sopenharmony_cibool radeon_has_atpx_dgpu_power_cntl(void); 11862306a36Sopenharmony_cibool radeon_is_atpx_hybrid(void); 11962306a36Sopenharmony_ci#else 12062306a36Sopenharmony_cistatic inline bool radeon_has_atpx_dgpu_power_cntl(void) { return false; } 12162306a36Sopenharmony_cistatic inline bool radeon_is_atpx_hybrid(void) { return false; } 12262306a36Sopenharmony_ci#endif 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define RADEON_PX_QUIRK_DISABLE_PX (1 << 0) 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistruct radeon_px_quirk { 12762306a36Sopenharmony_ci u32 chip_vendor; 12862306a36Sopenharmony_ci u32 chip_device; 12962306a36Sopenharmony_ci u32 subsys_vendor; 13062306a36Sopenharmony_ci u32 subsys_device; 13162306a36Sopenharmony_ci u32 px_quirk_flags; 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic struct radeon_px_quirk radeon_px_quirk_list[] = { 13562306a36Sopenharmony_ci /* Acer aspire 5560g (CPU: AMD A4-3305M; GPU: AMD Radeon HD 6480g + 7470m) 13662306a36Sopenharmony_ci * https://bugzilla.kernel.org/show_bug.cgi?id=74551 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci { PCI_VENDOR_ID_ATI, 0x6760, 0x1025, 0x0672, RADEON_PX_QUIRK_DISABLE_PX }, 13962306a36Sopenharmony_ci /* Asus K73TA laptop with AMD A6-3400M APU and Radeon 6550 GPU 14062306a36Sopenharmony_ci * https://bugzilla.kernel.org/show_bug.cgi?id=51381 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX }, 14362306a36Sopenharmony_ci /* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU 14462306a36Sopenharmony_ci * https://bugzilla.kernel.org/show_bug.cgi?id=51381 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX }, 14762306a36Sopenharmony_ci /* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU 14862306a36Sopenharmony_ci * https://bugs.freedesktop.org/show_bug.cgi?id=101491 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX }, 15162306a36Sopenharmony_ci /* Asus K73TK laptop with AMD A6-3420M APU and Radeon 7670m GPU 15262306a36Sopenharmony_ci * https://bugzilla.kernel.org/show_bug.cgi?id=51381#c52 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2123, RADEON_PX_QUIRK_DISABLE_PX }, 15562306a36Sopenharmony_ci { 0, 0, 0, 0, 0 }, 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cibool radeon_is_px(struct drm_device *dev) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PX) 16362306a36Sopenharmony_ci return true; 16462306a36Sopenharmony_ci return false; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic void radeon_device_handle_px_quirks(struct radeon_device *rdev) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct radeon_px_quirk *p = radeon_px_quirk_list; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Apply PX quirks */ 17262306a36Sopenharmony_ci while (p && p->chip_device != 0) { 17362306a36Sopenharmony_ci if (rdev->pdev->vendor == p->chip_vendor && 17462306a36Sopenharmony_ci rdev->pdev->device == p->chip_device && 17562306a36Sopenharmony_ci rdev->pdev->subsystem_vendor == p->subsys_vendor && 17662306a36Sopenharmony_ci rdev->pdev->subsystem_device == p->subsys_device) { 17762306a36Sopenharmony_ci rdev->px_quirk_flags = p->px_quirk_flags; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci ++p; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (rdev->px_quirk_flags & RADEON_PX_QUIRK_DISABLE_PX) 18462306a36Sopenharmony_ci rdev->flags &= ~RADEON_IS_PX; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* disable PX is the system doesn't support dGPU power control or hybrid gfx */ 18762306a36Sopenharmony_ci if (!radeon_is_atpx_hybrid() && 18862306a36Sopenharmony_ci !radeon_has_atpx_dgpu_power_cntl()) 18962306a36Sopenharmony_ci rdev->flags &= ~RADEON_IS_PX; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/** 19362306a36Sopenharmony_ci * radeon_program_register_sequence - program an array of registers. 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * @rdev: radeon_device pointer 19662306a36Sopenharmony_ci * @registers: pointer to the register array 19762306a36Sopenharmony_ci * @array_size: size of the register array 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * Programs an array or registers with and and or masks. 20062306a36Sopenharmony_ci * This is a helper for setting golden registers. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_civoid radeon_program_register_sequence(struct radeon_device *rdev, 20362306a36Sopenharmony_ci const u32 *registers, 20462306a36Sopenharmony_ci const u32 array_size) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci u32 tmp, reg, and_mask, or_mask; 20762306a36Sopenharmony_ci int i; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (array_size % 3) 21062306a36Sopenharmony_ci return; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci for (i = 0; i < array_size; i +=3) { 21362306a36Sopenharmony_ci reg = registers[i + 0]; 21462306a36Sopenharmony_ci and_mask = registers[i + 1]; 21562306a36Sopenharmony_ci or_mask = registers[i + 2]; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (and_mask == 0xffffffff) { 21862306a36Sopenharmony_ci tmp = or_mask; 21962306a36Sopenharmony_ci } else { 22062306a36Sopenharmony_ci tmp = RREG32(reg); 22162306a36Sopenharmony_ci tmp &= ~and_mask; 22262306a36Sopenharmony_ci tmp |= or_mask; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci WREG32(reg, tmp); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_civoid radeon_pci_config_reset(struct radeon_device *rdev) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci pci_write_config_dword(rdev->pdev, 0x7c, RADEON_ASIC_RESET_DATA); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/** 23462306a36Sopenharmony_ci * radeon_surface_init - Clear GPU surface registers. 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * @rdev: radeon_device pointer 23762306a36Sopenharmony_ci * 23862306a36Sopenharmony_ci * Clear GPU surface registers (r1xx-r5xx). 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_civoid radeon_surface_init(struct radeon_device *rdev) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci /* FIXME: check this out */ 24362306a36Sopenharmony_ci if (rdev->family < CHIP_R600) { 24462306a36Sopenharmony_ci int i; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) { 24762306a36Sopenharmony_ci if (rdev->surface_regs[i].bo) 24862306a36Sopenharmony_ci radeon_bo_get_surface_reg(rdev->surface_regs[i].bo); 24962306a36Sopenharmony_ci else 25062306a36Sopenharmony_ci radeon_clear_surface_reg(rdev, i); 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci /* enable surfaces */ 25362306a36Sopenharmony_ci WREG32(RADEON_SURFACE_CNTL, 0); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/* 25862306a36Sopenharmony_ci * GPU scratch registers helpers function. 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_ci/** 26162306a36Sopenharmony_ci * radeon_scratch_init - Init scratch register driver information. 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * @rdev: radeon_device pointer 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci * Init CP scratch register driver information (r1xx-r5xx) 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_civoid radeon_scratch_init(struct radeon_device *rdev) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci int i; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* FIXME: check this out */ 27262306a36Sopenharmony_ci if (rdev->family < CHIP_R300) { 27362306a36Sopenharmony_ci rdev->scratch.num_reg = 5; 27462306a36Sopenharmony_ci } else { 27562306a36Sopenharmony_ci rdev->scratch.num_reg = 7; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci rdev->scratch.reg_base = RADEON_SCRATCH_REG0; 27862306a36Sopenharmony_ci for (i = 0; i < rdev->scratch.num_reg; i++) { 27962306a36Sopenharmony_ci rdev->scratch.free[i] = true; 28062306a36Sopenharmony_ci rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * radeon_scratch_get - Allocate a scratch register 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * @rdev: radeon_device pointer 28862306a36Sopenharmony_ci * @reg: scratch register mmio offset 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci * Allocate a CP scratch register for use by the driver (all asics). 29162306a36Sopenharmony_ci * Returns 0 on success or -EINVAL on failure. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ciint radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci int i; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci for (i = 0; i < rdev->scratch.num_reg; i++) { 29862306a36Sopenharmony_ci if (rdev->scratch.free[i]) { 29962306a36Sopenharmony_ci rdev->scratch.free[i] = false; 30062306a36Sopenharmony_ci *reg = rdev->scratch.reg[i]; 30162306a36Sopenharmony_ci return 0; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci return -EINVAL; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/** 30862306a36Sopenharmony_ci * radeon_scratch_free - Free a scratch register 30962306a36Sopenharmony_ci * 31062306a36Sopenharmony_ci * @rdev: radeon_device pointer 31162306a36Sopenharmony_ci * @reg: scratch register mmio offset 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * Free a CP scratch register allocated for use by the driver (all asics) 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_civoid radeon_scratch_free(struct radeon_device *rdev, uint32_t reg) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci int i; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci for (i = 0; i < rdev->scratch.num_reg; i++) { 32062306a36Sopenharmony_ci if (rdev->scratch.reg[i] == reg) { 32162306a36Sopenharmony_ci rdev->scratch.free[i] = true; 32262306a36Sopenharmony_ci return; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/* 32862306a36Sopenharmony_ci * GPU doorbell aperture helpers function. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci/** 33162306a36Sopenharmony_ci * radeon_doorbell_init - Init doorbell driver information. 33262306a36Sopenharmony_ci * 33362306a36Sopenharmony_ci * @rdev: radeon_device pointer 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * Init doorbell driver information (CIK) 33662306a36Sopenharmony_ci * Returns 0 on success, error on failure. 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_cistatic int radeon_doorbell_init(struct radeon_device *rdev) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci /* doorbell bar mapping */ 34162306a36Sopenharmony_ci rdev->doorbell.base = pci_resource_start(rdev->pdev, 2); 34262306a36Sopenharmony_ci rdev->doorbell.size = pci_resource_len(rdev->pdev, 2); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci rdev->doorbell.num_doorbells = min_t(u32, rdev->doorbell.size / sizeof(u32), RADEON_MAX_DOORBELLS); 34562306a36Sopenharmony_ci if (rdev->doorbell.num_doorbells == 0) 34662306a36Sopenharmony_ci return -EINVAL; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.num_doorbells * sizeof(u32)); 34962306a36Sopenharmony_ci if (rdev->doorbell.ptr == NULL) { 35062306a36Sopenharmony_ci return -ENOMEM; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base); 35362306a36Sopenharmony_ci DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci memset(&rdev->doorbell.used, 0, sizeof(rdev->doorbell.used)); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci return 0; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/** 36162306a36Sopenharmony_ci * radeon_doorbell_fini - Tear down doorbell driver information. 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * @rdev: radeon_device pointer 36462306a36Sopenharmony_ci * 36562306a36Sopenharmony_ci * Tear down doorbell driver information (CIK) 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_cistatic void radeon_doorbell_fini(struct radeon_device *rdev) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci iounmap(rdev->doorbell.ptr); 37062306a36Sopenharmony_ci rdev->doorbell.ptr = NULL; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/** 37462306a36Sopenharmony_ci * radeon_doorbell_get - Allocate a doorbell entry 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * @rdev: radeon_device pointer 37762306a36Sopenharmony_ci * @doorbell: doorbell index 37862306a36Sopenharmony_ci * 37962306a36Sopenharmony_ci * Allocate a doorbell for use by the driver (all asics). 38062306a36Sopenharmony_ci * Returns 0 on success or -EINVAL on failure. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ciint radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci unsigned long offset = find_first_zero_bit(rdev->doorbell.used, rdev->doorbell.num_doorbells); 38562306a36Sopenharmony_ci if (offset < rdev->doorbell.num_doorbells) { 38662306a36Sopenharmony_ci __set_bit(offset, rdev->doorbell.used); 38762306a36Sopenharmony_ci *doorbell = offset; 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci } else { 39062306a36Sopenharmony_ci return -EINVAL; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/** 39562306a36Sopenharmony_ci * radeon_doorbell_free - Free a doorbell entry 39662306a36Sopenharmony_ci * 39762306a36Sopenharmony_ci * @rdev: radeon_device pointer 39862306a36Sopenharmony_ci * @doorbell: doorbell index 39962306a36Sopenharmony_ci * 40062306a36Sopenharmony_ci * Free a doorbell allocated for use by the driver (all asics) 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_civoid radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci if (doorbell < rdev->doorbell.num_doorbells) 40562306a36Sopenharmony_ci __clear_bit(doorbell, rdev->doorbell.used); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* 40962306a36Sopenharmony_ci * radeon_wb_*() 41062306a36Sopenharmony_ci * Writeback is the method by which the GPU updates special pages 41162306a36Sopenharmony_ci * in memory with the status of certain GPU events (fences, ring pointers, 41262306a36Sopenharmony_ci * etc.). 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/** 41662306a36Sopenharmony_ci * radeon_wb_disable - Disable Writeback 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * @rdev: radeon_device pointer 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * Disables Writeback (all asics). Used for suspend. 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_civoid radeon_wb_disable(struct radeon_device *rdev) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci rdev->wb.enabled = false; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci/** 42862306a36Sopenharmony_ci * radeon_wb_fini - Disable Writeback and free memory 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci * @rdev: radeon_device pointer 43162306a36Sopenharmony_ci * 43262306a36Sopenharmony_ci * Disables Writeback and frees the Writeback memory (all asics). 43362306a36Sopenharmony_ci * Used at driver shutdown. 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_civoid radeon_wb_fini(struct radeon_device *rdev) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci radeon_wb_disable(rdev); 43862306a36Sopenharmony_ci if (rdev->wb.wb_obj) { 43962306a36Sopenharmony_ci if (!radeon_bo_reserve(rdev->wb.wb_obj, false)) { 44062306a36Sopenharmony_ci radeon_bo_kunmap(rdev->wb.wb_obj); 44162306a36Sopenharmony_ci radeon_bo_unpin(rdev->wb.wb_obj); 44262306a36Sopenharmony_ci radeon_bo_unreserve(rdev->wb.wb_obj); 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci radeon_bo_unref(&rdev->wb.wb_obj); 44562306a36Sopenharmony_ci rdev->wb.wb = NULL; 44662306a36Sopenharmony_ci rdev->wb.wb_obj = NULL; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/** 45162306a36Sopenharmony_ci * radeon_wb_init- Init Writeback driver info and allocate memory 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci * @rdev: radeon_device pointer 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * Disables Writeback and frees the Writeback memory (all asics). 45662306a36Sopenharmony_ci * Used at driver startup. 45762306a36Sopenharmony_ci * Returns 0 on success or an -error on failure. 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ciint radeon_wb_init(struct radeon_device *rdev) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci int r; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (rdev->wb.wb_obj == NULL) { 46462306a36Sopenharmony_ci r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, 46562306a36Sopenharmony_ci RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL, 46662306a36Sopenharmony_ci &rdev->wb.wb_obj); 46762306a36Sopenharmony_ci if (r) { 46862306a36Sopenharmony_ci dev_warn(rdev->dev, "(%d) create WB bo failed\n", r); 46962306a36Sopenharmony_ci return r; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci r = radeon_bo_reserve(rdev->wb.wb_obj, false); 47262306a36Sopenharmony_ci if (unlikely(r != 0)) { 47362306a36Sopenharmony_ci radeon_wb_fini(rdev); 47462306a36Sopenharmony_ci return r; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT, 47762306a36Sopenharmony_ci &rdev->wb.gpu_addr); 47862306a36Sopenharmony_ci if (r) { 47962306a36Sopenharmony_ci radeon_bo_unreserve(rdev->wb.wb_obj); 48062306a36Sopenharmony_ci dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r); 48162306a36Sopenharmony_ci radeon_wb_fini(rdev); 48262306a36Sopenharmony_ci return r; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb); 48562306a36Sopenharmony_ci radeon_bo_unreserve(rdev->wb.wb_obj); 48662306a36Sopenharmony_ci if (r) { 48762306a36Sopenharmony_ci dev_warn(rdev->dev, "(%d) map WB bo failed\n", r); 48862306a36Sopenharmony_ci radeon_wb_fini(rdev); 48962306a36Sopenharmony_ci return r; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* clear wb memory */ 49462306a36Sopenharmony_ci memset((char *)rdev->wb.wb, 0, RADEON_GPU_PAGE_SIZE); 49562306a36Sopenharmony_ci /* disable event_write fences */ 49662306a36Sopenharmony_ci rdev->wb.use_event = false; 49762306a36Sopenharmony_ci /* disabled via module param */ 49862306a36Sopenharmony_ci if (radeon_no_wb == 1) { 49962306a36Sopenharmony_ci rdev->wb.enabled = false; 50062306a36Sopenharmony_ci } else { 50162306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) { 50262306a36Sopenharmony_ci /* often unreliable on AGP */ 50362306a36Sopenharmony_ci rdev->wb.enabled = false; 50462306a36Sopenharmony_ci } else if (rdev->family < CHIP_R300) { 50562306a36Sopenharmony_ci /* often unreliable on pre-r300 */ 50662306a36Sopenharmony_ci rdev->wb.enabled = false; 50762306a36Sopenharmony_ci } else { 50862306a36Sopenharmony_ci rdev->wb.enabled = true; 50962306a36Sopenharmony_ci /* event_write fences are only available on r600+ */ 51062306a36Sopenharmony_ci if (rdev->family >= CHIP_R600) { 51162306a36Sopenharmony_ci rdev->wb.use_event = true; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci /* always use writeback/events on NI, APUs */ 51662306a36Sopenharmony_ci if (rdev->family >= CHIP_PALM) { 51762306a36Sopenharmony_ci rdev->wb.enabled = true; 51862306a36Sopenharmony_ci rdev->wb.use_event = true; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci dev_info(rdev->dev, "WB %sabled\n", rdev->wb.enabled ? "en" : "dis"); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci/** 52762306a36Sopenharmony_ci * radeon_vram_location - try to find VRAM location 52862306a36Sopenharmony_ci * @rdev: radeon device structure holding all necessary informations 52962306a36Sopenharmony_ci * @mc: memory controller structure holding memory informations 53062306a36Sopenharmony_ci * @base: base address at which to put VRAM 53162306a36Sopenharmony_ci * 53262306a36Sopenharmony_ci * Function will place try to place VRAM at base address provided 53362306a36Sopenharmony_ci * as parameter (which is so far either PCI aperture address or 53462306a36Sopenharmony_ci * for IGP TOM base address). 53562306a36Sopenharmony_ci * 53662306a36Sopenharmony_ci * If there is not enough space to fit the unvisible VRAM in the 32bits 53762306a36Sopenharmony_ci * address space then we limit the VRAM size to the aperture. 53862306a36Sopenharmony_ci * 53962306a36Sopenharmony_ci * If we are using AGP and if the AGP aperture doesn't allow us to have 54062306a36Sopenharmony_ci * room for all the VRAM than we restrict the VRAM to the PCI aperture 54162306a36Sopenharmony_ci * size and print a warning. 54262306a36Sopenharmony_ci * 54362306a36Sopenharmony_ci * This function will never fails, worst case are limiting VRAM. 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * Note: GTT start, end, size should be initialized before calling this 54662306a36Sopenharmony_ci * function on AGP platform. 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * Note 1: We don't explicitly enforce VRAM start to be aligned on VRAM size, 54962306a36Sopenharmony_ci * this shouldn't be a problem as we are using the PCI aperture as a reference. 55062306a36Sopenharmony_ci * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but 55162306a36Sopenharmony_ci * not IGP. 55262306a36Sopenharmony_ci * 55362306a36Sopenharmony_ci * Note 2: we use mc_vram_size as on some board we need to program the mc to 55462306a36Sopenharmony_ci * cover the whole aperture even if VRAM size is inferior to aperture size 55562306a36Sopenharmony_ci * Novell bug 204882 + along with lots of ubuntu ones 55662306a36Sopenharmony_ci * 55762306a36Sopenharmony_ci * Note 3: when limiting vram it's safe to overwritte real_vram_size because 55862306a36Sopenharmony_ci * we are not in case where real_vram_size is inferior to mc_vram_size (ie 55962306a36Sopenharmony_ci * note afected by bogus hw of Novell bug 204882 + along with lots of ubuntu 56062306a36Sopenharmony_ci * ones) 56162306a36Sopenharmony_ci * 56262306a36Sopenharmony_ci * Note 4: IGP TOM addr should be the same as the aperture addr, we don't 56362306a36Sopenharmony_ci * explicitly check for that thought. 56462306a36Sopenharmony_ci * 56562306a36Sopenharmony_ci * FIXME: when reducing VRAM size align new size on power of 2. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_civoid radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci uint64_t limit = (uint64_t)radeon_vram_limit << 20; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci mc->vram_start = base; 57262306a36Sopenharmony_ci if (mc->mc_vram_size > (rdev->mc.mc_mask - base + 1)) { 57362306a36Sopenharmony_ci dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); 57462306a36Sopenharmony_ci mc->real_vram_size = mc->aper_size; 57562306a36Sopenharmony_ci mc->mc_vram_size = mc->aper_size; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; 57862306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_start <= mc->gtt_end) { 57962306a36Sopenharmony_ci dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); 58062306a36Sopenharmony_ci mc->real_vram_size = mc->aper_size; 58162306a36Sopenharmony_ci mc->mc_vram_size = mc->aper_size; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; 58462306a36Sopenharmony_ci if (limit && limit < mc->real_vram_size) 58562306a36Sopenharmony_ci mc->real_vram_size = limit; 58662306a36Sopenharmony_ci dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n", 58762306a36Sopenharmony_ci mc->mc_vram_size >> 20, mc->vram_start, 58862306a36Sopenharmony_ci mc->vram_end, mc->real_vram_size >> 20); 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci/** 59262306a36Sopenharmony_ci * radeon_gtt_location - try to find GTT location 59362306a36Sopenharmony_ci * @rdev: radeon device structure holding all necessary informations 59462306a36Sopenharmony_ci * @mc: memory controller structure holding memory informations 59562306a36Sopenharmony_ci * 59662306a36Sopenharmony_ci * Function will place try to place GTT before or after VRAM. 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * If GTT size is bigger than space left then we ajust GTT size. 59962306a36Sopenharmony_ci * Thus function will never fails. 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * FIXME: when reducing GTT size align new size on power of 2. 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_civoid radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci u64 size_af, size_bf; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci size_af = ((rdev->mc.mc_mask - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align; 60862306a36Sopenharmony_ci size_bf = mc->vram_start & ~mc->gtt_base_align; 60962306a36Sopenharmony_ci if (size_bf > size_af) { 61062306a36Sopenharmony_ci if (mc->gtt_size > size_bf) { 61162306a36Sopenharmony_ci dev_warn(rdev->dev, "limiting GTT\n"); 61262306a36Sopenharmony_ci mc->gtt_size = size_bf; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size; 61562306a36Sopenharmony_ci } else { 61662306a36Sopenharmony_ci if (mc->gtt_size > size_af) { 61762306a36Sopenharmony_ci dev_warn(rdev->dev, "limiting GTT\n"); 61862306a36Sopenharmony_ci mc->gtt_size = size_af; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci mc->gtt_end = mc->gtt_start + mc->gtt_size - 1; 62362306a36Sopenharmony_ci dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n", 62462306a36Sopenharmony_ci mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end); 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci/* 62862306a36Sopenharmony_ci * GPU helpers function. 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci/* 63262306a36Sopenharmony_ci * radeon_device_is_virtual - check if we are running is a virtual environment 63362306a36Sopenharmony_ci * 63462306a36Sopenharmony_ci * Check if the asic has been passed through to a VM (all asics). 63562306a36Sopenharmony_ci * Used at driver startup. 63662306a36Sopenharmony_ci * Returns true if virtual or false if not. 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_cibool radeon_device_is_virtual(void) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci#ifdef CONFIG_X86 64162306a36Sopenharmony_ci return boot_cpu_has(X86_FEATURE_HYPERVISOR); 64262306a36Sopenharmony_ci#else 64362306a36Sopenharmony_ci return false; 64462306a36Sopenharmony_ci#endif 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/** 64862306a36Sopenharmony_ci * radeon_card_posted - check if the hw has already been initialized 64962306a36Sopenharmony_ci * 65062306a36Sopenharmony_ci * @rdev: radeon_device pointer 65162306a36Sopenharmony_ci * 65262306a36Sopenharmony_ci * Check if the asic has been initialized (all asics). 65362306a36Sopenharmony_ci * Used at driver startup. 65462306a36Sopenharmony_ci * Returns true if initialized or false if not. 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_cibool radeon_card_posted(struct radeon_device *rdev) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci uint32_t reg; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci /* for pass through, always force asic_init for CI */ 66162306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE && 66262306a36Sopenharmony_ci radeon_device_is_virtual()) 66362306a36Sopenharmony_ci return false; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* required for EFI mode on macbook2,1 which uses an r5xx asic */ 66662306a36Sopenharmony_ci if (efi_enabled(EFI_BOOT) && 66762306a36Sopenharmony_ci (rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) && 66862306a36Sopenharmony_ci (rdev->family < CHIP_R600)) 66962306a36Sopenharmony_ci return false; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (ASIC_IS_NODCE(rdev)) 67262306a36Sopenharmony_ci goto check_memsize; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* first check CRTCs */ 67562306a36Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 67662306a36Sopenharmony_ci reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | 67762306a36Sopenharmony_ci RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); 67862306a36Sopenharmony_ci if (rdev->num_crtc >= 4) { 67962306a36Sopenharmony_ci reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | 68062306a36Sopenharmony_ci RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci if (rdev->num_crtc >= 6) { 68362306a36Sopenharmony_ci reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | 68462306a36Sopenharmony_ci RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci if (reg & EVERGREEN_CRTC_MASTER_EN) 68762306a36Sopenharmony_ci return true; 68862306a36Sopenharmony_ci } else if (ASIC_IS_AVIVO(rdev)) { 68962306a36Sopenharmony_ci reg = RREG32(AVIVO_D1CRTC_CONTROL) | 69062306a36Sopenharmony_ci RREG32(AVIVO_D2CRTC_CONTROL); 69162306a36Sopenharmony_ci if (reg & AVIVO_CRTC_EN) { 69262306a36Sopenharmony_ci return true; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci } else { 69562306a36Sopenharmony_ci reg = RREG32(RADEON_CRTC_GEN_CNTL) | 69662306a36Sopenharmony_ci RREG32(RADEON_CRTC2_GEN_CNTL); 69762306a36Sopenharmony_ci if (reg & RADEON_CRTC_EN) { 69862306a36Sopenharmony_ci return true; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cicheck_memsize: 70362306a36Sopenharmony_ci /* then check MEM_SIZE, in case the crtcs are off */ 70462306a36Sopenharmony_ci if (rdev->family >= CHIP_R600) 70562306a36Sopenharmony_ci reg = RREG32(R600_CONFIG_MEMSIZE); 70662306a36Sopenharmony_ci else 70762306a36Sopenharmony_ci reg = RREG32(RADEON_CONFIG_MEMSIZE); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (reg) 71062306a36Sopenharmony_ci return true; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return false; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci/** 71762306a36Sopenharmony_ci * radeon_update_bandwidth_info - update display bandwidth params 71862306a36Sopenharmony_ci * 71962306a36Sopenharmony_ci * @rdev: radeon_device pointer 72062306a36Sopenharmony_ci * 72162306a36Sopenharmony_ci * Used when sclk/mclk are switched or display modes are set. 72262306a36Sopenharmony_ci * params are used to calculate display watermarks (all asics) 72362306a36Sopenharmony_ci */ 72462306a36Sopenharmony_civoid radeon_update_bandwidth_info(struct radeon_device *rdev) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci fixed20_12 a; 72762306a36Sopenharmony_ci u32 sclk = rdev->pm.current_sclk; 72862306a36Sopenharmony_ci u32 mclk = rdev->pm.current_mclk; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* sclk/mclk in Mhz */ 73162306a36Sopenharmony_ci a.full = dfixed_const(100); 73262306a36Sopenharmony_ci rdev->pm.sclk.full = dfixed_const(sclk); 73362306a36Sopenharmony_ci rdev->pm.sclk.full = dfixed_div(rdev->pm.sclk, a); 73462306a36Sopenharmony_ci rdev->pm.mclk.full = dfixed_const(mclk); 73562306a36Sopenharmony_ci rdev->pm.mclk.full = dfixed_div(rdev->pm.mclk, a); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) { 73862306a36Sopenharmony_ci a.full = dfixed_const(16); 73962306a36Sopenharmony_ci /* core_bandwidth = sclk(Mhz) * 16 */ 74062306a36Sopenharmony_ci rdev->pm.core_bandwidth.full = dfixed_div(rdev->pm.sclk, a); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci/** 74562306a36Sopenharmony_ci * radeon_boot_test_post_card - check and possibly initialize the hw 74662306a36Sopenharmony_ci * 74762306a36Sopenharmony_ci * @rdev: radeon_device pointer 74862306a36Sopenharmony_ci * 74962306a36Sopenharmony_ci * Check if the asic is initialized and if not, attempt to initialize 75062306a36Sopenharmony_ci * it (all asics). 75162306a36Sopenharmony_ci * Returns true if initialized or false if not. 75262306a36Sopenharmony_ci */ 75362306a36Sopenharmony_cibool radeon_boot_test_post_card(struct radeon_device *rdev) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci if (radeon_card_posted(rdev)) 75662306a36Sopenharmony_ci return true; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (rdev->bios) { 75962306a36Sopenharmony_ci DRM_INFO("GPU not posted. posting now...\n"); 76062306a36Sopenharmony_ci if (rdev->is_atom_bios) 76162306a36Sopenharmony_ci atom_asic_init(rdev->mode_info.atom_context); 76262306a36Sopenharmony_ci else 76362306a36Sopenharmony_ci radeon_combios_asic_init(rdev->ddev); 76462306a36Sopenharmony_ci return true; 76562306a36Sopenharmony_ci } else { 76662306a36Sopenharmony_ci dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n"); 76762306a36Sopenharmony_ci return false; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/** 77262306a36Sopenharmony_ci * radeon_dummy_page_init - init dummy page used by the driver 77362306a36Sopenharmony_ci * 77462306a36Sopenharmony_ci * @rdev: radeon_device pointer 77562306a36Sopenharmony_ci * 77662306a36Sopenharmony_ci * Allocate the dummy page used by the driver (all asics). 77762306a36Sopenharmony_ci * This dummy page is used by the driver as a filler for gart entries 77862306a36Sopenharmony_ci * when pages are taken out of the GART 77962306a36Sopenharmony_ci * Returns 0 on sucess, -ENOMEM on failure. 78062306a36Sopenharmony_ci */ 78162306a36Sopenharmony_ciint radeon_dummy_page_init(struct radeon_device *rdev) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci if (rdev->dummy_page.page) 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci rdev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO); 78662306a36Sopenharmony_ci if (rdev->dummy_page.page == NULL) 78762306a36Sopenharmony_ci return -ENOMEM; 78862306a36Sopenharmony_ci rdev->dummy_page.addr = dma_map_page(&rdev->pdev->dev, rdev->dummy_page.page, 78962306a36Sopenharmony_ci 0, PAGE_SIZE, DMA_BIDIRECTIONAL); 79062306a36Sopenharmony_ci if (dma_mapping_error(&rdev->pdev->dev, rdev->dummy_page.addr)) { 79162306a36Sopenharmony_ci dev_err(&rdev->pdev->dev, "Failed to DMA MAP the dummy page\n"); 79262306a36Sopenharmony_ci __free_page(rdev->dummy_page.page); 79362306a36Sopenharmony_ci rdev->dummy_page.page = NULL; 79462306a36Sopenharmony_ci return -ENOMEM; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci rdev->dummy_page.entry = radeon_gart_get_page_entry(rdev->dummy_page.addr, 79762306a36Sopenharmony_ci RADEON_GART_PAGE_DUMMY); 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci/** 80262306a36Sopenharmony_ci * radeon_dummy_page_fini - free dummy page used by the driver 80362306a36Sopenharmony_ci * 80462306a36Sopenharmony_ci * @rdev: radeon_device pointer 80562306a36Sopenharmony_ci * 80662306a36Sopenharmony_ci * Frees the dummy page used by the driver (all asics). 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_civoid radeon_dummy_page_fini(struct radeon_device *rdev) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci if (rdev->dummy_page.page == NULL) 81162306a36Sopenharmony_ci return; 81262306a36Sopenharmony_ci dma_unmap_page(&rdev->pdev->dev, rdev->dummy_page.addr, PAGE_SIZE, 81362306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 81462306a36Sopenharmony_ci __free_page(rdev->dummy_page.page); 81562306a36Sopenharmony_ci rdev->dummy_page.page = NULL; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci/* ATOM accessor methods */ 82062306a36Sopenharmony_ci/* 82162306a36Sopenharmony_ci * ATOM is an interpreted byte code stored in tables in the vbios. The 82262306a36Sopenharmony_ci * driver registers callbacks to access registers and the interpreter 82362306a36Sopenharmony_ci * in the driver parses the tables and executes then to program specific 82462306a36Sopenharmony_ci * actions (set display modes, asic init, etc.). See radeon_atombios.c, 82562306a36Sopenharmony_ci * atombios.h, and atom.c 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci/** 82962306a36Sopenharmony_ci * cail_pll_read - read PLL register 83062306a36Sopenharmony_ci * 83162306a36Sopenharmony_ci * @info: atom card_info pointer 83262306a36Sopenharmony_ci * @reg: PLL register offset 83362306a36Sopenharmony_ci * 83462306a36Sopenharmony_ci * Provides a PLL register accessor for the atom interpreter (r4xx+). 83562306a36Sopenharmony_ci * Returns the value of the PLL register. 83662306a36Sopenharmony_ci */ 83762306a36Sopenharmony_cistatic uint32_t cail_pll_read(struct card_info *info, uint32_t reg) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci struct radeon_device *rdev = info->dev->dev_private; 84062306a36Sopenharmony_ci uint32_t r; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci r = rdev->pll_rreg(rdev, reg); 84362306a36Sopenharmony_ci return r; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci/** 84762306a36Sopenharmony_ci * cail_pll_write - write PLL register 84862306a36Sopenharmony_ci * 84962306a36Sopenharmony_ci * @info: atom card_info pointer 85062306a36Sopenharmony_ci * @reg: PLL register offset 85162306a36Sopenharmony_ci * @val: value to write to the pll register 85262306a36Sopenharmony_ci * 85362306a36Sopenharmony_ci * Provides a PLL register accessor for the atom interpreter (r4xx+). 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_cistatic void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci struct radeon_device *rdev = info->dev->dev_private; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci rdev->pll_wreg(rdev, reg, val); 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci/** 86362306a36Sopenharmony_ci * cail_mc_read - read MC (Memory Controller) register 86462306a36Sopenharmony_ci * 86562306a36Sopenharmony_ci * @info: atom card_info pointer 86662306a36Sopenharmony_ci * @reg: MC register offset 86762306a36Sopenharmony_ci * 86862306a36Sopenharmony_ci * Provides an MC register accessor for the atom interpreter (r4xx+). 86962306a36Sopenharmony_ci * Returns the value of the MC register. 87062306a36Sopenharmony_ci */ 87162306a36Sopenharmony_cistatic uint32_t cail_mc_read(struct card_info *info, uint32_t reg) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct radeon_device *rdev = info->dev->dev_private; 87462306a36Sopenharmony_ci uint32_t r; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci r = rdev->mc_rreg(rdev, reg); 87762306a36Sopenharmony_ci return r; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci/** 88162306a36Sopenharmony_ci * cail_mc_write - write MC (Memory Controller) register 88262306a36Sopenharmony_ci * 88362306a36Sopenharmony_ci * @info: atom card_info pointer 88462306a36Sopenharmony_ci * @reg: MC register offset 88562306a36Sopenharmony_ci * @val: value to write to the pll register 88662306a36Sopenharmony_ci * 88762306a36Sopenharmony_ci * Provides a MC register accessor for the atom interpreter (r4xx+). 88862306a36Sopenharmony_ci */ 88962306a36Sopenharmony_cistatic void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci struct radeon_device *rdev = info->dev->dev_private; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci rdev->mc_wreg(rdev, reg, val); 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci/** 89762306a36Sopenharmony_ci * cail_reg_write - write MMIO register 89862306a36Sopenharmony_ci * 89962306a36Sopenharmony_ci * @info: atom card_info pointer 90062306a36Sopenharmony_ci * @reg: MMIO register offset 90162306a36Sopenharmony_ci * @val: value to write to the pll register 90262306a36Sopenharmony_ci * 90362306a36Sopenharmony_ci * Provides a MMIO register accessor for the atom interpreter (r4xx+). 90462306a36Sopenharmony_ci */ 90562306a36Sopenharmony_cistatic void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci struct radeon_device *rdev = info->dev->dev_private; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci WREG32(reg*4, val); 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci/** 91362306a36Sopenharmony_ci * cail_reg_read - read MMIO register 91462306a36Sopenharmony_ci * 91562306a36Sopenharmony_ci * @info: atom card_info pointer 91662306a36Sopenharmony_ci * @reg: MMIO register offset 91762306a36Sopenharmony_ci * 91862306a36Sopenharmony_ci * Provides an MMIO register accessor for the atom interpreter (r4xx+). 91962306a36Sopenharmony_ci * Returns the value of the MMIO register. 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_cistatic uint32_t cail_reg_read(struct card_info *info, uint32_t reg) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct radeon_device *rdev = info->dev->dev_private; 92462306a36Sopenharmony_ci uint32_t r; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci r = RREG32(reg*4); 92762306a36Sopenharmony_ci return r; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci/** 93162306a36Sopenharmony_ci * cail_ioreg_write - write IO register 93262306a36Sopenharmony_ci * 93362306a36Sopenharmony_ci * @info: atom card_info pointer 93462306a36Sopenharmony_ci * @reg: IO register offset 93562306a36Sopenharmony_ci * @val: value to write to the pll register 93662306a36Sopenharmony_ci * 93762306a36Sopenharmony_ci * Provides a IO register accessor for the atom interpreter (r4xx+). 93862306a36Sopenharmony_ci */ 93962306a36Sopenharmony_cistatic void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct radeon_device *rdev = info->dev->dev_private; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci WREG32_IO(reg*4, val); 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci/** 94762306a36Sopenharmony_ci * cail_ioreg_read - read IO register 94862306a36Sopenharmony_ci * 94962306a36Sopenharmony_ci * @info: atom card_info pointer 95062306a36Sopenharmony_ci * @reg: IO register offset 95162306a36Sopenharmony_ci * 95262306a36Sopenharmony_ci * Provides an IO register accessor for the atom interpreter (r4xx+). 95362306a36Sopenharmony_ci * Returns the value of the IO register. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_cistatic uint32_t cail_ioreg_read(struct card_info *info, uint32_t reg) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci struct radeon_device *rdev = info->dev->dev_private; 95862306a36Sopenharmony_ci uint32_t r; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci r = RREG32_IO(reg*4); 96162306a36Sopenharmony_ci return r; 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci/** 96562306a36Sopenharmony_ci * radeon_atombios_init - init the driver info and callbacks for atombios 96662306a36Sopenharmony_ci * 96762306a36Sopenharmony_ci * @rdev: radeon_device pointer 96862306a36Sopenharmony_ci * 96962306a36Sopenharmony_ci * Initializes the driver info and register access callbacks for the 97062306a36Sopenharmony_ci * ATOM interpreter (r4xx+). 97162306a36Sopenharmony_ci * Returns 0 on sucess, -ENOMEM on failure. 97262306a36Sopenharmony_ci * Called at driver startup. 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_ciint radeon_atombios_init(struct radeon_device *rdev) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci struct card_info *atom_card_info = 97762306a36Sopenharmony_ci kzalloc(sizeof(struct card_info), GFP_KERNEL); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (!atom_card_info) 98062306a36Sopenharmony_ci return -ENOMEM; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci rdev->mode_info.atom_card_info = atom_card_info; 98362306a36Sopenharmony_ci atom_card_info->dev = rdev->ddev; 98462306a36Sopenharmony_ci atom_card_info->reg_read = cail_reg_read; 98562306a36Sopenharmony_ci atom_card_info->reg_write = cail_reg_write; 98662306a36Sopenharmony_ci /* needed for iio ops */ 98762306a36Sopenharmony_ci if (rdev->rio_mem) { 98862306a36Sopenharmony_ci atom_card_info->ioreg_read = cail_ioreg_read; 98962306a36Sopenharmony_ci atom_card_info->ioreg_write = cail_ioreg_write; 99062306a36Sopenharmony_ci } else { 99162306a36Sopenharmony_ci DRM_ERROR("Unable to find PCI I/O BAR; using MMIO for ATOM IIO\n"); 99262306a36Sopenharmony_ci atom_card_info->ioreg_read = cail_reg_read; 99362306a36Sopenharmony_ci atom_card_info->ioreg_write = cail_reg_write; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci atom_card_info->mc_read = cail_mc_read; 99662306a36Sopenharmony_ci atom_card_info->mc_write = cail_mc_write; 99762306a36Sopenharmony_ci atom_card_info->pll_read = cail_pll_read; 99862306a36Sopenharmony_ci atom_card_info->pll_write = cail_pll_write; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci rdev->mode_info.atom_context = atom_parse(atom_card_info, rdev->bios); 100162306a36Sopenharmony_ci if (!rdev->mode_info.atom_context) { 100262306a36Sopenharmony_ci radeon_atombios_fini(rdev); 100362306a36Sopenharmony_ci return -ENOMEM; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci mutex_init(&rdev->mode_info.atom_context->mutex); 100762306a36Sopenharmony_ci mutex_init(&rdev->mode_info.atom_context->scratch_mutex); 100862306a36Sopenharmony_ci radeon_atom_initialize_bios_scratch_regs(rdev->ddev); 100962306a36Sopenharmony_ci atom_allocate_fb_scratch(rdev->mode_info.atom_context); 101062306a36Sopenharmony_ci return 0; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci/** 101462306a36Sopenharmony_ci * radeon_atombios_fini - free the driver info and callbacks for atombios 101562306a36Sopenharmony_ci * 101662306a36Sopenharmony_ci * @rdev: radeon_device pointer 101762306a36Sopenharmony_ci * 101862306a36Sopenharmony_ci * Frees the driver info and register access callbacks for the ATOM 101962306a36Sopenharmony_ci * interpreter (r4xx+). 102062306a36Sopenharmony_ci * Called at driver shutdown. 102162306a36Sopenharmony_ci */ 102262306a36Sopenharmony_civoid radeon_atombios_fini(struct radeon_device *rdev) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci if (rdev->mode_info.atom_context) { 102562306a36Sopenharmony_ci kfree(rdev->mode_info.atom_context->scratch); 102662306a36Sopenharmony_ci kfree(rdev->mode_info.atom_context->iio); 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci kfree(rdev->mode_info.atom_context); 102962306a36Sopenharmony_ci rdev->mode_info.atom_context = NULL; 103062306a36Sopenharmony_ci kfree(rdev->mode_info.atom_card_info); 103162306a36Sopenharmony_ci rdev->mode_info.atom_card_info = NULL; 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci/* COMBIOS */ 103562306a36Sopenharmony_ci/* 103662306a36Sopenharmony_ci * COMBIOS is the bios format prior to ATOM. It provides 103762306a36Sopenharmony_ci * command tables similar to ATOM, but doesn't have a unified 103862306a36Sopenharmony_ci * parser. See radeon_combios.c 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci/** 104262306a36Sopenharmony_ci * radeon_combios_init - init the driver info for combios 104362306a36Sopenharmony_ci * 104462306a36Sopenharmony_ci * @rdev: radeon_device pointer 104562306a36Sopenharmony_ci * 104662306a36Sopenharmony_ci * Initializes the driver info for combios (r1xx-r3xx). 104762306a36Sopenharmony_ci * Returns 0 on sucess. 104862306a36Sopenharmony_ci * Called at driver startup. 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_ciint radeon_combios_init(struct radeon_device *rdev) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci radeon_combios_initialize_bios_scratch_regs(rdev->ddev); 105362306a36Sopenharmony_ci return 0; 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci/** 105762306a36Sopenharmony_ci * radeon_combios_fini - free the driver info for combios 105862306a36Sopenharmony_ci * 105962306a36Sopenharmony_ci * @rdev: radeon_device pointer 106062306a36Sopenharmony_ci * 106162306a36Sopenharmony_ci * Frees the driver info for combios (r1xx-r3xx). 106262306a36Sopenharmony_ci * Called at driver shutdown. 106362306a36Sopenharmony_ci */ 106462306a36Sopenharmony_civoid radeon_combios_fini(struct radeon_device *rdev) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci/* if we get transitioned to only one device, take VGA back */ 106962306a36Sopenharmony_ci/** 107062306a36Sopenharmony_ci * radeon_vga_set_decode - enable/disable vga decode 107162306a36Sopenharmony_ci * 107262306a36Sopenharmony_ci * @pdev: PCI device 107362306a36Sopenharmony_ci * @state: enable/disable vga decode 107462306a36Sopenharmony_ci * 107562306a36Sopenharmony_ci * Enable/disable vga decode (all asics). 107662306a36Sopenharmony_ci * Returns VGA resource flags. 107762306a36Sopenharmony_ci */ 107862306a36Sopenharmony_cistatic unsigned int radeon_vga_set_decode(struct pci_dev *pdev, bool state) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 108162306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 108262306a36Sopenharmony_ci radeon_vga_set_state(rdev, state); 108362306a36Sopenharmony_ci if (state) 108462306a36Sopenharmony_ci return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | 108562306a36Sopenharmony_ci VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 108662306a36Sopenharmony_ci else 108762306a36Sopenharmony_ci return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci/** 109162306a36Sopenharmony_ci * radeon_gart_size_auto - Determine a sensible default GART size 109262306a36Sopenharmony_ci * according to ASIC family. 109362306a36Sopenharmony_ci * 109462306a36Sopenharmony_ci * @family: ASIC family name 109562306a36Sopenharmony_ci */ 109662306a36Sopenharmony_cistatic int radeon_gart_size_auto(enum radeon_family family) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci /* default to a larger gart size on newer asics */ 109962306a36Sopenharmony_ci if (family >= CHIP_TAHITI) 110062306a36Sopenharmony_ci return 2048; 110162306a36Sopenharmony_ci else if (family >= CHIP_RV770) 110262306a36Sopenharmony_ci return 1024; 110362306a36Sopenharmony_ci else 110462306a36Sopenharmony_ci return 512; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci/** 110862306a36Sopenharmony_ci * radeon_check_arguments - validate module params 110962306a36Sopenharmony_ci * 111062306a36Sopenharmony_ci * @rdev: radeon_device pointer 111162306a36Sopenharmony_ci * 111262306a36Sopenharmony_ci * Validates certain module parameters and updates 111362306a36Sopenharmony_ci * the associated values used by the driver (all asics). 111462306a36Sopenharmony_ci */ 111562306a36Sopenharmony_cistatic void radeon_check_arguments(struct radeon_device *rdev) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci /* vramlimit must be a power of two */ 111862306a36Sopenharmony_ci if (radeon_vram_limit != 0 && !is_power_of_2(radeon_vram_limit)) { 111962306a36Sopenharmony_ci dev_warn(rdev->dev, "vram limit (%d) must be a power of 2\n", 112062306a36Sopenharmony_ci radeon_vram_limit); 112162306a36Sopenharmony_ci radeon_vram_limit = 0; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (radeon_gart_size == -1) { 112562306a36Sopenharmony_ci radeon_gart_size = radeon_gart_size_auto(rdev->family); 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci /* gtt size must be power of two and greater or equal to 32M */ 112862306a36Sopenharmony_ci if (radeon_gart_size < 32) { 112962306a36Sopenharmony_ci dev_warn(rdev->dev, "gart size (%d) too small\n", 113062306a36Sopenharmony_ci radeon_gart_size); 113162306a36Sopenharmony_ci radeon_gart_size = radeon_gart_size_auto(rdev->family); 113262306a36Sopenharmony_ci } else if (!is_power_of_2(radeon_gart_size)) { 113362306a36Sopenharmony_ci dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n", 113462306a36Sopenharmony_ci radeon_gart_size); 113562306a36Sopenharmony_ci radeon_gart_size = radeon_gart_size_auto(rdev->family); 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci rdev->mc.gtt_size = (uint64_t)radeon_gart_size << 20; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* AGP mode can only be -1, 1, 2, 4, 8 */ 114062306a36Sopenharmony_ci switch (radeon_agpmode) { 114162306a36Sopenharmony_ci case -1: 114262306a36Sopenharmony_ci case 0: 114362306a36Sopenharmony_ci case 1: 114462306a36Sopenharmony_ci case 2: 114562306a36Sopenharmony_ci case 4: 114662306a36Sopenharmony_ci case 8: 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci default: 114962306a36Sopenharmony_ci dev_warn(rdev->dev, "invalid AGP mode %d (valid mode: " 115062306a36Sopenharmony_ci "-1, 0, 1, 2, 4, 8)\n", radeon_agpmode); 115162306a36Sopenharmony_ci radeon_agpmode = 0; 115262306a36Sopenharmony_ci break; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci if (!is_power_of_2(radeon_vm_size)) { 115662306a36Sopenharmony_ci dev_warn(rdev->dev, "VM size (%d) must be a power of 2\n", 115762306a36Sopenharmony_ci radeon_vm_size); 115862306a36Sopenharmony_ci radeon_vm_size = 4; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (radeon_vm_size < 1) { 116262306a36Sopenharmony_ci dev_warn(rdev->dev, "VM size (%d) too small, min is 1GB\n", 116362306a36Sopenharmony_ci radeon_vm_size); 116462306a36Sopenharmony_ci radeon_vm_size = 4; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci /* 116862306a36Sopenharmony_ci * Max GPUVM size for Cayman, SI and CI are 40 bits. 116962306a36Sopenharmony_ci */ 117062306a36Sopenharmony_ci if (radeon_vm_size > 1024) { 117162306a36Sopenharmony_ci dev_warn(rdev->dev, "VM size (%d) too large, max is 1TB\n", 117262306a36Sopenharmony_ci radeon_vm_size); 117362306a36Sopenharmony_ci radeon_vm_size = 4; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci /* defines number of bits in page table versus page directory, 117762306a36Sopenharmony_ci * a page is 4KB so we have 12 bits offset, minimum 9 bits in the 117862306a36Sopenharmony_ci * page table and the remaining bits are in the page directory */ 117962306a36Sopenharmony_ci if (radeon_vm_block_size == -1) { 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* Total bits covered by PD + PTs */ 118262306a36Sopenharmony_ci unsigned bits = ilog2(radeon_vm_size) + 18; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci /* Make sure the PD is 4K in size up to 8GB address space. 118562306a36Sopenharmony_ci Above that split equal between PD and PTs */ 118662306a36Sopenharmony_ci if (radeon_vm_size <= 8) 118762306a36Sopenharmony_ci radeon_vm_block_size = bits - 9; 118862306a36Sopenharmony_ci else 118962306a36Sopenharmony_ci radeon_vm_block_size = (bits + 3) / 2; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci } else if (radeon_vm_block_size < 9) { 119262306a36Sopenharmony_ci dev_warn(rdev->dev, "VM page table size (%d) too small\n", 119362306a36Sopenharmony_ci radeon_vm_block_size); 119462306a36Sopenharmony_ci radeon_vm_block_size = 9; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (radeon_vm_block_size > 24 || 119862306a36Sopenharmony_ci (radeon_vm_size * 1024) < (1ull << radeon_vm_block_size)) { 119962306a36Sopenharmony_ci dev_warn(rdev->dev, "VM page table size (%d) too large\n", 120062306a36Sopenharmony_ci radeon_vm_block_size); 120162306a36Sopenharmony_ci radeon_vm_block_size = 9; 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci} 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci/** 120662306a36Sopenharmony_ci * radeon_switcheroo_set_state - set switcheroo state 120762306a36Sopenharmony_ci * 120862306a36Sopenharmony_ci * @pdev: pci dev pointer 120962306a36Sopenharmony_ci * @state: vga_switcheroo state 121062306a36Sopenharmony_ci * 121162306a36Sopenharmony_ci * Callback for the switcheroo driver. Suspends or resumes 121262306a36Sopenharmony_ci * the asics before or after it is powered up using ACPI methods. 121362306a36Sopenharmony_ci */ 121462306a36Sopenharmony_cistatic void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci if (radeon_is_px(dev) && state == VGA_SWITCHEROO_OFF) 121962306a36Sopenharmony_ci return; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (state == VGA_SWITCHEROO_ON) { 122262306a36Sopenharmony_ci pr_info("radeon: switched on\n"); 122362306a36Sopenharmony_ci /* don't suspend or resume card normally */ 122462306a36Sopenharmony_ci dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci radeon_resume_kms(dev, true, true); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci dev->switch_power_state = DRM_SWITCH_POWER_ON; 122962306a36Sopenharmony_ci drm_kms_helper_poll_enable(dev); 123062306a36Sopenharmony_ci } else { 123162306a36Sopenharmony_ci pr_info("radeon: switched off\n"); 123262306a36Sopenharmony_ci drm_kms_helper_poll_disable(dev); 123362306a36Sopenharmony_ci dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; 123462306a36Sopenharmony_ci radeon_suspend_kms(dev, true, true, false); 123562306a36Sopenharmony_ci dev->switch_power_state = DRM_SWITCH_POWER_OFF; 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci/** 124062306a36Sopenharmony_ci * radeon_switcheroo_can_switch - see if switcheroo state can change 124162306a36Sopenharmony_ci * 124262306a36Sopenharmony_ci * @pdev: pci dev pointer 124362306a36Sopenharmony_ci * 124462306a36Sopenharmony_ci * Callback for the switcheroo driver. Check of the switcheroo 124562306a36Sopenharmony_ci * state can be changed. 124662306a36Sopenharmony_ci * Returns true if the state can be changed, false if not. 124762306a36Sopenharmony_ci */ 124862306a36Sopenharmony_cistatic bool radeon_switcheroo_can_switch(struct pci_dev *pdev) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* 125362306a36Sopenharmony_ci * FIXME: open_count is protected by drm_global_mutex but that would lead to 125462306a36Sopenharmony_ci * locking inversion with the driver load path. And the access here is 125562306a36Sopenharmony_ci * completely racy anyway. So don't bother with locking for now. 125662306a36Sopenharmony_ci */ 125762306a36Sopenharmony_ci return atomic_read(&dev->open_count) == 0; 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { 126162306a36Sopenharmony_ci .set_gpu_state = radeon_switcheroo_set_state, 126262306a36Sopenharmony_ci .reprobe = NULL, 126362306a36Sopenharmony_ci .can_switch = radeon_switcheroo_can_switch, 126462306a36Sopenharmony_ci}; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci/** 126762306a36Sopenharmony_ci * radeon_device_init - initialize the driver 126862306a36Sopenharmony_ci * 126962306a36Sopenharmony_ci * @rdev: radeon_device pointer 127062306a36Sopenharmony_ci * @ddev: drm dev pointer 127162306a36Sopenharmony_ci * @pdev: pci dev pointer 127262306a36Sopenharmony_ci * @flags: driver flags 127362306a36Sopenharmony_ci * 127462306a36Sopenharmony_ci * Initializes the driver info and hw (all asics). 127562306a36Sopenharmony_ci * Returns 0 for success or an error on failure. 127662306a36Sopenharmony_ci * Called at driver startup. 127762306a36Sopenharmony_ci */ 127862306a36Sopenharmony_ciint radeon_device_init(struct radeon_device *rdev, 127962306a36Sopenharmony_ci struct drm_device *ddev, 128062306a36Sopenharmony_ci struct pci_dev *pdev, 128162306a36Sopenharmony_ci uint32_t flags) 128262306a36Sopenharmony_ci{ 128362306a36Sopenharmony_ci int r, i; 128462306a36Sopenharmony_ci int dma_bits; 128562306a36Sopenharmony_ci bool runtime = false; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci rdev->shutdown = false; 128862306a36Sopenharmony_ci rdev->dev = &pdev->dev; 128962306a36Sopenharmony_ci rdev->ddev = ddev; 129062306a36Sopenharmony_ci rdev->pdev = pdev; 129162306a36Sopenharmony_ci rdev->flags = flags; 129262306a36Sopenharmony_ci rdev->family = flags & RADEON_FAMILY_MASK; 129362306a36Sopenharmony_ci rdev->is_atom_bios = false; 129462306a36Sopenharmony_ci rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT; 129562306a36Sopenharmony_ci rdev->mc.gtt_size = 512 * 1024 * 1024; 129662306a36Sopenharmony_ci rdev->accel_working = false; 129762306a36Sopenharmony_ci /* set up ring ids */ 129862306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; i++) { 129962306a36Sopenharmony_ci rdev->ring[i].idx = i; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci rdev->fence_context = dma_fence_context_alloc(RADEON_NUM_RINGS); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X 0x%02X).\n", 130462306a36Sopenharmony_ci radeon_family_name[rdev->family], pdev->vendor, pdev->device, 130562306a36Sopenharmony_ci pdev->subsystem_vendor, pdev->subsystem_device, pdev->revision); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci /* mutex initialization are all done here so we 130862306a36Sopenharmony_ci * can recall function without having locking issues */ 130962306a36Sopenharmony_ci mutex_init(&rdev->ring_lock); 131062306a36Sopenharmony_ci mutex_init(&rdev->dc_hw_i2c_mutex); 131162306a36Sopenharmony_ci atomic_set(&rdev->ih.lock, 0); 131262306a36Sopenharmony_ci mutex_init(&rdev->gem.mutex); 131362306a36Sopenharmony_ci mutex_init(&rdev->pm.mutex); 131462306a36Sopenharmony_ci mutex_init(&rdev->gpu_clock_mutex); 131562306a36Sopenharmony_ci mutex_init(&rdev->srbm_mutex); 131662306a36Sopenharmony_ci mutex_init(&rdev->audio.component_mutex); 131762306a36Sopenharmony_ci init_rwsem(&rdev->pm.mclk_lock); 131862306a36Sopenharmony_ci init_rwsem(&rdev->exclusive_lock); 131962306a36Sopenharmony_ci init_waitqueue_head(&rdev->irq.vblank_queue); 132062306a36Sopenharmony_ci r = radeon_gem_init(rdev); 132162306a36Sopenharmony_ci if (r) 132262306a36Sopenharmony_ci return r; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci radeon_check_arguments(rdev); 132562306a36Sopenharmony_ci /* Adjust VM size here. 132662306a36Sopenharmony_ci * Max GPUVM size for cayman+ is 40 bits. 132762306a36Sopenharmony_ci */ 132862306a36Sopenharmony_ci rdev->vm_manager.max_pfn = radeon_vm_size << 18; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci /* Set asic functions */ 133162306a36Sopenharmony_ci r = radeon_asic_init(rdev); 133262306a36Sopenharmony_ci if (r) 133362306a36Sopenharmony_ci return r; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* all of the newer IGP chips have an internal gart 133662306a36Sopenharmony_ci * However some rs4xx report as AGP, so remove that here. 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_ci if ((rdev->family >= CHIP_RS400) && 133962306a36Sopenharmony_ci (rdev->flags & RADEON_IS_IGP)) { 134062306a36Sopenharmony_ci rdev->flags &= ~RADEON_IS_AGP; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) { 134462306a36Sopenharmony_ci radeon_agp_disable(rdev); 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci /* Set the internal MC address mask 134862306a36Sopenharmony_ci * This is the max address of the GPU's 134962306a36Sopenharmony_ci * internal address space. 135062306a36Sopenharmony_ci */ 135162306a36Sopenharmony_ci if (rdev->family >= CHIP_CAYMAN) 135262306a36Sopenharmony_ci rdev->mc.mc_mask = 0xffffffffffULL; /* 40 bit MC */ 135362306a36Sopenharmony_ci else if (rdev->family >= CHIP_CEDAR) 135462306a36Sopenharmony_ci rdev->mc.mc_mask = 0xfffffffffULL; /* 36 bit MC */ 135562306a36Sopenharmony_ci else 135662306a36Sopenharmony_ci rdev->mc.mc_mask = 0xffffffffULL; /* 32 bit MC */ 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci /* set DMA mask. 135962306a36Sopenharmony_ci * PCIE - can handle 40-bits. 136062306a36Sopenharmony_ci * IGP - can handle 40-bits 136162306a36Sopenharmony_ci * AGP - generally dma32 is safest 136262306a36Sopenharmony_ci * PCI - dma32 for legacy pci gart, 40 bits on newer asics 136362306a36Sopenharmony_ci */ 136462306a36Sopenharmony_ci dma_bits = 40; 136562306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) 136662306a36Sopenharmony_ci dma_bits = 32; 136762306a36Sopenharmony_ci if ((rdev->flags & RADEON_IS_PCI) && 136862306a36Sopenharmony_ci (rdev->family <= CHIP_RS740)) 136962306a36Sopenharmony_ci dma_bits = 32; 137062306a36Sopenharmony_ci#ifdef CONFIG_PPC64 137162306a36Sopenharmony_ci if (rdev->family == CHIP_CEDAR) 137262306a36Sopenharmony_ci dma_bits = 32; 137362306a36Sopenharmony_ci#endif 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci r = dma_set_mask_and_coherent(&rdev->pdev->dev, DMA_BIT_MASK(dma_bits)); 137662306a36Sopenharmony_ci if (r) { 137762306a36Sopenharmony_ci pr_warn("radeon: No suitable DMA available\n"); 137862306a36Sopenharmony_ci return r; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci rdev->need_swiotlb = drm_need_swiotlb(dma_bits); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci /* Registers mapping */ 138362306a36Sopenharmony_ci /* TODO: block userspace mapping of io register */ 138462306a36Sopenharmony_ci spin_lock_init(&rdev->mmio_idx_lock); 138562306a36Sopenharmony_ci spin_lock_init(&rdev->smc_idx_lock); 138662306a36Sopenharmony_ci spin_lock_init(&rdev->pll_idx_lock); 138762306a36Sopenharmony_ci spin_lock_init(&rdev->mc_idx_lock); 138862306a36Sopenharmony_ci spin_lock_init(&rdev->pcie_idx_lock); 138962306a36Sopenharmony_ci spin_lock_init(&rdev->pciep_idx_lock); 139062306a36Sopenharmony_ci spin_lock_init(&rdev->pif_idx_lock); 139162306a36Sopenharmony_ci spin_lock_init(&rdev->cg_idx_lock); 139262306a36Sopenharmony_ci spin_lock_init(&rdev->uvd_idx_lock); 139362306a36Sopenharmony_ci spin_lock_init(&rdev->rcu_idx_lock); 139462306a36Sopenharmony_ci spin_lock_init(&rdev->didt_idx_lock); 139562306a36Sopenharmony_ci spin_lock_init(&rdev->end_idx_lock); 139662306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) { 139762306a36Sopenharmony_ci rdev->rmmio_base = pci_resource_start(rdev->pdev, 5); 139862306a36Sopenharmony_ci rdev->rmmio_size = pci_resource_len(rdev->pdev, 5); 139962306a36Sopenharmony_ci } else { 140062306a36Sopenharmony_ci rdev->rmmio_base = pci_resource_start(rdev->pdev, 2); 140162306a36Sopenharmony_ci rdev->rmmio_size = pci_resource_len(rdev->pdev, 2); 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size); 140462306a36Sopenharmony_ci if (rdev->rmmio == NULL) 140562306a36Sopenharmony_ci return -ENOMEM; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* doorbell bar mapping */ 140862306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 140962306a36Sopenharmony_ci radeon_doorbell_init(rdev); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci /* io port mapping */ 141262306a36Sopenharmony_ci for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 141362306a36Sopenharmony_ci if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) { 141462306a36Sopenharmony_ci rdev->rio_mem_size = pci_resource_len(rdev->pdev, i); 141562306a36Sopenharmony_ci rdev->rio_mem = pci_iomap(rdev->pdev, i, rdev->rio_mem_size); 141662306a36Sopenharmony_ci break; 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci if (rdev->rio_mem == NULL) 142062306a36Sopenharmony_ci DRM_ERROR("Unable to find PCI I/O BAR\n"); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PX) 142362306a36Sopenharmony_ci radeon_device_handle_px_quirks(rdev); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci /* if we have > 1 VGA cards, then disable the radeon VGA resources */ 142662306a36Sopenharmony_ci /* this will fail for cards that aren't VGA class devices, just 142762306a36Sopenharmony_ci * ignore it */ 142862306a36Sopenharmony_ci vga_client_register(rdev->pdev, radeon_vga_set_decode); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PX) 143162306a36Sopenharmony_ci runtime = true; 143262306a36Sopenharmony_ci if (!pci_is_thunderbolt_attached(rdev->pdev)) 143362306a36Sopenharmony_ci vga_switcheroo_register_client(rdev->pdev, 143462306a36Sopenharmony_ci &radeon_switcheroo_ops, runtime); 143562306a36Sopenharmony_ci if (runtime) 143662306a36Sopenharmony_ci vga_switcheroo_init_domain_pm_ops(rdev->dev, &rdev->vga_pm_domain); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci r = radeon_init(rdev); 143962306a36Sopenharmony_ci if (r) 144062306a36Sopenharmony_ci goto failed; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci radeon_gem_debugfs_init(rdev); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) { 144562306a36Sopenharmony_ci /* Acceleration not working on AGP card try again 144662306a36Sopenharmony_ci * with fallback to PCI or PCIE GART 144762306a36Sopenharmony_ci */ 144862306a36Sopenharmony_ci radeon_asic_reset(rdev); 144962306a36Sopenharmony_ci radeon_fini(rdev); 145062306a36Sopenharmony_ci radeon_agp_disable(rdev); 145162306a36Sopenharmony_ci r = radeon_init(rdev); 145262306a36Sopenharmony_ci if (r) 145362306a36Sopenharmony_ci goto failed; 145462306a36Sopenharmony_ci } 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci radeon_audio_component_init(rdev); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci r = radeon_ib_ring_tests(rdev); 145962306a36Sopenharmony_ci if (r) 146062306a36Sopenharmony_ci DRM_ERROR("ib ring test failed (%d).\n", r); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci /* 146362306a36Sopenharmony_ci * Turks/Thames GPU will freeze whole laptop if DPM is not restarted 146462306a36Sopenharmony_ci * after the CP ring have chew one packet at least. Hence here we stop 146562306a36Sopenharmony_ci * and restart DPM after the radeon_ib_ring_tests(). 146662306a36Sopenharmony_ci */ 146762306a36Sopenharmony_ci if (rdev->pm.dpm_enabled && 146862306a36Sopenharmony_ci (rdev->pm.pm_method == PM_METHOD_DPM) && 146962306a36Sopenharmony_ci (rdev->family == CHIP_TURKS) && 147062306a36Sopenharmony_ci (rdev->flags & RADEON_IS_MOBILITY)) { 147162306a36Sopenharmony_ci mutex_lock(&rdev->pm.mutex); 147262306a36Sopenharmony_ci radeon_dpm_disable(rdev); 147362306a36Sopenharmony_ci radeon_dpm_enable(rdev); 147462306a36Sopenharmony_ci mutex_unlock(&rdev->pm.mutex); 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci if ((radeon_testing & 1)) { 147862306a36Sopenharmony_ci if (rdev->accel_working) 147962306a36Sopenharmony_ci radeon_test_moves(rdev); 148062306a36Sopenharmony_ci else 148162306a36Sopenharmony_ci DRM_INFO("radeon: acceleration disabled, skipping move tests\n"); 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci if ((radeon_testing & 2)) { 148462306a36Sopenharmony_ci if (rdev->accel_working) 148562306a36Sopenharmony_ci radeon_test_syncing(rdev); 148662306a36Sopenharmony_ci else 148762306a36Sopenharmony_ci DRM_INFO("radeon: acceleration disabled, skipping sync tests\n"); 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci if (radeon_benchmarking) { 149062306a36Sopenharmony_ci if (rdev->accel_working) 149162306a36Sopenharmony_ci radeon_benchmark(rdev, radeon_benchmarking); 149262306a36Sopenharmony_ci else 149362306a36Sopenharmony_ci DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n"); 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci return 0; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_cifailed: 149862306a36Sopenharmony_ci /* balance pm_runtime_get_sync() in radeon_driver_unload_kms() */ 149962306a36Sopenharmony_ci if (radeon_is_px(ddev)) 150062306a36Sopenharmony_ci pm_runtime_put_noidle(ddev->dev); 150162306a36Sopenharmony_ci if (runtime) 150262306a36Sopenharmony_ci vga_switcheroo_fini_domain_pm_ops(rdev->dev); 150362306a36Sopenharmony_ci return r; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci/** 150762306a36Sopenharmony_ci * radeon_device_fini - tear down the driver 150862306a36Sopenharmony_ci * 150962306a36Sopenharmony_ci * @rdev: radeon_device pointer 151062306a36Sopenharmony_ci * 151162306a36Sopenharmony_ci * Tear down the driver info (all asics). 151262306a36Sopenharmony_ci * Called at driver shutdown. 151362306a36Sopenharmony_ci */ 151462306a36Sopenharmony_civoid radeon_device_fini(struct radeon_device *rdev) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci DRM_INFO("radeon: finishing device.\n"); 151762306a36Sopenharmony_ci rdev->shutdown = true; 151862306a36Sopenharmony_ci /* evict vram memory */ 151962306a36Sopenharmony_ci radeon_bo_evict_vram(rdev); 152062306a36Sopenharmony_ci radeon_audio_component_fini(rdev); 152162306a36Sopenharmony_ci radeon_fini(rdev); 152262306a36Sopenharmony_ci if (!pci_is_thunderbolt_attached(rdev->pdev)) 152362306a36Sopenharmony_ci vga_switcheroo_unregister_client(rdev->pdev); 152462306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PX) 152562306a36Sopenharmony_ci vga_switcheroo_fini_domain_pm_ops(rdev->dev); 152662306a36Sopenharmony_ci vga_client_unregister(rdev->pdev); 152762306a36Sopenharmony_ci if (rdev->rio_mem) 152862306a36Sopenharmony_ci pci_iounmap(rdev->pdev, rdev->rio_mem); 152962306a36Sopenharmony_ci rdev->rio_mem = NULL; 153062306a36Sopenharmony_ci iounmap(rdev->rmmio); 153162306a36Sopenharmony_ci rdev->rmmio = NULL; 153262306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 153362306a36Sopenharmony_ci radeon_doorbell_fini(rdev); 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci/* 153862306a36Sopenharmony_ci * Suspend & resume. 153962306a36Sopenharmony_ci */ 154062306a36Sopenharmony_ci/* 154162306a36Sopenharmony_ci * radeon_suspend_kms - initiate device suspend 154262306a36Sopenharmony_ci * 154362306a36Sopenharmony_ci * Puts the hw in the suspend state (all asics). 154462306a36Sopenharmony_ci * Returns 0 for success or an error on failure. 154562306a36Sopenharmony_ci * Called at driver suspend. 154662306a36Sopenharmony_ci */ 154762306a36Sopenharmony_ciint radeon_suspend_kms(struct drm_device *dev, bool suspend, 154862306a36Sopenharmony_ci bool fbcon, bool freeze) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci struct radeon_device *rdev; 155162306a36Sopenharmony_ci struct pci_dev *pdev; 155262306a36Sopenharmony_ci struct drm_crtc *crtc; 155362306a36Sopenharmony_ci struct drm_connector *connector; 155462306a36Sopenharmony_ci int i, r; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (dev == NULL || dev->dev_private == NULL) { 155762306a36Sopenharmony_ci return -ENODEV; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci rdev = dev->dev_private; 156162306a36Sopenharmony_ci pdev = to_pci_dev(dev->dev); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 156462306a36Sopenharmony_ci return 0; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci drm_kms_helper_poll_disable(dev); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci drm_modeset_lock_all(dev); 156962306a36Sopenharmony_ci /* turn off display hw */ 157062306a36Sopenharmony_ci list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 157162306a36Sopenharmony_ci drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci drm_modeset_unlock_all(dev); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci /* unpin the front buffers and cursors */ 157662306a36Sopenharmony_ci list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 157762306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 157862306a36Sopenharmony_ci struct drm_framebuffer *fb = crtc->primary->fb; 157962306a36Sopenharmony_ci struct radeon_bo *robj; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (radeon_crtc->cursor_bo) { 158262306a36Sopenharmony_ci struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); 158362306a36Sopenharmony_ci r = radeon_bo_reserve(robj, false); 158462306a36Sopenharmony_ci if (r == 0) { 158562306a36Sopenharmony_ci radeon_bo_unpin(robj); 158662306a36Sopenharmony_ci radeon_bo_unreserve(robj); 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci if (fb == NULL || fb->obj[0] == NULL) { 159162306a36Sopenharmony_ci continue; 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci robj = gem_to_radeon_bo(fb->obj[0]); 159462306a36Sopenharmony_ci /* don't unpin kernel fb objects */ 159562306a36Sopenharmony_ci if (!radeon_fbdev_robj_is_fb(rdev, robj)) { 159662306a36Sopenharmony_ci r = radeon_bo_reserve(robj, false); 159762306a36Sopenharmony_ci if (r == 0) { 159862306a36Sopenharmony_ci radeon_bo_unpin(robj); 159962306a36Sopenharmony_ci radeon_bo_unreserve(robj); 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci /* evict vram memory */ 160462306a36Sopenharmony_ci radeon_bo_evict_vram(rdev); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* wait for gpu to finish processing current batch */ 160762306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; i++) { 160862306a36Sopenharmony_ci r = radeon_fence_wait_empty(rdev, i); 160962306a36Sopenharmony_ci if (r) { 161062306a36Sopenharmony_ci /* delay GPU reset to resume */ 161162306a36Sopenharmony_ci radeon_fence_driver_force_completion(rdev, i); 161262306a36Sopenharmony_ci } else { 161362306a36Sopenharmony_ci /* finish executing delayed work */ 161462306a36Sopenharmony_ci flush_delayed_work(&rdev->fence_drv[i].lockup_work); 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci radeon_save_bios_scratch_regs(rdev); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci radeon_suspend(rdev); 162162306a36Sopenharmony_ci radeon_hpd_fini(rdev); 162262306a36Sopenharmony_ci /* evict remaining vram memory 162362306a36Sopenharmony_ci * This second call to evict vram is to evict the gart page table 162462306a36Sopenharmony_ci * using the CPU. 162562306a36Sopenharmony_ci */ 162662306a36Sopenharmony_ci radeon_bo_evict_vram(rdev); 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci radeon_agp_suspend(rdev); 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci pci_save_state(pdev); 163162306a36Sopenharmony_ci if (freeze && rdev->family >= CHIP_CEDAR && !(rdev->flags & RADEON_IS_IGP)) { 163262306a36Sopenharmony_ci rdev->asic->asic_reset(rdev, true); 163362306a36Sopenharmony_ci pci_restore_state(pdev); 163462306a36Sopenharmony_ci } else if (suspend) { 163562306a36Sopenharmony_ci /* Shut down the device */ 163662306a36Sopenharmony_ci pci_disable_device(pdev); 163762306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci if (fbcon) { 164162306a36Sopenharmony_ci console_lock(); 164262306a36Sopenharmony_ci radeon_fbdev_set_suspend(rdev, 1); 164362306a36Sopenharmony_ci console_unlock(); 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci return 0; 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci/* 164962306a36Sopenharmony_ci * radeon_resume_kms - initiate device resume 165062306a36Sopenharmony_ci * 165162306a36Sopenharmony_ci * Bring the hw back to operating state (all asics). 165262306a36Sopenharmony_ci * Returns 0 for success or an error on failure. 165362306a36Sopenharmony_ci * Called at driver resume. 165462306a36Sopenharmony_ci */ 165562306a36Sopenharmony_ciint radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) 165662306a36Sopenharmony_ci{ 165762306a36Sopenharmony_ci struct drm_connector *connector; 165862306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 165962306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev->dev); 166062306a36Sopenharmony_ci struct drm_crtc *crtc; 166162306a36Sopenharmony_ci int r; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 166462306a36Sopenharmony_ci return 0; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci if (fbcon) { 166762306a36Sopenharmony_ci console_lock(); 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci if (resume) { 167062306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 167162306a36Sopenharmony_ci pci_restore_state(pdev); 167262306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 167362306a36Sopenharmony_ci if (fbcon) 167462306a36Sopenharmony_ci console_unlock(); 167562306a36Sopenharmony_ci return -1; 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci /* resume AGP if in use */ 167962306a36Sopenharmony_ci radeon_agp_resume(rdev); 168062306a36Sopenharmony_ci radeon_resume(rdev); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci r = radeon_ib_ring_tests(rdev); 168362306a36Sopenharmony_ci if (r) 168462306a36Sopenharmony_ci DRM_ERROR("ib ring test failed (%d).\n", r); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 168762306a36Sopenharmony_ci /* do dpm late init */ 168862306a36Sopenharmony_ci r = radeon_pm_late_init(rdev); 168962306a36Sopenharmony_ci if (r) { 169062306a36Sopenharmony_ci rdev->pm.dpm_enabled = false; 169162306a36Sopenharmony_ci DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci } else { 169462306a36Sopenharmony_ci /* resume old pm late */ 169562306a36Sopenharmony_ci radeon_pm_resume(rdev); 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci radeon_restore_bios_scratch_regs(rdev); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci /* pin cursors */ 170162306a36Sopenharmony_ci list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 170262306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci if (radeon_crtc->cursor_bo) { 170562306a36Sopenharmony_ci struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); 170662306a36Sopenharmony_ci r = radeon_bo_reserve(robj, false); 170762306a36Sopenharmony_ci if (r == 0) { 170862306a36Sopenharmony_ci /* Only 27 bit offset for legacy cursor */ 170962306a36Sopenharmony_ci r = radeon_bo_pin_restricted(robj, 171062306a36Sopenharmony_ci RADEON_GEM_DOMAIN_VRAM, 171162306a36Sopenharmony_ci ASIC_IS_AVIVO(rdev) ? 171262306a36Sopenharmony_ci 0 : 1 << 27, 171362306a36Sopenharmony_ci &radeon_crtc->cursor_addr); 171462306a36Sopenharmony_ci if (r != 0) 171562306a36Sopenharmony_ci DRM_ERROR("Failed to pin cursor BO (%d)\n", r); 171662306a36Sopenharmony_ci radeon_bo_unreserve(robj); 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci /* init dig PHYs, disp eng pll */ 172262306a36Sopenharmony_ci if (rdev->is_atom_bios) { 172362306a36Sopenharmony_ci radeon_atom_encoder_init(rdev); 172462306a36Sopenharmony_ci radeon_atom_disp_eng_pll_init(rdev); 172562306a36Sopenharmony_ci /* turn on the BL */ 172662306a36Sopenharmony_ci if (rdev->mode_info.bl_encoder) { 172762306a36Sopenharmony_ci u8 bl_level = radeon_get_backlight_level(rdev, 172862306a36Sopenharmony_ci rdev->mode_info.bl_encoder); 172962306a36Sopenharmony_ci radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, 173062306a36Sopenharmony_ci bl_level); 173162306a36Sopenharmony_ci } 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci /* reset hpd state */ 173462306a36Sopenharmony_ci radeon_hpd_init(rdev); 173562306a36Sopenharmony_ci /* blat the mode back in */ 173662306a36Sopenharmony_ci if (fbcon) { 173762306a36Sopenharmony_ci drm_helper_resume_force_mode(dev); 173862306a36Sopenharmony_ci /* turn on display hw */ 173962306a36Sopenharmony_ci drm_modeset_lock_all(dev); 174062306a36Sopenharmony_ci list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 174162306a36Sopenharmony_ci drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); 174262306a36Sopenharmony_ci } 174362306a36Sopenharmony_ci drm_modeset_unlock_all(dev); 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci drm_kms_helper_poll_enable(dev); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci /* set the power state here in case we are a PX system or headless */ 174962306a36Sopenharmony_ci if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 175062306a36Sopenharmony_ci radeon_pm_compute_clocks(rdev); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (fbcon) { 175362306a36Sopenharmony_ci radeon_fbdev_set_suspend(rdev, 0); 175462306a36Sopenharmony_ci console_unlock(); 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci return 0; 175862306a36Sopenharmony_ci} 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci/** 176162306a36Sopenharmony_ci * radeon_gpu_reset - reset the asic 176262306a36Sopenharmony_ci * 176362306a36Sopenharmony_ci * @rdev: radeon device pointer 176462306a36Sopenharmony_ci * 176562306a36Sopenharmony_ci * Attempt the reset the GPU if it has hung (all asics). 176662306a36Sopenharmony_ci * Returns 0 for success or an error on failure. 176762306a36Sopenharmony_ci */ 176862306a36Sopenharmony_ciint radeon_gpu_reset(struct radeon_device *rdev) 176962306a36Sopenharmony_ci{ 177062306a36Sopenharmony_ci unsigned ring_sizes[RADEON_NUM_RINGS]; 177162306a36Sopenharmony_ci uint32_t *ring_data[RADEON_NUM_RINGS]; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci bool saved = false; 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci int i, r; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci down_write(&rdev->exclusive_lock); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci if (!rdev->needs_reset) { 178062306a36Sopenharmony_ci up_write(&rdev->exclusive_lock); 178162306a36Sopenharmony_ci return 0; 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci atomic_inc(&rdev->gpu_reset_counter); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci radeon_save_bios_scratch_regs(rdev); 178762306a36Sopenharmony_ci radeon_suspend(rdev); 178862306a36Sopenharmony_ci radeon_hpd_fini(rdev); 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 179162306a36Sopenharmony_ci ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i], 179262306a36Sopenharmony_ci &ring_data[i]); 179362306a36Sopenharmony_ci if (ring_sizes[i]) { 179462306a36Sopenharmony_ci saved = true; 179562306a36Sopenharmony_ci dev_info(rdev->dev, "Saved %d dwords of commands " 179662306a36Sopenharmony_ci "on ring %d.\n", ring_sizes[i], i); 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci } 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci r = radeon_asic_reset(rdev); 180162306a36Sopenharmony_ci if (!r) { 180262306a36Sopenharmony_ci dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n"); 180362306a36Sopenharmony_ci radeon_resume(rdev); 180462306a36Sopenharmony_ci } 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci radeon_restore_bios_scratch_regs(rdev); 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 180962306a36Sopenharmony_ci if (!r && ring_data[i]) { 181062306a36Sopenharmony_ci radeon_ring_restore(rdev, &rdev->ring[i], 181162306a36Sopenharmony_ci ring_sizes[i], ring_data[i]); 181262306a36Sopenharmony_ci } else { 181362306a36Sopenharmony_ci radeon_fence_driver_force_completion(rdev, i); 181462306a36Sopenharmony_ci kfree(ring_data[i]); 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 181962306a36Sopenharmony_ci /* do dpm late init */ 182062306a36Sopenharmony_ci r = radeon_pm_late_init(rdev); 182162306a36Sopenharmony_ci if (r) { 182262306a36Sopenharmony_ci rdev->pm.dpm_enabled = false; 182362306a36Sopenharmony_ci DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); 182462306a36Sopenharmony_ci } 182562306a36Sopenharmony_ci } else { 182662306a36Sopenharmony_ci /* resume old pm late */ 182762306a36Sopenharmony_ci radeon_pm_resume(rdev); 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci /* init dig PHYs, disp eng pll */ 183162306a36Sopenharmony_ci if (rdev->is_atom_bios) { 183262306a36Sopenharmony_ci radeon_atom_encoder_init(rdev); 183362306a36Sopenharmony_ci radeon_atom_disp_eng_pll_init(rdev); 183462306a36Sopenharmony_ci /* turn on the BL */ 183562306a36Sopenharmony_ci if (rdev->mode_info.bl_encoder) { 183662306a36Sopenharmony_ci u8 bl_level = radeon_get_backlight_level(rdev, 183762306a36Sopenharmony_ci rdev->mode_info.bl_encoder); 183862306a36Sopenharmony_ci radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, 183962306a36Sopenharmony_ci bl_level); 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci } 184262306a36Sopenharmony_ci /* reset hpd state */ 184362306a36Sopenharmony_ci radeon_hpd_init(rdev); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci rdev->in_reset = true; 184662306a36Sopenharmony_ci rdev->needs_reset = false; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci downgrade_write(&rdev->exclusive_lock); 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci drm_helper_resume_force_mode(rdev->ddev); 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci /* set the power state here in case we are a PX system or headless */ 185362306a36Sopenharmony_ci if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 185462306a36Sopenharmony_ci radeon_pm_compute_clocks(rdev); 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci if (!r) { 185762306a36Sopenharmony_ci r = radeon_ib_ring_tests(rdev); 185862306a36Sopenharmony_ci if (r && saved) 185962306a36Sopenharmony_ci r = -EAGAIN; 186062306a36Sopenharmony_ci } else { 186162306a36Sopenharmony_ci /* bad news, how to tell it to userspace ? */ 186262306a36Sopenharmony_ci dev_info(rdev->dev, "GPU reset failed\n"); 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci rdev->needs_reset = r == -EAGAIN; 186662306a36Sopenharmony_ci rdev->in_reset = false; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 186962306a36Sopenharmony_ci return r; 187062306a36Sopenharmony_ci} 1871