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 "radeon.h" 3062306a36Sopenharmony_ci#include "radeon_asic.h" 3162306a36Sopenharmony_ci#include "atom.h" 3262306a36Sopenharmony_ci#include "r520d.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* This files gather functions specifics to: r520,rv530,rv560,rv570,r580 */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciint r520_mc_wait_for_idle(struct radeon_device *rdev) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci unsigned i; 3962306a36Sopenharmony_ci uint32_t tmp; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 4262306a36Sopenharmony_ci /* read MC_STATUS */ 4362306a36Sopenharmony_ci tmp = RREG32_MC(R520_MC_STATUS); 4462306a36Sopenharmony_ci if (tmp & R520_MC_STATUS_IDLE) { 4562306a36Sopenharmony_ci return 0; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci udelay(1); 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci return -1; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic void r520_gpu_init(struct radeon_device *rdev) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci unsigned pipe_select_current, gb_pipe_select, tmp; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci rv515_vga_render_disable(rdev); 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * DST_PIPE_CONFIG 0x170C 5962306a36Sopenharmony_ci * GB_TILE_CONFIG 0x4018 6062306a36Sopenharmony_ci * GB_FIFO_SIZE 0x4024 6162306a36Sopenharmony_ci * GB_PIPE_SELECT 0x402C 6262306a36Sopenharmony_ci * GB_PIPE_SELECT2 0x4124 6362306a36Sopenharmony_ci * Z_PIPE_SHIFT 0 6462306a36Sopenharmony_ci * Z_PIPE_MASK 0x000000003 6562306a36Sopenharmony_ci * GB_FIFO_SIZE2 0x4128 6662306a36Sopenharmony_ci * SC_SFIFO_SIZE_SHIFT 0 6762306a36Sopenharmony_ci * SC_SFIFO_SIZE_MASK 0x000000003 6862306a36Sopenharmony_ci * SC_MFIFO_SIZE_SHIFT 2 6962306a36Sopenharmony_ci * SC_MFIFO_SIZE_MASK 0x00000000C 7062306a36Sopenharmony_ci * FG_SFIFO_SIZE_SHIFT 4 7162306a36Sopenharmony_ci * FG_SFIFO_SIZE_MASK 0x000000030 7262306a36Sopenharmony_ci * ZB_MFIFO_SIZE_SHIFT 6 7362306a36Sopenharmony_ci * ZB_MFIFO_SIZE_MASK 0x0000000C0 7462306a36Sopenharmony_ci * GA_ENHANCE 0x4274 7562306a36Sopenharmony_ci * SU_REG_DEST 0x42C8 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci /* workaround for RV530 */ 7862306a36Sopenharmony_ci if (rdev->family == CHIP_RV530) { 7962306a36Sopenharmony_ci WREG32(0x4128, 0xFF); 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci r420_pipes_init(rdev); 8262306a36Sopenharmony_ci gb_pipe_select = RREG32(R400_GB_PIPE_SELECT); 8362306a36Sopenharmony_ci tmp = RREG32(R300_DST_PIPE_CONFIG); 8462306a36Sopenharmony_ci pipe_select_current = (tmp >> 2) & 3; 8562306a36Sopenharmony_ci tmp = (1 << pipe_select_current) | 8662306a36Sopenharmony_ci (((gb_pipe_select >> 8) & 0xF) << 4); 8762306a36Sopenharmony_ci WREG32_PLL(0x000D, tmp); 8862306a36Sopenharmony_ci if (r520_mc_wait_for_idle(rdev)) { 8962306a36Sopenharmony_ci pr_warn("Failed to wait MC idle while programming pipes. Bad things might happen.\n"); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic void r520_vram_get_type(struct radeon_device *rdev) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci uint32_t tmp; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci rdev->mc.vram_width = 128; 9862306a36Sopenharmony_ci rdev->mc.vram_is_ddr = true; 9962306a36Sopenharmony_ci tmp = RREG32_MC(R520_MC_CNTL0); 10062306a36Sopenharmony_ci switch ((tmp & R520_MEM_NUM_CHANNELS_MASK) >> R520_MEM_NUM_CHANNELS_SHIFT) { 10162306a36Sopenharmony_ci case 0: 10262306a36Sopenharmony_ci rdev->mc.vram_width = 32; 10362306a36Sopenharmony_ci break; 10462306a36Sopenharmony_ci case 1: 10562306a36Sopenharmony_ci rdev->mc.vram_width = 64; 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci case 2: 10862306a36Sopenharmony_ci rdev->mc.vram_width = 128; 10962306a36Sopenharmony_ci break; 11062306a36Sopenharmony_ci case 3: 11162306a36Sopenharmony_ci rdev->mc.vram_width = 256; 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci default: 11462306a36Sopenharmony_ci rdev->mc.vram_width = 128; 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci if (tmp & R520_MC_CHANNEL_SIZE) 11862306a36Sopenharmony_ci rdev->mc.vram_width *= 2; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void r520_mc_init(struct radeon_device *rdev) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci r520_vram_get_type(rdev); 12562306a36Sopenharmony_ci r100_vram_init_sizes(rdev); 12662306a36Sopenharmony_ci radeon_vram_location(rdev, &rdev->mc, 0); 12762306a36Sopenharmony_ci rdev->mc.gtt_base_align = 0; 12862306a36Sopenharmony_ci if (!(rdev->flags & RADEON_IS_AGP)) 12962306a36Sopenharmony_ci radeon_gtt_location(rdev, &rdev->mc); 13062306a36Sopenharmony_ci radeon_update_bandwidth_info(rdev); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void r520_mc_program(struct radeon_device *rdev) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct rv515_mc_save save; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Stops all mc clients */ 13862306a36Sopenharmony_ci rv515_mc_stop(rdev, &save); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* Wait for mc idle */ 14162306a36Sopenharmony_ci if (r520_mc_wait_for_idle(rdev)) 14262306a36Sopenharmony_ci dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n"); 14362306a36Sopenharmony_ci /* Write VRAM size in case we are limiting it */ 14462306a36Sopenharmony_ci WREG32(R_0000F8_CONFIG_MEMSIZE, rdev->mc.real_vram_size); 14562306a36Sopenharmony_ci /* Program MC, should be a 32bits limited address space */ 14662306a36Sopenharmony_ci WREG32_MC(R_000004_MC_FB_LOCATION, 14762306a36Sopenharmony_ci S_000004_MC_FB_START(rdev->mc.vram_start >> 16) | 14862306a36Sopenharmony_ci S_000004_MC_FB_TOP(rdev->mc.vram_end >> 16)); 14962306a36Sopenharmony_ci WREG32(R_000134_HDP_FB_LOCATION, 15062306a36Sopenharmony_ci S_000134_HDP_FB_START(rdev->mc.vram_start >> 16)); 15162306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) { 15262306a36Sopenharmony_ci WREG32_MC(R_000005_MC_AGP_LOCATION, 15362306a36Sopenharmony_ci S_000005_MC_AGP_START(rdev->mc.gtt_start >> 16) | 15462306a36Sopenharmony_ci S_000005_MC_AGP_TOP(rdev->mc.gtt_end >> 16)); 15562306a36Sopenharmony_ci WREG32_MC(R_000006_AGP_BASE, lower_32_bits(rdev->mc.agp_base)); 15662306a36Sopenharmony_ci WREG32_MC(R_000007_AGP_BASE_2, 15762306a36Sopenharmony_ci S_000007_AGP_BASE_ADDR_2(upper_32_bits(rdev->mc.agp_base))); 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci WREG32_MC(R_000005_MC_AGP_LOCATION, 0xFFFFFFFF); 16062306a36Sopenharmony_ci WREG32_MC(R_000006_AGP_BASE, 0); 16162306a36Sopenharmony_ci WREG32_MC(R_000007_AGP_BASE_2, 0); 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci rv515_mc_resume(rdev, &save); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int r520_startup(struct radeon_device *rdev) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci int r; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci r520_mc_program(rdev); 17262306a36Sopenharmony_ci /* Resume clock */ 17362306a36Sopenharmony_ci rv515_clock_startup(rdev); 17462306a36Sopenharmony_ci /* Initialize GPU configuration (# pipes, ...) */ 17562306a36Sopenharmony_ci r520_gpu_init(rdev); 17662306a36Sopenharmony_ci /* Initialize GART (initialize after TTM so we can allocate 17762306a36Sopenharmony_ci * memory through TTM but finalize after TTM) */ 17862306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PCIE) { 17962306a36Sopenharmony_ci r = rv370_pcie_gart_enable(rdev); 18062306a36Sopenharmony_ci if (r) 18162306a36Sopenharmony_ci return r; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* allocate wb buffer */ 18562306a36Sopenharmony_ci r = radeon_wb_init(rdev); 18662306a36Sopenharmony_ci if (r) 18762306a36Sopenharmony_ci return r; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX); 19062306a36Sopenharmony_ci if (r) { 19162306a36Sopenharmony_ci dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); 19262306a36Sopenharmony_ci return r; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Enable IRQ */ 19662306a36Sopenharmony_ci if (!rdev->irq.installed) { 19762306a36Sopenharmony_ci r = radeon_irq_kms_init(rdev); 19862306a36Sopenharmony_ci if (r) 19962306a36Sopenharmony_ci return r; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci rs600_irq_set(rdev); 20362306a36Sopenharmony_ci rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); 20462306a36Sopenharmony_ci /* 1M ring buffer */ 20562306a36Sopenharmony_ci r = r100_cp_init(rdev, 1024 * 1024); 20662306a36Sopenharmony_ci if (r) { 20762306a36Sopenharmony_ci dev_err(rdev->dev, "failed initializing CP (%d).\n", r); 20862306a36Sopenharmony_ci return r; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci r = radeon_ib_pool_init(rdev); 21262306a36Sopenharmony_ci if (r) { 21362306a36Sopenharmony_ci dev_err(rdev->dev, "IB initialization failed (%d).\n", r); 21462306a36Sopenharmony_ci return r; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciint r520_resume(struct radeon_device *rdev) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci int r; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Make sur GART are not working */ 22562306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_PCIE) 22662306a36Sopenharmony_ci rv370_pcie_gart_disable(rdev); 22762306a36Sopenharmony_ci /* Resume clock before doing reset */ 22862306a36Sopenharmony_ci rv515_clock_startup(rdev); 22962306a36Sopenharmony_ci /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 23062306a36Sopenharmony_ci if (radeon_asic_reset(rdev)) { 23162306a36Sopenharmony_ci dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 23262306a36Sopenharmony_ci RREG32(R_000E40_RBBM_STATUS), 23362306a36Sopenharmony_ci RREG32(R_0007C0_CP_STAT)); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci /* post */ 23662306a36Sopenharmony_ci atom_asic_init(rdev->mode_info.atom_context); 23762306a36Sopenharmony_ci /* Resume clock after posting */ 23862306a36Sopenharmony_ci rv515_clock_startup(rdev); 23962306a36Sopenharmony_ci /* Initialize surface registers */ 24062306a36Sopenharmony_ci radeon_surface_init(rdev); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci rdev->accel_working = true; 24362306a36Sopenharmony_ci r = r520_startup(rdev); 24462306a36Sopenharmony_ci if (r) { 24562306a36Sopenharmony_ci rdev->accel_working = false; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci return r; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciint r520_init(struct radeon_device *rdev) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci int r; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* Initialize scratch registers */ 25562306a36Sopenharmony_ci radeon_scratch_init(rdev); 25662306a36Sopenharmony_ci /* Initialize surface registers */ 25762306a36Sopenharmony_ci radeon_surface_init(rdev); 25862306a36Sopenharmony_ci /* restore some register to sane defaults */ 25962306a36Sopenharmony_ci r100_restore_sanity(rdev); 26062306a36Sopenharmony_ci /* TODO: disable VGA need to use VGA request */ 26162306a36Sopenharmony_ci /* BIOS*/ 26262306a36Sopenharmony_ci if (!radeon_get_bios(rdev)) { 26362306a36Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) 26462306a36Sopenharmony_ci return -EINVAL; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci if (rdev->is_atom_bios) { 26762306a36Sopenharmony_ci r = radeon_atombios_init(rdev); 26862306a36Sopenharmony_ci if (r) 26962306a36Sopenharmony_ci return r; 27062306a36Sopenharmony_ci } else { 27162306a36Sopenharmony_ci dev_err(rdev->dev, "Expecting atombios for RV515 GPU\n"); 27262306a36Sopenharmony_ci return -EINVAL; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 27562306a36Sopenharmony_ci if (radeon_asic_reset(rdev)) { 27662306a36Sopenharmony_ci dev_warn(rdev->dev, 27762306a36Sopenharmony_ci "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 27862306a36Sopenharmony_ci RREG32(R_000E40_RBBM_STATUS), 27962306a36Sopenharmony_ci RREG32(R_0007C0_CP_STAT)); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci /* check if cards are posted or not */ 28262306a36Sopenharmony_ci if (radeon_boot_test_post_card(rdev) == false) 28362306a36Sopenharmony_ci return -EINVAL; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (!radeon_card_posted(rdev) && rdev->bios) { 28662306a36Sopenharmony_ci DRM_INFO("GPU not posted. posting now...\n"); 28762306a36Sopenharmony_ci atom_asic_init(rdev->mode_info.atom_context); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci /* Initialize clocks */ 29062306a36Sopenharmony_ci radeon_get_clock_info(rdev->ddev); 29162306a36Sopenharmony_ci /* initialize AGP */ 29262306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_AGP) { 29362306a36Sopenharmony_ci r = radeon_agp_init(rdev); 29462306a36Sopenharmony_ci if (r) { 29562306a36Sopenharmony_ci radeon_agp_disable(rdev); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci /* initialize memory controller */ 29962306a36Sopenharmony_ci r520_mc_init(rdev); 30062306a36Sopenharmony_ci rv515_debugfs(rdev); 30162306a36Sopenharmony_ci /* Fence driver */ 30262306a36Sopenharmony_ci radeon_fence_driver_init(rdev); 30362306a36Sopenharmony_ci /* Memory manager */ 30462306a36Sopenharmony_ci r = radeon_bo_init(rdev); 30562306a36Sopenharmony_ci if (r) 30662306a36Sopenharmony_ci return r; 30762306a36Sopenharmony_ci r = rv370_pcie_gart_init(rdev); 30862306a36Sopenharmony_ci if (r) 30962306a36Sopenharmony_ci return r; 31062306a36Sopenharmony_ci rv515_set_safe_registers(rdev); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* Initialize power management */ 31362306a36Sopenharmony_ci radeon_pm_init(rdev); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci rdev->accel_working = true; 31662306a36Sopenharmony_ci r = r520_startup(rdev); 31762306a36Sopenharmony_ci if (r) { 31862306a36Sopenharmony_ci /* Somethings want wront with the accel init stop accel */ 31962306a36Sopenharmony_ci dev_err(rdev->dev, "Disabling GPU acceleration\n"); 32062306a36Sopenharmony_ci r100_cp_fini(rdev); 32162306a36Sopenharmony_ci radeon_wb_fini(rdev); 32262306a36Sopenharmony_ci radeon_ib_pool_fini(rdev); 32362306a36Sopenharmony_ci radeon_irq_kms_fini(rdev); 32462306a36Sopenharmony_ci rv370_pcie_gart_fini(rdev); 32562306a36Sopenharmony_ci radeon_agp_fini(rdev); 32662306a36Sopenharmony_ci rdev->accel_working = false; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci} 330