1926deccbSFrançois Tigeot /* 2926deccbSFrançois Tigeot * Copyright 2008 Advanced Micro Devices, Inc. 3926deccbSFrançois Tigeot * Copyright 2008 Red Hat Inc. 4926deccbSFrançois Tigeot * Copyright 2009 Jerome Glisse. 5926deccbSFrançois Tigeot * 6926deccbSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 7926deccbSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 8926deccbSFrançois Tigeot * to deal in the Software without restriction, including without limitation 9926deccbSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10926deccbSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 11926deccbSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 12926deccbSFrançois Tigeot * 13926deccbSFrançois Tigeot * The above copyright notice and this permission notice shall be included in 14926deccbSFrançois Tigeot * all copies or substantial portions of the Software. 15926deccbSFrançois Tigeot * 16926deccbSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17926deccbSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18926deccbSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19926deccbSFrançois Tigeot * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20926deccbSFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21926deccbSFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22926deccbSFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE. 23926deccbSFrançois Tigeot * 24926deccbSFrançois Tigeot * Authors: Dave Airlie 25926deccbSFrançois Tigeot * Alex Deucher 26926deccbSFrançois Tigeot * Jerome Glisse 27926deccbSFrançois Tigeot */ 28926deccbSFrançois Tigeot #include <drm/drmP.h> 29926deccbSFrançois Tigeot #include "radeon.h" 30926deccbSFrançois Tigeot #include "radeon_asic.h" 31*c59a5c48SFrançois Tigeot #include "radeon_audio.h" 32926deccbSFrançois Tigeot #include "atom.h" 33926deccbSFrançois Tigeot #include "rs690d.h" 34926deccbSFrançois Tigeot 35926deccbSFrançois Tigeot int rs690_mc_wait_for_idle(struct radeon_device *rdev) 36926deccbSFrançois Tigeot { 37926deccbSFrançois Tigeot unsigned i; 38926deccbSFrançois Tigeot uint32_t tmp; 39926deccbSFrançois Tigeot 40926deccbSFrançois Tigeot for (i = 0; i < rdev->usec_timeout; i++) { 41926deccbSFrançois Tigeot /* read MC_STATUS */ 42926deccbSFrançois Tigeot tmp = RREG32_MC(R_000090_MC_SYSTEM_STATUS); 43926deccbSFrançois Tigeot if (G_000090_MC_SYSTEM_IDLE(tmp)) 44926deccbSFrançois Tigeot return 0; 45c4ef309bSzrj udelay(1); 46926deccbSFrançois Tigeot } 47926deccbSFrançois Tigeot return -1; 48926deccbSFrançois Tigeot } 49926deccbSFrançois Tigeot 50926deccbSFrançois Tigeot static void rs690_gpu_init(struct radeon_device *rdev) 51926deccbSFrançois Tigeot { 52926deccbSFrançois Tigeot /* FIXME: is this correct ? */ 53926deccbSFrançois Tigeot r420_pipes_init(rdev); 54926deccbSFrançois Tigeot if (rs690_mc_wait_for_idle(rdev)) { 55c4ef309bSzrj printk(KERN_WARNING "Failed to wait MC idle while " 56926deccbSFrançois Tigeot "programming pipes. Bad things might happen.\n"); 57926deccbSFrançois Tigeot } 58926deccbSFrançois Tigeot } 59926deccbSFrançois Tigeot 60926deccbSFrançois Tigeot union igp_info { 61926deccbSFrançois Tigeot struct _ATOM_INTEGRATED_SYSTEM_INFO info; 62926deccbSFrançois Tigeot struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_v2; 63926deccbSFrançois Tigeot }; 64926deccbSFrançois Tigeot 65926deccbSFrançois Tigeot void rs690_pm_info(struct radeon_device *rdev) 66926deccbSFrançois Tigeot { 67926deccbSFrançois Tigeot int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 68926deccbSFrançois Tigeot union igp_info *info; 69926deccbSFrançois Tigeot uint16_t data_offset; 70926deccbSFrançois Tigeot uint8_t frev, crev; 71926deccbSFrançois Tigeot fixed20_12 tmp; 72926deccbSFrançois Tigeot 73926deccbSFrançois Tigeot if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL, 74926deccbSFrançois Tigeot &frev, &crev, &data_offset)) { 75926deccbSFrançois Tigeot info = (union igp_info *)((uintptr_t)rdev->mode_info.atom_context->bios + data_offset); 76926deccbSFrançois Tigeot 77926deccbSFrançois Tigeot /* Get various system informations from bios */ 78926deccbSFrançois Tigeot switch (crev) { 79926deccbSFrançois Tigeot case 1: 80926deccbSFrançois Tigeot tmp.full = dfixed_const(100); 81926deccbSFrançois Tigeot rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info.ulBootUpMemoryClock)); 82926deccbSFrançois Tigeot rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp); 83926deccbSFrançois Tigeot if (le16_to_cpu(info->info.usK8MemoryClock)) 84926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_const(le16_to_cpu(info->info.usK8MemoryClock)); 85926deccbSFrançois Tigeot else if (rdev->clock.default_mclk) { 86926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk); 87926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp); 88926deccbSFrançois Tigeot } else 89926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_const(400); 90926deccbSFrançois Tigeot rdev->pm.igp_ht_link_clk.full = dfixed_const(le16_to_cpu(info->info.usFSBClock)); 91926deccbSFrançois Tigeot rdev->pm.igp_ht_link_width.full = dfixed_const(info->info.ucHTLinkWidth); 92926deccbSFrançois Tigeot break; 93926deccbSFrançois Tigeot case 2: 94926deccbSFrançois Tigeot tmp.full = dfixed_const(100); 95926deccbSFrançois Tigeot rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpSidePortClock)); 96926deccbSFrançois Tigeot rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp); 97926deccbSFrançois Tigeot if (le32_to_cpu(info->info_v2.ulBootUpUMAClock)) 98926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpUMAClock)); 99926deccbSFrançois Tigeot else if (rdev->clock.default_mclk) 100926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk); 101926deccbSFrançois Tigeot else 102926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_const(66700); 103926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp); 104926deccbSFrançois Tigeot rdev->pm.igp_ht_link_clk.full = dfixed_const(le32_to_cpu(info->info_v2.ulHTLinkFreq)); 105926deccbSFrançois Tigeot rdev->pm.igp_ht_link_clk.full = dfixed_div(rdev->pm.igp_ht_link_clk, tmp); 106926deccbSFrançois Tigeot rdev->pm.igp_ht_link_width.full = dfixed_const(le16_to_cpu(info->info_v2.usMinHTLinkWidth)); 107926deccbSFrançois Tigeot break; 108926deccbSFrançois Tigeot default: 109926deccbSFrançois Tigeot /* We assume the slower possible clock ie worst case */ 110926deccbSFrançois Tigeot rdev->pm.igp_sideport_mclk.full = dfixed_const(200); 111926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_const(200); 112926deccbSFrançois Tigeot rdev->pm.igp_ht_link_clk.full = dfixed_const(1000); 113926deccbSFrançois Tigeot rdev->pm.igp_ht_link_width.full = dfixed_const(8); 114926deccbSFrançois Tigeot DRM_ERROR("No integrated system info for your GPU, using safe default\n"); 115926deccbSFrançois Tigeot break; 116926deccbSFrançois Tigeot } 117926deccbSFrançois Tigeot } else { 118926deccbSFrançois Tigeot /* We assume the slower possible clock ie worst case */ 119926deccbSFrançois Tigeot rdev->pm.igp_sideport_mclk.full = dfixed_const(200); 120926deccbSFrançois Tigeot rdev->pm.igp_system_mclk.full = dfixed_const(200); 121926deccbSFrançois Tigeot rdev->pm.igp_ht_link_clk.full = dfixed_const(1000); 122926deccbSFrançois Tigeot rdev->pm.igp_ht_link_width.full = dfixed_const(8); 123926deccbSFrançois Tigeot DRM_ERROR("No integrated system info for your GPU, using safe default\n"); 124926deccbSFrançois Tigeot } 125926deccbSFrançois Tigeot /* Compute various bandwidth */ 126926deccbSFrançois Tigeot /* k8_bandwidth = (memory_clk / 2) * 2 * 8 * 0.5 = memory_clk * 4 */ 127926deccbSFrançois Tigeot tmp.full = dfixed_const(4); 128926deccbSFrançois Tigeot rdev->pm.k8_bandwidth.full = dfixed_mul(rdev->pm.igp_system_mclk, tmp); 129926deccbSFrançois Tigeot /* ht_bandwidth = ht_clk * 2 * ht_width / 8 * 0.8 130926deccbSFrançois Tigeot * = ht_clk * ht_width / 5 131926deccbSFrançois Tigeot */ 132926deccbSFrançois Tigeot tmp.full = dfixed_const(5); 133926deccbSFrançois Tigeot rdev->pm.ht_bandwidth.full = dfixed_mul(rdev->pm.igp_ht_link_clk, 134926deccbSFrançois Tigeot rdev->pm.igp_ht_link_width); 135926deccbSFrançois Tigeot rdev->pm.ht_bandwidth.full = dfixed_div(rdev->pm.ht_bandwidth, tmp); 136926deccbSFrançois Tigeot if (tmp.full < rdev->pm.max_bandwidth.full) { 137926deccbSFrançois Tigeot /* HT link is a limiting factor */ 138926deccbSFrançois Tigeot rdev->pm.max_bandwidth.full = tmp.full; 139926deccbSFrançois Tigeot } 140926deccbSFrançois Tigeot /* sideport_bandwidth = (sideport_clk / 2) * 2 * 2 * 0.7 141926deccbSFrançois Tigeot * = (sideport_clk * 14) / 10 142926deccbSFrançois Tigeot */ 143926deccbSFrançois Tigeot tmp.full = dfixed_const(14); 144926deccbSFrançois Tigeot rdev->pm.sideport_bandwidth.full = dfixed_mul(rdev->pm.igp_sideport_mclk, tmp); 145926deccbSFrançois Tigeot tmp.full = dfixed_const(10); 146926deccbSFrançois Tigeot rdev->pm.sideport_bandwidth.full = dfixed_div(rdev->pm.sideport_bandwidth, tmp); 147926deccbSFrançois Tigeot } 148926deccbSFrançois Tigeot 149926deccbSFrançois Tigeot static void rs690_mc_init(struct radeon_device *rdev) 150926deccbSFrançois Tigeot { 151926deccbSFrançois Tigeot u64 base; 152f43cf1b1SMichael Neumann uint32_t h_addr, l_addr; 153f43cf1b1SMichael Neumann unsigned long long k8_addr; 154926deccbSFrançois Tigeot 155926deccbSFrançois Tigeot rs400_gart_adjust_size(rdev); 156926deccbSFrançois Tigeot rdev->mc.vram_is_ddr = true; 157926deccbSFrançois Tigeot rdev->mc.vram_width = 128; 158926deccbSFrançois Tigeot rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE); 159926deccbSFrançois Tigeot rdev->mc.mc_vram_size = rdev->mc.real_vram_size; 1604a26d795SImre Vadasz rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); 1614a26d795SImre Vadasz rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); 162926deccbSFrançois Tigeot rdev->mc.visible_vram_size = rdev->mc.aper_size; 163926deccbSFrançois Tigeot base = RREG32_MC(R_000100_MCCFG_FB_LOCATION); 164926deccbSFrançois Tigeot base = G_000100_MC_FB_START(base) << 16; 165926deccbSFrançois Tigeot rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); 166c6f73aabSFrançois Tigeot /* Some boards seem to be configured for 128MB of sideport memory, 167c6f73aabSFrançois Tigeot * but really only have 64MB. Just skip the sideport and use 168c6f73aabSFrançois Tigeot * UMA memory. 169c6f73aabSFrançois Tigeot */ 170c6f73aabSFrançois Tigeot if (rdev->mc.igp_sideport_enabled && 171c6f73aabSFrançois Tigeot (rdev->mc.real_vram_size == (384 * 1024 * 1024))) { 172c6f73aabSFrançois Tigeot base += 128 * 1024 * 1024; 173c6f73aabSFrançois Tigeot rdev->mc.real_vram_size -= 128 * 1024 * 1024; 174c6f73aabSFrançois Tigeot rdev->mc.mc_vram_size = rdev->mc.real_vram_size; 175c6f73aabSFrançois Tigeot } 176f43cf1b1SMichael Neumann 177f43cf1b1SMichael Neumann /* Use K8 direct mapping for fast fb access. */ 178f43cf1b1SMichael Neumann rdev->fastfb_working = false; 179f43cf1b1SMichael Neumann h_addr = G_00005F_K8_ADDR_EXT(RREG32_MC(R_00005F_MC_MISC_UMA_CNTL)); 180f43cf1b1SMichael Neumann l_addr = RREG32_MC(R_00001E_K8_FB_LOCATION); 181f43cf1b1SMichael Neumann k8_addr = ((unsigned long long)h_addr) << 32 | l_addr; 182f43cf1b1SMichael Neumann #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE) 183f43cf1b1SMichael Neumann if (k8_addr + rdev->mc.visible_vram_size < 0x100000000ULL) 184f43cf1b1SMichael Neumann #endif 185f43cf1b1SMichael Neumann { 186f43cf1b1SMichael Neumann /* FastFB shall be used with UMA memory. Here it is simply disabled when sideport 187f43cf1b1SMichael Neumann * memory is present. 188f43cf1b1SMichael Neumann */ 189f43cf1b1SMichael Neumann if (rdev->mc.igp_sideport_enabled == false && radeon_fastfb == 1) { 190f43cf1b1SMichael Neumann DRM_INFO("Direct mapping: aper base at 0x%llx, replaced by direct mapping base 0x%llx.\n", 191f43cf1b1SMichael Neumann (unsigned long long)rdev->mc.aper_base, k8_addr); 192f43cf1b1SMichael Neumann rdev->mc.aper_base = (resource_size_t)k8_addr; 193f43cf1b1SMichael Neumann rdev->fastfb_working = true; 194f43cf1b1SMichael Neumann } 195f43cf1b1SMichael Neumann } 196f43cf1b1SMichael Neumann 197926deccbSFrançois Tigeot rs690_pm_info(rdev); 198926deccbSFrançois Tigeot radeon_vram_location(rdev, &rdev->mc, base); 199926deccbSFrançois Tigeot rdev->mc.gtt_base_align = rdev->mc.gtt_size - 1; 200926deccbSFrançois Tigeot radeon_gtt_location(rdev, &rdev->mc); 201926deccbSFrançois Tigeot radeon_update_bandwidth_info(rdev); 202926deccbSFrançois Tigeot } 203926deccbSFrançois Tigeot 204926deccbSFrançois Tigeot void rs690_line_buffer_adjust(struct radeon_device *rdev, 205926deccbSFrançois Tigeot struct drm_display_mode *mode1, 206926deccbSFrançois Tigeot struct drm_display_mode *mode2) 207926deccbSFrançois Tigeot { 208926deccbSFrançois Tigeot u32 tmp; 209926deccbSFrançois Tigeot 210*c59a5c48SFrançois Tigeot /* Guess line buffer size to be 8192 pixels */ 211*c59a5c48SFrançois Tigeot u32 lb_size = 8192; 212*c59a5c48SFrançois Tigeot 213926deccbSFrançois Tigeot /* 214926deccbSFrançois Tigeot * Line Buffer Setup 215926deccbSFrançois Tigeot * There is a single line buffer shared by both display controllers. 216926deccbSFrançois Tigeot * R_006520_DC_LB_MEMORY_SPLIT controls how that line buffer is shared between 217926deccbSFrançois Tigeot * the display controllers. The paritioning can either be done 218926deccbSFrançois Tigeot * manually or via one of four preset allocations specified in bits 1:0: 219926deccbSFrançois Tigeot * 0 - line buffer is divided in half and shared between crtc 220926deccbSFrançois Tigeot * 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4 221926deccbSFrançois Tigeot * 2 - D1 gets the whole buffer 222926deccbSFrançois Tigeot * 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4 223926deccbSFrançois Tigeot * Setting bit 2 of R_006520_DC_LB_MEMORY_SPLIT controls switches to manual 224926deccbSFrançois Tigeot * allocation mode. In manual allocation mode, D1 always starts at 0, 225926deccbSFrançois Tigeot * D1 end/2 is specified in bits 14:4; D2 allocation follows D1. 226926deccbSFrançois Tigeot */ 227926deccbSFrançois Tigeot tmp = RREG32(R_006520_DC_LB_MEMORY_SPLIT) & C_006520_DC_LB_MEMORY_SPLIT; 228926deccbSFrançois Tigeot tmp &= ~C_006520_DC_LB_MEMORY_SPLIT_MODE; 229926deccbSFrançois Tigeot /* auto */ 230926deccbSFrançois Tigeot if (mode1 && mode2) { 231926deccbSFrançois Tigeot if (mode1->hdisplay > mode2->hdisplay) { 232926deccbSFrançois Tigeot if (mode1->hdisplay > 2560) 233926deccbSFrançois Tigeot tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q; 234926deccbSFrançois Tigeot else 235926deccbSFrançois Tigeot tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; 236926deccbSFrançois Tigeot } else if (mode2->hdisplay > mode1->hdisplay) { 237926deccbSFrançois Tigeot if (mode2->hdisplay > 2560) 238926deccbSFrançois Tigeot tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; 239926deccbSFrançois Tigeot else 240926deccbSFrançois Tigeot tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; 241926deccbSFrançois Tigeot } else 242926deccbSFrançois Tigeot tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; 243926deccbSFrançois Tigeot } else if (mode1) { 244926deccbSFrançois Tigeot tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_ONLY; 245926deccbSFrançois Tigeot } else if (mode2) { 246926deccbSFrançois Tigeot tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; 247926deccbSFrançois Tigeot } 248926deccbSFrançois Tigeot WREG32(R_006520_DC_LB_MEMORY_SPLIT, tmp); 249*c59a5c48SFrançois Tigeot 250*c59a5c48SFrançois Tigeot /* Save number of lines the linebuffer leads before the scanout */ 251*c59a5c48SFrançois Tigeot if (mode1) 252*c59a5c48SFrançois Tigeot rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay); 253*c59a5c48SFrançois Tigeot 254*c59a5c48SFrançois Tigeot if (mode2) 255*c59a5c48SFrançois Tigeot rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay); 256926deccbSFrançois Tigeot } 257926deccbSFrançois Tigeot 258926deccbSFrançois Tigeot struct rs690_watermark { 259926deccbSFrançois Tigeot u32 lb_request_fifo_depth; 260926deccbSFrançois Tigeot fixed20_12 num_line_pair; 261926deccbSFrançois Tigeot fixed20_12 estimated_width; 262926deccbSFrançois Tigeot fixed20_12 worst_case_latency; 263926deccbSFrançois Tigeot fixed20_12 consumption_rate; 264926deccbSFrançois Tigeot fixed20_12 active_time; 265926deccbSFrançois Tigeot fixed20_12 dbpp; 266926deccbSFrançois Tigeot fixed20_12 priority_mark_max; 267926deccbSFrançois Tigeot fixed20_12 priority_mark; 268926deccbSFrançois Tigeot fixed20_12 sclk; 269926deccbSFrançois Tigeot }; 270926deccbSFrançois Tigeot 271926deccbSFrançois Tigeot static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, 272926deccbSFrançois Tigeot struct radeon_crtc *crtc, 27357e252bfSMichael Neumann struct rs690_watermark *wm, 27457e252bfSMichael Neumann bool low) 275926deccbSFrançois Tigeot { 276926deccbSFrançois Tigeot struct drm_display_mode *mode = &crtc->base.mode; 277926deccbSFrançois Tigeot fixed20_12 a, b, c; 278926deccbSFrançois Tigeot fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width; 279926deccbSFrançois Tigeot fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency; 28057e252bfSMichael Neumann fixed20_12 sclk, core_bandwidth, max_bandwidth; 28157e252bfSMichael Neumann u32 selected_sclk; 282926deccbSFrançois Tigeot 28357e09377SMatthew Dillon bzero(wm, sizeof(*wm)); /* avoid gcc warning */ 284926deccbSFrançois Tigeot if (!crtc->base.enabled) { 285926deccbSFrançois Tigeot /* FIXME: wouldn't it better to set priority mark to maximum */ 286926deccbSFrançois Tigeot wm->lb_request_fifo_depth = 4; 287926deccbSFrançois Tigeot return; 288926deccbSFrançois Tigeot } 289926deccbSFrançois Tigeot 29057e252bfSMichael Neumann if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) && 29157e252bfSMichael Neumann (rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) 29257e252bfSMichael Neumann selected_sclk = radeon_dpm_get_sclk(rdev, low); 29357e252bfSMichael Neumann else 29457e252bfSMichael Neumann selected_sclk = rdev->pm.current_sclk; 29557e252bfSMichael Neumann 29657e252bfSMichael Neumann /* sclk in Mhz */ 29757e252bfSMichael Neumann a.full = dfixed_const(100); 29857e252bfSMichael Neumann sclk.full = dfixed_const(selected_sclk); 29957e252bfSMichael Neumann sclk.full = dfixed_div(sclk, a); 30057e252bfSMichael Neumann 30157e252bfSMichael Neumann /* core_bandwidth = sclk(Mhz) * 16 */ 30257e252bfSMichael Neumann a.full = dfixed_const(16); 30357e252bfSMichael Neumann core_bandwidth.full = dfixed_div(rdev->pm.sclk, a); 30457e252bfSMichael Neumann 305926deccbSFrançois Tigeot if (crtc->vsc.full > dfixed_const(2)) 306926deccbSFrançois Tigeot wm->num_line_pair.full = dfixed_const(2); 307926deccbSFrançois Tigeot else 308926deccbSFrançois Tigeot wm->num_line_pair.full = dfixed_const(1); 309926deccbSFrançois Tigeot 310926deccbSFrançois Tigeot b.full = dfixed_const(mode->crtc_hdisplay); 311926deccbSFrançois Tigeot c.full = dfixed_const(256); 312926deccbSFrançois Tigeot a.full = dfixed_div(b, c); 313926deccbSFrançois Tigeot request_fifo_depth.full = dfixed_mul(a, wm->num_line_pair); 314926deccbSFrançois Tigeot request_fifo_depth.full = dfixed_ceil(request_fifo_depth); 315926deccbSFrançois Tigeot if (a.full < dfixed_const(4)) { 316926deccbSFrançois Tigeot wm->lb_request_fifo_depth = 4; 317926deccbSFrançois Tigeot } else { 318926deccbSFrançois Tigeot wm->lb_request_fifo_depth = dfixed_trunc(request_fifo_depth); 319926deccbSFrançois Tigeot } 320926deccbSFrançois Tigeot 321926deccbSFrançois Tigeot /* Determine consumption rate 322926deccbSFrançois Tigeot * pclk = pixel clock period(ns) = 1000 / (mode.clock / 1000) 323926deccbSFrançois Tigeot * vtaps = number of vertical taps, 324926deccbSFrançois Tigeot * vsc = vertical scaling ratio, defined as source/destination 325926deccbSFrançois Tigeot * hsc = horizontal scaling ration, defined as source/destination 326926deccbSFrançois Tigeot */ 327926deccbSFrançois Tigeot a.full = dfixed_const(mode->clock); 328926deccbSFrançois Tigeot b.full = dfixed_const(1000); 329926deccbSFrançois Tigeot a.full = dfixed_div(a, b); 330926deccbSFrançois Tigeot pclk.full = dfixed_div(b, a); 331926deccbSFrançois Tigeot if (crtc->rmx_type != RMX_OFF) { 332926deccbSFrançois Tigeot b.full = dfixed_const(2); 333926deccbSFrançois Tigeot if (crtc->vsc.full > b.full) 334926deccbSFrançois Tigeot b.full = crtc->vsc.full; 335926deccbSFrançois Tigeot b.full = dfixed_mul(b, crtc->hsc); 336926deccbSFrançois Tigeot c.full = dfixed_const(2); 337926deccbSFrançois Tigeot b.full = dfixed_div(b, c); 338926deccbSFrançois Tigeot consumption_time.full = dfixed_div(pclk, b); 339926deccbSFrançois Tigeot } else { 340926deccbSFrançois Tigeot consumption_time.full = pclk.full; 341926deccbSFrançois Tigeot } 342926deccbSFrançois Tigeot a.full = dfixed_const(1); 343926deccbSFrançois Tigeot wm->consumption_rate.full = dfixed_div(a, consumption_time); 344926deccbSFrançois Tigeot 345926deccbSFrançois Tigeot 346926deccbSFrançois Tigeot /* Determine line time 347926deccbSFrançois Tigeot * LineTime = total time for one line of displayhtotal 348926deccbSFrançois Tigeot * LineTime = total number of horizontal pixels 349926deccbSFrançois Tigeot * pclk = pixel clock period(ns) 350926deccbSFrançois Tigeot */ 351926deccbSFrançois Tigeot a.full = dfixed_const(crtc->base.mode.crtc_htotal); 352926deccbSFrançois Tigeot line_time.full = dfixed_mul(a, pclk); 353926deccbSFrançois Tigeot 354926deccbSFrançois Tigeot /* Determine active time 355926deccbSFrançois Tigeot * ActiveTime = time of active region of display within one line, 356926deccbSFrançois Tigeot * hactive = total number of horizontal active pixels 357926deccbSFrançois Tigeot * htotal = total number of horizontal pixels 358926deccbSFrançois Tigeot */ 359926deccbSFrançois Tigeot a.full = dfixed_const(crtc->base.mode.crtc_htotal); 360926deccbSFrançois Tigeot b.full = dfixed_const(crtc->base.mode.crtc_hdisplay); 361926deccbSFrançois Tigeot wm->active_time.full = dfixed_mul(line_time, b); 362926deccbSFrançois Tigeot wm->active_time.full = dfixed_div(wm->active_time, a); 363926deccbSFrançois Tigeot 364926deccbSFrançois Tigeot /* Maximun bandwidth is the minimun bandwidth of all component */ 36557e252bfSMichael Neumann max_bandwidth = core_bandwidth; 366926deccbSFrançois Tigeot if (rdev->mc.igp_sideport_enabled) { 36757e252bfSMichael Neumann if (max_bandwidth.full > rdev->pm.sideport_bandwidth.full && 368926deccbSFrançois Tigeot rdev->pm.sideport_bandwidth.full) 36957e252bfSMichael Neumann max_bandwidth = rdev->pm.sideport_bandwidth; 370c6f73aabSFrançois Tigeot read_delay_latency.full = dfixed_const(370 * 800); 371c6f73aabSFrançois Tigeot a.full = dfixed_const(1000); 372c6f73aabSFrançois Tigeot b.full = dfixed_div(rdev->pm.igp_sideport_mclk, a); 373c6f73aabSFrançois Tigeot read_delay_latency.full = dfixed_div(read_delay_latency, b); 374c6f73aabSFrançois Tigeot read_delay_latency.full = dfixed_mul(read_delay_latency, a); 375926deccbSFrançois Tigeot } else { 37657e252bfSMichael Neumann if (max_bandwidth.full > rdev->pm.k8_bandwidth.full && 377926deccbSFrançois Tigeot rdev->pm.k8_bandwidth.full) 37857e252bfSMichael Neumann max_bandwidth = rdev->pm.k8_bandwidth; 37957e252bfSMichael Neumann if (max_bandwidth.full > rdev->pm.ht_bandwidth.full && 380926deccbSFrançois Tigeot rdev->pm.ht_bandwidth.full) 38157e252bfSMichael Neumann max_bandwidth = rdev->pm.ht_bandwidth; 382926deccbSFrançois Tigeot read_delay_latency.full = dfixed_const(5000); 383926deccbSFrançois Tigeot } 384926deccbSFrançois Tigeot 385926deccbSFrançois Tigeot /* sclk = system clocks(ns) = 1000 / max_bandwidth / 16 */ 386926deccbSFrançois Tigeot a.full = dfixed_const(16); 38757e252bfSMichael Neumann sclk.full = dfixed_mul(max_bandwidth, a); 388926deccbSFrançois Tigeot a.full = dfixed_const(1000); 38957e252bfSMichael Neumann sclk.full = dfixed_div(a, sclk); 390926deccbSFrançois Tigeot /* Determine chunk time 391926deccbSFrançois Tigeot * ChunkTime = the time it takes the DCP to send one chunk of data 392926deccbSFrançois Tigeot * to the LB which consists of pipeline delay and inter chunk gap 393926deccbSFrançois Tigeot * sclk = system clock(ns) 394926deccbSFrançois Tigeot */ 395926deccbSFrançois Tigeot a.full = dfixed_const(256 * 13); 39657e252bfSMichael Neumann chunk_time.full = dfixed_mul(sclk, a); 397926deccbSFrançois Tigeot a.full = dfixed_const(10); 398926deccbSFrançois Tigeot chunk_time.full = dfixed_div(chunk_time, a); 399926deccbSFrançois Tigeot 400926deccbSFrançois Tigeot /* Determine the worst case latency 401926deccbSFrançois Tigeot * NumLinePair = Number of line pairs to request(1=2 lines, 2=4 lines) 402926deccbSFrançois Tigeot * WorstCaseLatency = worst case time from urgent to when the MC starts 403926deccbSFrançois Tigeot * to return data 404926deccbSFrançois Tigeot * READ_DELAY_IDLE_MAX = constant of 1us 405926deccbSFrançois Tigeot * ChunkTime = time it takes the DCP to send one chunk of data to the LB 406926deccbSFrançois Tigeot * which consists of pipeline delay and inter chunk gap 407926deccbSFrançois Tigeot */ 408926deccbSFrançois Tigeot if (dfixed_trunc(wm->num_line_pair) > 1) { 409926deccbSFrançois Tigeot a.full = dfixed_const(3); 410926deccbSFrançois Tigeot wm->worst_case_latency.full = dfixed_mul(a, chunk_time); 411926deccbSFrançois Tigeot wm->worst_case_latency.full += read_delay_latency.full; 412926deccbSFrançois Tigeot } else { 413926deccbSFrançois Tigeot a.full = dfixed_const(2); 414926deccbSFrançois Tigeot wm->worst_case_latency.full = dfixed_mul(a, chunk_time); 415926deccbSFrançois Tigeot wm->worst_case_latency.full += read_delay_latency.full; 416926deccbSFrançois Tigeot } 417926deccbSFrançois Tigeot 418926deccbSFrançois Tigeot /* Determine the tolerable latency 419926deccbSFrançois Tigeot * TolerableLatency = Any given request has only 1 line time 420926deccbSFrançois Tigeot * for the data to be returned 421926deccbSFrançois Tigeot * LBRequestFifoDepth = Number of chunk requests the LB can 422926deccbSFrançois Tigeot * put into the request FIFO for a display 423926deccbSFrançois Tigeot * LineTime = total time for one line of display 424926deccbSFrançois Tigeot * ChunkTime = the time it takes the DCP to send one chunk 425926deccbSFrançois Tigeot * of data to the LB which consists of 426926deccbSFrançois Tigeot * pipeline delay and inter chunk gap 427926deccbSFrançois Tigeot */ 428926deccbSFrançois Tigeot if ((2+wm->lb_request_fifo_depth) >= dfixed_trunc(request_fifo_depth)) { 429926deccbSFrançois Tigeot tolerable_latency.full = line_time.full; 430926deccbSFrançois Tigeot } else { 431926deccbSFrançois Tigeot tolerable_latency.full = dfixed_const(wm->lb_request_fifo_depth - 2); 432926deccbSFrançois Tigeot tolerable_latency.full = request_fifo_depth.full - tolerable_latency.full; 433926deccbSFrançois Tigeot tolerable_latency.full = dfixed_mul(tolerable_latency, chunk_time); 434926deccbSFrançois Tigeot tolerable_latency.full = line_time.full - tolerable_latency.full; 435926deccbSFrançois Tigeot } 436926deccbSFrançois Tigeot /* We assume worst case 32bits (4 bytes) */ 437926deccbSFrançois Tigeot wm->dbpp.full = dfixed_const(4 * 8); 438926deccbSFrançois Tigeot 439926deccbSFrançois Tigeot /* Determine the maximum priority mark 440926deccbSFrançois Tigeot * width = viewport width in pixels 441926deccbSFrançois Tigeot */ 442926deccbSFrançois Tigeot a.full = dfixed_const(16); 443926deccbSFrançois Tigeot wm->priority_mark_max.full = dfixed_const(crtc->base.mode.crtc_hdisplay); 444926deccbSFrançois Tigeot wm->priority_mark_max.full = dfixed_div(wm->priority_mark_max, a); 445926deccbSFrançois Tigeot wm->priority_mark_max.full = dfixed_ceil(wm->priority_mark_max); 446926deccbSFrançois Tigeot 447926deccbSFrançois Tigeot /* Determine estimated width */ 448926deccbSFrançois Tigeot estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full; 449926deccbSFrançois Tigeot estimated_width.full = dfixed_div(estimated_width, consumption_time); 450926deccbSFrançois Tigeot if (dfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) { 451926deccbSFrançois Tigeot wm->priority_mark.full = dfixed_const(10); 452926deccbSFrançois Tigeot } else { 453926deccbSFrançois Tigeot a.full = dfixed_const(16); 454926deccbSFrançois Tigeot wm->priority_mark.full = dfixed_div(estimated_width, a); 455926deccbSFrançois Tigeot wm->priority_mark.full = dfixed_ceil(wm->priority_mark); 456926deccbSFrançois Tigeot wm->priority_mark.full = wm->priority_mark_max.full - wm->priority_mark.full; 457926deccbSFrançois Tigeot } 458926deccbSFrançois Tigeot } 459926deccbSFrançois Tigeot 46057e252bfSMichael Neumann static void rs690_compute_mode_priority(struct radeon_device *rdev, 46157e252bfSMichael Neumann struct rs690_watermark *wm0, 46257e252bfSMichael Neumann struct rs690_watermark *wm1, 46357e252bfSMichael Neumann struct drm_display_mode *mode0, 46457e252bfSMichael Neumann struct drm_display_mode *mode1, 46557e252bfSMichael Neumann u32 *d1mode_priority_a_cnt, 46657e252bfSMichael Neumann u32 *d2mode_priority_a_cnt) 46757e252bfSMichael Neumann { 46857e252bfSMichael Neumann fixed20_12 priority_mark02, priority_mark12, fill_rate; 46957e252bfSMichael Neumann fixed20_12 a, b; 47057e252bfSMichael Neumann 47157e252bfSMichael Neumann *d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); 47257e252bfSMichael Neumann *d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); 47357e252bfSMichael Neumann 47457e252bfSMichael Neumann if (mode0 && mode1) { 47557e252bfSMichael Neumann if (dfixed_trunc(wm0->dbpp) > 64) 47657e252bfSMichael Neumann a.full = dfixed_mul(wm0->dbpp, wm0->num_line_pair); 47757e252bfSMichael Neumann else 47857e252bfSMichael Neumann a.full = wm0->num_line_pair.full; 47957e252bfSMichael Neumann if (dfixed_trunc(wm1->dbpp) > 64) 48057e252bfSMichael Neumann b.full = dfixed_mul(wm1->dbpp, wm1->num_line_pair); 48157e252bfSMichael Neumann else 48257e252bfSMichael Neumann b.full = wm1->num_line_pair.full; 48357e252bfSMichael Neumann a.full += b.full; 48457e252bfSMichael Neumann fill_rate.full = dfixed_div(wm0->sclk, a); 48557e252bfSMichael Neumann if (wm0->consumption_rate.full > fill_rate.full) { 48657e252bfSMichael Neumann b.full = wm0->consumption_rate.full - fill_rate.full; 48757e252bfSMichael Neumann b.full = dfixed_mul(b, wm0->active_time); 48857e252bfSMichael Neumann a.full = dfixed_mul(wm0->worst_case_latency, 48957e252bfSMichael Neumann wm0->consumption_rate); 49057e252bfSMichael Neumann a.full = a.full + b.full; 49157e252bfSMichael Neumann b.full = dfixed_const(16 * 1000); 49257e252bfSMichael Neumann priority_mark02.full = dfixed_div(a, b); 49357e252bfSMichael Neumann } else { 49457e252bfSMichael Neumann a.full = dfixed_mul(wm0->worst_case_latency, 49557e252bfSMichael Neumann wm0->consumption_rate); 49657e252bfSMichael Neumann b.full = dfixed_const(16 * 1000); 49757e252bfSMichael Neumann priority_mark02.full = dfixed_div(a, b); 49857e252bfSMichael Neumann } 49957e252bfSMichael Neumann if (wm1->consumption_rate.full > fill_rate.full) { 50057e252bfSMichael Neumann b.full = wm1->consumption_rate.full - fill_rate.full; 50157e252bfSMichael Neumann b.full = dfixed_mul(b, wm1->active_time); 50257e252bfSMichael Neumann a.full = dfixed_mul(wm1->worst_case_latency, 50357e252bfSMichael Neumann wm1->consumption_rate); 50457e252bfSMichael Neumann a.full = a.full + b.full; 50557e252bfSMichael Neumann b.full = dfixed_const(16 * 1000); 50657e252bfSMichael Neumann priority_mark12.full = dfixed_div(a, b); 50757e252bfSMichael Neumann } else { 50857e252bfSMichael Neumann a.full = dfixed_mul(wm1->worst_case_latency, 50957e252bfSMichael Neumann wm1->consumption_rate); 51057e252bfSMichael Neumann b.full = dfixed_const(16 * 1000); 51157e252bfSMichael Neumann priority_mark12.full = dfixed_div(a, b); 51257e252bfSMichael Neumann } 51357e252bfSMichael Neumann if (wm0->priority_mark.full > priority_mark02.full) 51457e252bfSMichael Neumann priority_mark02.full = wm0->priority_mark.full; 51557e252bfSMichael Neumann if (wm0->priority_mark_max.full > priority_mark02.full) 51657e252bfSMichael Neumann priority_mark02.full = wm0->priority_mark_max.full; 51757e252bfSMichael Neumann if (wm1->priority_mark.full > priority_mark12.full) 51857e252bfSMichael Neumann priority_mark12.full = wm1->priority_mark.full; 51957e252bfSMichael Neumann if (wm1->priority_mark_max.full > priority_mark12.full) 52057e252bfSMichael Neumann priority_mark12.full = wm1->priority_mark_max.full; 52157e252bfSMichael Neumann *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); 52257e252bfSMichael Neumann *d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); 52357e252bfSMichael Neumann if (rdev->disp_priority == 2) { 52457e252bfSMichael Neumann *d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); 52557e252bfSMichael Neumann *d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); 52657e252bfSMichael Neumann } 52757e252bfSMichael Neumann } else if (mode0) { 52857e252bfSMichael Neumann if (dfixed_trunc(wm0->dbpp) > 64) 52957e252bfSMichael Neumann a.full = dfixed_mul(wm0->dbpp, wm0->num_line_pair); 53057e252bfSMichael Neumann else 53157e252bfSMichael Neumann a.full = wm0->num_line_pair.full; 53257e252bfSMichael Neumann fill_rate.full = dfixed_div(wm0->sclk, a); 53357e252bfSMichael Neumann if (wm0->consumption_rate.full > fill_rate.full) { 53457e252bfSMichael Neumann b.full = wm0->consumption_rate.full - fill_rate.full; 53557e252bfSMichael Neumann b.full = dfixed_mul(b, wm0->active_time); 53657e252bfSMichael Neumann a.full = dfixed_mul(wm0->worst_case_latency, 53757e252bfSMichael Neumann wm0->consumption_rate); 53857e252bfSMichael Neumann a.full = a.full + b.full; 53957e252bfSMichael Neumann b.full = dfixed_const(16 * 1000); 54057e252bfSMichael Neumann priority_mark02.full = dfixed_div(a, b); 54157e252bfSMichael Neumann } else { 54257e252bfSMichael Neumann a.full = dfixed_mul(wm0->worst_case_latency, 54357e252bfSMichael Neumann wm0->consumption_rate); 54457e252bfSMichael Neumann b.full = dfixed_const(16 * 1000); 54557e252bfSMichael Neumann priority_mark02.full = dfixed_div(a, b); 54657e252bfSMichael Neumann } 54757e252bfSMichael Neumann if (wm0->priority_mark.full > priority_mark02.full) 54857e252bfSMichael Neumann priority_mark02.full = wm0->priority_mark.full; 54957e252bfSMichael Neumann if (wm0->priority_mark_max.full > priority_mark02.full) 55057e252bfSMichael Neumann priority_mark02.full = wm0->priority_mark_max.full; 55157e252bfSMichael Neumann *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); 55257e252bfSMichael Neumann if (rdev->disp_priority == 2) 55357e252bfSMichael Neumann *d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); 55457e252bfSMichael Neumann } else if (mode1) { 55557e252bfSMichael Neumann if (dfixed_trunc(wm1->dbpp) > 64) 55657e252bfSMichael Neumann a.full = dfixed_mul(wm1->dbpp, wm1->num_line_pair); 55757e252bfSMichael Neumann else 55857e252bfSMichael Neumann a.full = wm1->num_line_pair.full; 55957e252bfSMichael Neumann fill_rate.full = dfixed_div(wm1->sclk, a); 56057e252bfSMichael Neumann if (wm1->consumption_rate.full > fill_rate.full) { 56157e252bfSMichael Neumann b.full = wm1->consumption_rate.full - fill_rate.full; 56257e252bfSMichael Neumann b.full = dfixed_mul(b, wm1->active_time); 56357e252bfSMichael Neumann a.full = dfixed_mul(wm1->worst_case_latency, 56457e252bfSMichael Neumann wm1->consumption_rate); 56557e252bfSMichael Neumann a.full = a.full + b.full; 56657e252bfSMichael Neumann b.full = dfixed_const(16 * 1000); 56757e252bfSMichael Neumann priority_mark12.full = dfixed_div(a, b); 56857e252bfSMichael Neumann } else { 56957e252bfSMichael Neumann a.full = dfixed_mul(wm1->worst_case_latency, 57057e252bfSMichael Neumann wm1->consumption_rate); 57157e252bfSMichael Neumann b.full = dfixed_const(16 * 1000); 57257e252bfSMichael Neumann priority_mark12.full = dfixed_div(a, b); 57357e252bfSMichael Neumann } 57457e252bfSMichael Neumann if (wm1->priority_mark.full > priority_mark12.full) 57557e252bfSMichael Neumann priority_mark12.full = wm1->priority_mark.full; 57657e252bfSMichael Neumann if (wm1->priority_mark_max.full > priority_mark12.full) 57757e252bfSMichael Neumann priority_mark12.full = wm1->priority_mark_max.full; 57857e252bfSMichael Neumann *d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); 57957e252bfSMichael Neumann if (rdev->disp_priority == 2) 58057e252bfSMichael Neumann *d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); 58157e252bfSMichael Neumann } 58257e252bfSMichael Neumann } 58357e252bfSMichael Neumann 584926deccbSFrançois Tigeot void rs690_bandwidth_update(struct radeon_device *rdev) 585926deccbSFrançois Tigeot { 586926deccbSFrançois Tigeot struct drm_display_mode *mode0 = NULL; 587926deccbSFrançois Tigeot struct drm_display_mode *mode1 = NULL; 58857e252bfSMichael Neumann struct rs690_watermark wm0_high, wm0_low; 58957e252bfSMichael Neumann struct rs690_watermark wm1_high, wm1_low; 590926deccbSFrançois Tigeot u32 tmp; 59157e252bfSMichael Neumann u32 d1mode_priority_a_cnt, d1mode_priority_b_cnt; 59257e252bfSMichael Neumann u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt; 593926deccbSFrançois Tigeot 594591d5043SFrançois Tigeot if (!rdev->mode_info.mode_config_initialized) 595591d5043SFrançois Tigeot return; 596591d5043SFrançois Tigeot 597926deccbSFrançois Tigeot radeon_update_display_priority(rdev); 598926deccbSFrançois Tigeot 599926deccbSFrançois Tigeot if (rdev->mode_info.crtcs[0]->base.enabled) 600926deccbSFrançois Tigeot mode0 = &rdev->mode_info.crtcs[0]->base.mode; 601926deccbSFrançois Tigeot if (rdev->mode_info.crtcs[1]->base.enabled) 602926deccbSFrançois Tigeot mode1 = &rdev->mode_info.crtcs[1]->base.mode; 603926deccbSFrançois Tigeot /* 604926deccbSFrançois Tigeot * Set display0/1 priority up in the memory controller for 605926deccbSFrançois Tigeot * modes if the user specifies HIGH for displaypriority 606926deccbSFrançois Tigeot * option. 607926deccbSFrançois Tigeot */ 608926deccbSFrançois Tigeot if ((rdev->disp_priority == 2) && 609926deccbSFrançois Tigeot ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))) { 610926deccbSFrançois Tigeot tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER); 611926deccbSFrançois Tigeot tmp &= C_000104_MC_DISP0R_INIT_LAT; 612926deccbSFrançois Tigeot tmp &= C_000104_MC_DISP1R_INIT_LAT; 613926deccbSFrançois Tigeot if (mode0) 614926deccbSFrançois Tigeot tmp |= S_000104_MC_DISP0R_INIT_LAT(1); 615926deccbSFrançois Tigeot if (mode1) 616926deccbSFrançois Tigeot tmp |= S_000104_MC_DISP1R_INIT_LAT(1); 617926deccbSFrançois Tigeot WREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER, tmp); 618926deccbSFrançois Tigeot } 619926deccbSFrançois Tigeot rs690_line_buffer_adjust(rdev, mode0, mode1); 620926deccbSFrançois Tigeot 621926deccbSFrançois Tigeot if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) 622926deccbSFrançois Tigeot WREG32(R_006C9C_DCP_CONTROL, 0); 623926deccbSFrançois Tigeot if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) 624926deccbSFrançois Tigeot WREG32(R_006C9C_DCP_CONTROL, 2); 625926deccbSFrançois Tigeot 62657e252bfSMichael Neumann rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_high, false); 62757e252bfSMichael Neumann rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_high, false); 628926deccbSFrançois Tigeot 62957e252bfSMichael Neumann rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_low, true); 63057e252bfSMichael Neumann rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_low, true); 63157e252bfSMichael Neumann 63257e252bfSMichael Neumann tmp = (wm0_high.lb_request_fifo_depth - 1); 63357e252bfSMichael Neumann tmp |= (wm1_high.lb_request_fifo_depth - 1) << 16; 634926deccbSFrançois Tigeot WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp); 635926deccbSFrançois Tigeot 63657e252bfSMichael Neumann rs690_compute_mode_priority(rdev, 63757e252bfSMichael Neumann &wm0_high, &wm1_high, 63857e252bfSMichael Neumann mode0, mode1, 63957e252bfSMichael Neumann &d1mode_priority_a_cnt, &d2mode_priority_a_cnt); 64057e252bfSMichael Neumann rs690_compute_mode_priority(rdev, 64157e252bfSMichael Neumann &wm0_low, &wm1_low, 64257e252bfSMichael Neumann mode0, mode1, 64357e252bfSMichael Neumann &d1mode_priority_b_cnt, &d2mode_priority_b_cnt); 644926deccbSFrançois Tigeot 645926deccbSFrançois Tigeot WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); 64657e252bfSMichael Neumann WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_b_cnt); 647926deccbSFrançois Tigeot WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); 64857e252bfSMichael Neumann WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_b_cnt); 649926deccbSFrançois Tigeot } 650926deccbSFrançois Tigeot 651926deccbSFrançois Tigeot uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg) 652926deccbSFrançois Tigeot { 653926deccbSFrançois Tigeot uint32_t r; 654926deccbSFrançois Tigeot 655ee479021SImre Vadász spin_lock(&rdev->mc_idx_lock); 656926deccbSFrançois Tigeot WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg)); 657926deccbSFrançois Tigeot r = RREG32(R_00007C_MC_DATA); 658926deccbSFrançois Tigeot WREG32(R_000078_MC_INDEX, ~C_000078_MC_IND_ADDR); 659ee479021SImre Vadász spin_unlock(&rdev->mc_idx_lock); 660926deccbSFrançois Tigeot return r; 661926deccbSFrançois Tigeot } 662926deccbSFrançois Tigeot 663926deccbSFrançois Tigeot void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) 664926deccbSFrançois Tigeot { 665ee479021SImre Vadász spin_lock(&rdev->mc_idx_lock); 666926deccbSFrançois Tigeot WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg) | 667926deccbSFrançois Tigeot S_000078_MC_IND_WR_EN(1)); 668926deccbSFrançois Tigeot WREG32(R_00007C_MC_DATA, v); 669926deccbSFrançois Tigeot WREG32(R_000078_MC_INDEX, 0x7F); 670ee479021SImre Vadász spin_unlock(&rdev->mc_idx_lock); 671926deccbSFrançois Tigeot } 672926deccbSFrançois Tigeot 673926deccbSFrançois Tigeot static void rs690_mc_program(struct radeon_device *rdev) 674926deccbSFrançois Tigeot { 675926deccbSFrançois Tigeot struct rv515_mc_save save; 676926deccbSFrançois Tigeot 677926deccbSFrançois Tigeot /* Stops all mc clients */ 678926deccbSFrançois Tigeot rv515_mc_stop(rdev, &save); 679926deccbSFrançois Tigeot 680926deccbSFrançois Tigeot /* Wait for mc idle */ 681926deccbSFrançois Tigeot if (rs690_mc_wait_for_idle(rdev)) 682926deccbSFrançois Tigeot dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n"); 683926deccbSFrançois Tigeot /* Program MC, should be a 32bits limited address space */ 684926deccbSFrançois Tigeot WREG32_MC(R_000100_MCCFG_FB_LOCATION, 685926deccbSFrançois Tigeot S_000100_MC_FB_START(rdev->mc.vram_start >> 16) | 686926deccbSFrançois Tigeot S_000100_MC_FB_TOP(rdev->mc.vram_end >> 16)); 687926deccbSFrançois Tigeot WREG32(R_000134_HDP_FB_LOCATION, 688926deccbSFrançois Tigeot S_000134_HDP_FB_START(rdev->mc.vram_start >> 16)); 689926deccbSFrançois Tigeot 690926deccbSFrançois Tigeot rv515_mc_resume(rdev, &save); 691926deccbSFrançois Tigeot } 692926deccbSFrançois Tigeot 693926deccbSFrançois Tigeot static int rs690_startup(struct radeon_device *rdev) 694926deccbSFrançois Tigeot { 695926deccbSFrançois Tigeot int r; 696926deccbSFrançois Tigeot 697926deccbSFrançois Tigeot rs690_mc_program(rdev); 698926deccbSFrançois Tigeot /* Resume clock */ 699926deccbSFrançois Tigeot rv515_clock_startup(rdev); 700926deccbSFrançois Tigeot /* Initialize GPU configuration (# pipes, ...) */ 701926deccbSFrançois Tigeot rs690_gpu_init(rdev); 702926deccbSFrançois Tigeot /* Initialize GART (initialize after TTM so we can allocate 703926deccbSFrançois Tigeot * memory through TTM but finalize after TTM) */ 704926deccbSFrançois Tigeot r = rs400_gart_enable(rdev); 705926deccbSFrançois Tigeot if (r) 706926deccbSFrançois Tigeot return r; 707926deccbSFrançois Tigeot 708926deccbSFrançois Tigeot /* allocate wb buffer */ 709926deccbSFrançois Tigeot r = radeon_wb_init(rdev); 710926deccbSFrançois Tigeot if (r) 711926deccbSFrançois Tigeot return r; 712926deccbSFrançois Tigeot 713926deccbSFrançois Tigeot r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX); 714926deccbSFrançois Tigeot if (r) { 715926deccbSFrançois Tigeot dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); 716926deccbSFrançois Tigeot return r; 717926deccbSFrançois Tigeot } 718926deccbSFrançois Tigeot 719926deccbSFrançois Tigeot /* Enable IRQ */ 720f43cf1b1SMichael Neumann if (!rdev->irq.installed) { 721f43cf1b1SMichael Neumann r = radeon_irq_kms_init(rdev); 722f43cf1b1SMichael Neumann if (r) 723f43cf1b1SMichael Neumann return r; 724f43cf1b1SMichael Neumann } 725f43cf1b1SMichael Neumann 726926deccbSFrançois Tigeot rs600_irq_set(rdev); 727926deccbSFrançois Tigeot rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); 728926deccbSFrançois Tigeot /* 1M ring buffer */ 729926deccbSFrançois Tigeot r = r100_cp_init(rdev, 1024 * 1024); 730926deccbSFrançois Tigeot if (r) { 731926deccbSFrançois Tigeot dev_err(rdev->dev, "failed initializing CP (%d).\n", r); 732926deccbSFrançois Tigeot return r; 733926deccbSFrançois Tigeot } 734926deccbSFrançois Tigeot 735926deccbSFrançois Tigeot r = radeon_ib_pool_init(rdev); 736926deccbSFrançois Tigeot if (r) { 737926deccbSFrançois Tigeot dev_err(rdev->dev, "IB initialization failed (%d).\n", r); 738926deccbSFrançois Tigeot return r; 739926deccbSFrançois Tigeot } 740926deccbSFrançois Tigeot 741*c59a5c48SFrançois Tigeot r = radeon_audio_init(rdev); 742926deccbSFrançois Tigeot if (r) { 743926deccbSFrançois Tigeot dev_err(rdev->dev, "failed initializing audio\n"); 744926deccbSFrançois Tigeot return r; 745926deccbSFrançois Tigeot } 746926deccbSFrançois Tigeot 747926deccbSFrançois Tigeot return 0; 748926deccbSFrançois Tigeot } 749926deccbSFrançois Tigeot 750926deccbSFrançois Tigeot int rs690_resume(struct radeon_device *rdev) 751926deccbSFrançois Tigeot { 752926deccbSFrançois Tigeot int r; 753926deccbSFrançois Tigeot 754926deccbSFrançois Tigeot /* Make sur GART are not working */ 755926deccbSFrançois Tigeot rs400_gart_disable(rdev); 756926deccbSFrançois Tigeot /* Resume clock before doing reset */ 757926deccbSFrançois Tigeot rv515_clock_startup(rdev); 758926deccbSFrançois Tigeot /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 759926deccbSFrançois Tigeot if (radeon_asic_reset(rdev)) { 760926deccbSFrançois Tigeot dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 761926deccbSFrançois Tigeot RREG32(R_000E40_RBBM_STATUS), 762926deccbSFrançois Tigeot RREG32(R_0007C0_CP_STAT)); 763926deccbSFrançois Tigeot } 764926deccbSFrançois Tigeot /* post */ 765926deccbSFrançois Tigeot atom_asic_init(rdev->mode_info.atom_context); 766926deccbSFrançois Tigeot /* Resume clock after posting */ 767926deccbSFrançois Tigeot rv515_clock_startup(rdev); 768926deccbSFrançois Tigeot /* Initialize surface registers */ 769926deccbSFrançois Tigeot radeon_surface_init(rdev); 770926deccbSFrançois Tigeot 771926deccbSFrançois Tigeot rdev->accel_working = true; 772926deccbSFrançois Tigeot r = rs690_startup(rdev); 773926deccbSFrançois Tigeot if (r) { 774926deccbSFrançois Tigeot rdev->accel_working = false; 775926deccbSFrançois Tigeot } 776926deccbSFrançois Tigeot return r; 777926deccbSFrançois Tigeot } 778926deccbSFrançois Tigeot 779926deccbSFrançois Tigeot int rs690_suspend(struct radeon_device *rdev) 780926deccbSFrançois Tigeot { 781c6f73aabSFrançois Tigeot radeon_pm_suspend(rdev); 782*c59a5c48SFrançois Tigeot radeon_audio_fini(rdev); 783926deccbSFrançois Tigeot r100_cp_disable(rdev); 784926deccbSFrançois Tigeot radeon_wb_disable(rdev); 785926deccbSFrançois Tigeot rs600_irq_disable(rdev); 786926deccbSFrançois Tigeot rs400_gart_disable(rdev); 787926deccbSFrançois Tigeot return 0; 788926deccbSFrançois Tigeot } 789926deccbSFrançois Tigeot 790926deccbSFrançois Tigeot void rs690_fini(struct radeon_device *rdev) 791926deccbSFrançois Tigeot { 792c6f73aabSFrançois Tigeot radeon_pm_fini(rdev); 793*c59a5c48SFrançois Tigeot radeon_audio_fini(rdev); 794926deccbSFrançois Tigeot r100_cp_fini(rdev); 795926deccbSFrançois Tigeot radeon_wb_fini(rdev); 796926deccbSFrançois Tigeot radeon_ib_pool_fini(rdev); 797926deccbSFrançois Tigeot radeon_gem_fini(rdev); 798926deccbSFrançois Tigeot rs400_gart_fini(rdev); 799926deccbSFrançois Tigeot radeon_irq_kms_fini(rdev); 800926deccbSFrançois Tigeot radeon_fence_driver_fini(rdev); 801926deccbSFrançois Tigeot radeon_bo_fini(rdev); 802926deccbSFrançois Tigeot radeon_atombios_fini(rdev); 803c4ef309bSzrj kfree(rdev->bios); 804926deccbSFrançois Tigeot rdev->bios = NULL; 805926deccbSFrançois Tigeot } 806926deccbSFrançois Tigeot 807926deccbSFrançois Tigeot int rs690_init(struct radeon_device *rdev) 808926deccbSFrançois Tigeot { 809926deccbSFrançois Tigeot int r; 810926deccbSFrançois Tigeot 811926deccbSFrançois Tigeot /* Disable VGA */ 812926deccbSFrançois Tigeot rv515_vga_render_disable(rdev); 813926deccbSFrançois Tigeot /* Initialize scratch registers */ 814926deccbSFrançois Tigeot radeon_scratch_init(rdev); 815926deccbSFrançois Tigeot /* Initialize surface registers */ 816926deccbSFrançois Tigeot radeon_surface_init(rdev); 817926deccbSFrançois Tigeot /* restore some register to sane defaults */ 818926deccbSFrançois Tigeot r100_restore_sanity(rdev); 819926deccbSFrançois Tigeot /* TODO: disable VGA need to use VGA request */ 820926deccbSFrançois Tigeot /* BIOS*/ 821926deccbSFrançois Tigeot if (!radeon_get_bios(rdev)) { 822926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) 823926deccbSFrançois Tigeot return -EINVAL; 824926deccbSFrançois Tigeot } 825926deccbSFrançois Tigeot if (rdev->is_atom_bios) { 826926deccbSFrançois Tigeot r = radeon_atombios_init(rdev); 827926deccbSFrançois Tigeot if (r) 828926deccbSFrançois Tigeot return r; 829926deccbSFrançois Tigeot } else { 830926deccbSFrançois Tigeot dev_err(rdev->dev, "Expecting atombios for RV515 GPU\n"); 831926deccbSFrançois Tigeot return -EINVAL; 832926deccbSFrançois Tigeot } 833926deccbSFrançois Tigeot /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 834926deccbSFrançois Tigeot if (radeon_asic_reset(rdev)) { 835926deccbSFrançois Tigeot dev_warn(rdev->dev, 836926deccbSFrançois Tigeot "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 837926deccbSFrançois Tigeot RREG32(R_000E40_RBBM_STATUS), 838926deccbSFrançois Tigeot RREG32(R_0007C0_CP_STAT)); 839926deccbSFrançois Tigeot } 840926deccbSFrançois Tigeot /* check if cards are posted or not */ 841926deccbSFrançois Tigeot if (radeon_boot_test_post_card(rdev) == false) 842926deccbSFrançois Tigeot return -EINVAL; 843926deccbSFrançois Tigeot 844926deccbSFrançois Tigeot /* Initialize clocks */ 845926deccbSFrançois Tigeot radeon_get_clock_info(rdev->ddev); 846926deccbSFrançois Tigeot /* initialize memory controller */ 847926deccbSFrançois Tigeot rs690_mc_init(rdev); 848926deccbSFrançois Tigeot rv515_debugfs(rdev); 849926deccbSFrançois Tigeot /* Fence driver */ 850926deccbSFrançois Tigeot r = radeon_fence_driver_init(rdev); 851926deccbSFrançois Tigeot if (r) 852926deccbSFrançois Tigeot return r; 853926deccbSFrançois Tigeot /* Memory manager */ 854926deccbSFrançois Tigeot r = radeon_bo_init(rdev); 855926deccbSFrançois Tigeot if (r) 856926deccbSFrançois Tigeot return r; 857926deccbSFrançois Tigeot r = rs400_gart_init(rdev); 858926deccbSFrançois Tigeot if (r) 859926deccbSFrançois Tigeot return r; 860926deccbSFrançois Tigeot rs600_set_safe_registers(rdev); 861926deccbSFrançois Tigeot 862c6f73aabSFrançois Tigeot /* Initialize power management */ 863c6f73aabSFrançois Tigeot radeon_pm_init(rdev); 864c6f73aabSFrançois Tigeot 865926deccbSFrançois Tigeot rdev->accel_working = true; 866926deccbSFrançois Tigeot r = rs690_startup(rdev); 867926deccbSFrançois Tigeot if (r) { 868926deccbSFrançois Tigeot /* Somethings want wront with the accel init stop accel */ 869926deccbSFrançois Tigeot dev_err(rdev->dev, "Disabling GPU acceleration\n"); 870926deccbSFrançois Tigeot r100_cp_fini(rdev); 871926deccbSFrançois Tigeot radeon_wb_fini(rdev); 872926deccbSFrançois Tigeot radeon_ib_pool_fini(rdev); 873926deccbSFrançois Tigeot rs400_gart_fini(rdev); 874926deccbSFrançois Tigeot radeon_irq_kms_fini(rdev); 875926deccbSFrançois Tigeot rdev->accel_working = false; 876926deccbSFrançois Tigeot } 877926deccbSFrançois Tigeot return 0; 878926deccbSFrançois Tigeot } 879