1254885Sdumbbell/* 2254885Sdumbbell * Copyright 2008 Advanced Micro Devices, Inc. 3254885Sdumbbell * Copyright 2008 Red Hat Inc. 4254885Sdumbbell * Copyright 2009 Jerome Glisse. 5254885Sdumbbell * 6254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 7254885Sdumbbell * copy of this software and associated documentation files (the "Software"), 8254885Sdumbbell * to deal in the Software without restriction, including without limitation 9254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 11254885Sdumbbell * Software is furnished to do so, subject to the following conditions: 12254885Sdumbbell * 13254885Sdumbbell * The above copyright notice and this permission notice shall be included in 14254885Sdumbbell * all copies or substantial portions of the Software. 15254885Sdumbbell * 16254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE. 23254885Sdumbbell * 24254885Sdumbbell * Authors: Dave Airlie 25254885Sdumbbell * Alex Deucher 26254885Sdumbbell * Jerome Glisse 27254885Sdumbbell */ 28254885Sdumbbell 29254885Sdumbbell#include <sys/cdefs.h> 30254885Sdumbbell__FBSDID("$FreeBSD$"); 31254885Sdumbbell 32263170Sdumbbell#include <sys/limits.h> 33263170Sdumbbell 34254885Sdumbbell#include <dev/drm2/drmP.h> 35254885Sdumbbell#include "radeon.h" 36254885Sdumbbell#include "radeon_asic.h" 37254885Sdumbbell#include "atom.h" 38254885Sdumbbell#include "rs690d.h" 39254885Sdumbbell 40254885Sdumbbellint rs690_mc_wait_for_idle(struct radeon_device *rdev) 41254885Sdumbbell{ 42254885Sdumbbell unsigned i; 43254885Sdumbbell uint32_t tmp; 44254885Sdumbbell 45254885Sdumbbell for (i = 0; i < rdev->usec_timeout; i++) { 46254885Sdumbbell /* read MC_STATUS */ 47254885Sdumbbell tmp = RREG32_MC(R_000090_MC_SYSTEM_STATUS); 48254885Sdumbbell if (G_000090_MC_SYSTEM_IDLE(tmp)) 49254885Sdumbbell return 0; 50254885Sdumbbell DRM_UDELAY(1); 51254885Sdumbbell } 52254885Sdumbbell return -1; 53254885Sdumbbell} 54254885Sdumbbell 55254885Sdumbbellstatic void rs690_gpu_init(struct radeon_device *rdev) 56254885Sdumbbell{ 57254885Sdumbbell /* FIXME: is this correct ? */ 58254885Sdumbbell r420_pipes_init(rdev); 59254885Sdumbbell if (rs690_mc_wait_for_idle(rdev)) { 60254885Sdumbbell DRM_ERROR("Failed to wait MC idle while " 61254885Sdumbbell "programming pipes. Bad things might happen.\n"); 62254885Sdumbbell } 63254885Sdumbbell} 64254885Sdumbbell 65254885Sdumbbellunion igp_info { 66254885Sdumbbell struct _ATOM_INTEGRATED_SYSTEM_INFO info; 67254885Sdumbbell struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_v2; 68254885Sdumbbell}; 69254885Sdumbbell 70254885Sdumbbellvoid rs690_pm_info(struct radeon_device *rdev) 71254885Sdumbbell{ 72254885Sdumbbell int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 73254885Sdumbbell union igp_info *info; 74254885Sdumbbell uint16_t data_offset; 75254885Sdumbbell uint8_t frev, crev; 76254885Sdumbbell fixed20_12 tmp; 77254885Sdumbbell 78254885Sdumbbell if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL, 79254885Sdumbbell &frev, &crev, &data_offset)) { 80254885Sdumbbell info = (union igp_info *)((uintptr_t)rdev->mode_info.atom_context->bios + data_offset); 81254885Sdumbbell 82254885Sdumbbell /* Get various system informations from bios */ 83254885Sdumbbell switch (crev) { 84254885Sdumbbell case 1: 85254885Sdumbbell tmp.full = dfixed_const(100); 86254885Sdumbbell rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info.ulBootUpMemoryClock)); 87254885Sdumbbell rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp); 88254885Sdumbbell if (le16_to_cpu(info->info.usK8MemoryClock)) 89254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_const(le16_to_cpu(info->info.usK8MemoryClock)); 90254885Sdumbbell else if (rdev->clock.default_mclk) { 91254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk); 92254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp); 93254885Sdumbbell } else 94254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_const(400); 95254885Sdumbbell rdev->pm.igp_ht_link_clk.full = dfixed_const(le16_to_cpu(info->info.usFSBClock)); 96254885Sdumbbell rdev->pm.igp_ht_link_width.full = dfixed_const(info->info.ucHTLinkWidth); 97254885Sdumbbell break; 98254885Sdumbbell case 2: 99254885Sdumbbell tmp.full = dfixed_const(100); 100254885Sdumbbell rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpSidePortClock)); 101254885Sdumbbell rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp); 102254885Sdumbbell if (le32_to_cpu(info->info_v2.ulBootUpUMAClock)) 103254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpUMAClock)); 104254885Sdumbbell else if (rdev->clock.default_mclk) 105254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk); 106254885Sdumbbell else 107254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_const(66700); 108254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp); 109254885Sdumbbell rdev->pm.igp_ht_link_clk.full = dfixed_const(le32_to_cpu(info->info_v2.ulHTLinkFreq)); 110254885Sdumbbell rdev->pm.igp_ht_link_clk.full = dfixed_div(rdev->pm.igp_ht_link_clk, tmp); 111254885Sdumbbell rdev->pm.igp_ht_link_width.full = dfixed_const(le16_to_cpu(info->info_v2.usMinHTLinkWidth)); 112254885Sdumbbell break; 113254885Sdumbbell default: 114254885Sdumbbell /* We assume the slower possible clock ie worst case */ 115254885Sdumbbell rdev->pm.igp_sideport_mclk.full = dfixed_const(200); 116254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_const(200); 117254885Sdumbbell rdev->pm.igp_ht_link_clk.full = dfixed_const(1000); 118254885Sdumbbell rdev->pm.igp_ht_link_width.full = dfixed_const(8); 119254885Sdumbbell DRM_ERROR("No integrated system info for your GPU, using safe default\n"); 120254885Sdumbbell break; 121254885Sdumbbell } 122254885Sdumbbell } else { 123254885Sdumbbell /* We assume the slower possible clock ie worst case */ 124254885Sdumbbell rdev->pm.igp_sideport_mclk.full = dfixed_const(200); 125254885Sdumbbell rdev->pm.igp_system_mclk.full = dfixed_const(200); 126254885Sdumbbell rdev->pm.igp_ht_link_clk.full = dfixed_const(1000); 127254885Sdumbbell rdev->pm.igp_ht_link_width.full = dfixed_const(8); 128254885Sdumbbell DRM_ERROR("No integrated system info for your GPU, using safe default\n"); 129254885Sdumbbell } 130254885Sdumbbell /* Compute various bandwidth */ 131254885Sdumbbell /* k8_bandwidth = (memory_clk / 2) * 2 * 8 * 0.5 = memory_clk * 4 */ 132254885Sdumbbell tmp.full = dfixed_const(4); 133254885Sdumbbell rdev->pm.k8_bandwidth.full = dfixed_mul(rdev->pm.igp_system_mclk, tmp); 134254885Sdumbbell /* ht_bandwidth = ht_clk * 2 * ht_width / 8 * 0.8 135254885Sdumbbell * = ht_clk * ht_width / 5 136254885Sdumbbell */ 137254885Sdumbbell tmp.full = dfixed_const(5); 138254885Sdumbbell rdev->pm.ht_bandwidth.full = dfixed_mul(rdev->pm.igp_ht_link_clk, 139254885Sdumbbell rdev->pm.igp_ht_link_width); 140254885Sdumbbell rdev->pm.ht_bandwidth.full = dfixed_div(rdev->pm.ht_bandwidth, tmp); 141254885Sdumbbell if (tmp.full < rdev->pm.max_bandwidth.full) { 142254885Sdumbbell /* HT link is a limiting factor */ 143254885Sdumbbell rdev->pm.max_bandwidth.full = tmp.full; 144254885Sdumbbell } 145254885Sdumbbell /* sideport_bandwidth = (sideport_clk / 2) * 2 * 2 * 0.7 146254885Sdumbbell * = (sideport_clk * 14) / 10 147254885Sdumbbell */ 148254885Sdumbbell tmp.full = dfixed_const(14); 149254885Sdumbbell rdev->pm.sideport_bandwidth.full = dfixed_mul(rdev->pm.igp_sideport_mclk, tmp); 150254885Sdumbbell tmp.full = dfixed_const(10); 151254885Sdumbbell rdev->pm.sideport_bandwidth.full = dfixed_div(rdev->pm.sideport_bandwidth, tmp); 152254885Sdumbbell} 153254885Sdumbbell 154254885Sdumbbellstatic void rs690_mc_init(struct radeon_device *rdev) 155254885Sdumbbell{ 156254885Sdumbbell u64 base; 157254885Sdumbbell 158254885Sdumbbell rs400_gart_adjust_size(rdev); 159254885Sdumbbell rdev->mc.vram_is_ddr = true; 160254885Sdumbbell rdev->mc.vram_width = 128; 161254885Sdumbbell rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE); 162254885Sdumbbell rdev->mc.mc_vram_size = rdev->mc.real_vram_size; 163254885Sdumbbell rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); 164254885Sdumbbell rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); 165254885Sdumbbell rdev->mc.visible_vram_size = rdev->mc.aper_size; 166254885Sdumbbell base = RREG32_MC(R_000100_MCCFG_FB_LOCATION); 167254885Sdumbbell base = G_000100_MC_FB_START(base) << 16; 168254885Sdumbbell rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); 169254885Sdumbbell rs690_pm_info(rdev); 170254885Sdumbbell radeon_vram_location(rdev, &rdev->mc, base); 171254885Sdumbbell rdev->mc.gtt_base_align = rdev->mc.gtt_size - 1; 172254885Sdumbbell radeon_gtt_location(rdev, &rdev->mc); 173254885Sdumbbell radeon_update_bandwidth_info(rdev); 174254885Sdumbbell} 175254885Sdumbbell 176254885Sdumbbellvoid rs690_line_buffer_adjust(struct radeon_device *rdev, 177254885Sdumbbell struct drm_display_mode *mode1, 178254885Sdumbbell struct drm_display_mode *mode2) 179254885Sdumbbell{ 180254885Sdumbbell u32 tmp; 181254885Sdumbbell 182254885Sdumbbell /* 183254885Sdumbbell * Line Buffer Setup 184254885Sdumbbell * There is a single line buffer shared by both display controllers. 185254885Sdumbbell * R_006520_DC_LB_MEMORY_SPLIT controls how that line buffer is shared between 186254885Sdumbbell * the display controllers. The paritioning can either be done 187254885Sdumbbell * manually or via one of four preset allocations specified in bits 1:0: 188254885Sdumbbell * 0 - line buffer is divided in half and shared between crtc 189254885Sdumbbell * 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4 190254885Sdumbbell * 2 - D1 gets the whole buffer 191254885Sdumbbell * 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4 192254885Sdumbbell * Setting bit 2 of R_006520_DC_LB_MEMORY_SPLIT controls switches to manual 193254885Sdumbbell * allocation mode. In manual allocation mode, D1 always starts at 0, 194254885Sdumbbell * D1 end/2 is specified in bits 14:4; D2 allocation follows D1. 195254885Sdumbbell */ 196254885Sdumbbell tmp = RREG32(R_006520_DC_LB_MEMORY_SPLIT) & C_006520_DC_LB_MEMORY_SPLIT; 197254885Sdumbbell tmp &= ~C_006520_DC_LB_MEMORY_SPLIT_MODE; 198254885Sdumbbell /* auto */ 199254885Sdumbbell if (mode1 && mode2) { 200254885Sdumbbell if (mode1->hdisplay > mode2->hdisplay) { 201254885Sdumbbell if (mode1->hdisplay > 2560) 202254885Sdumbbell tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q; 203254885Sdumbbell else 204254885Sdumbbell tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; 205254885Sdumbbell } else if (mode2->hdisplay > mode1->hdisplay) { 206254885Sdumbbell if (mode2->hdisplay > 2560) 207254885Sdumbbell tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; 208254885Sdumbbell else 209254885Sdumbbell tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; 210254885Sdumbbell } else 211254885Sdumbbell tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; 212254885Sdumbbell } else if (mode1) { 213254885Sdumbbell tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_ONLY; 214254885Sdumbbell } else if (mode2) { 215254885Sdumbbell tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; 216254885Sdumbbell } 217254885Sdumbbell WREG32(R_006520_DC_LB_MEMORY_SPLIT, tmp); 218254885Sdumbbell} 219254885Sdumbbell 220254885Sdumbbellstruct rs690_watermark { 221254885Sdumbbell u32 lb_request_fifo_depth; 222254885Sdumbbell fixed20_12 num_line_pair; 223254885Sdumbbell fixed20_12 estimated_width; 224254885Sdumbbell fixed20_12 worst_case_latency; 225254885Sdumbbell fixed20_12 consumption_rate; 226254885Sdumbbell fixed20_12 active_time; 227254885Sdumbbell fixed20_12 dbpp; 228254885Sdumbbell fixed20_12 priority_mark_max; 229254885Sdumbbell fixed20_12 priority_mark; 230254885Sdumbbell fixed20_12 sclk; 231254885Sdumbbell}; 232254885Sdumbbell 233254885Sdumbbellstatic void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, 234254885Sdumbbell struct radeon_crtc *crtc, 235254885Sdumbbell struct rs690_watermark *wm) 236254885Sdumbbell{ 237254885Sdumbbell struct drm_display_mode *mode = &crtc->base.mode; 238254885Sdumbbell fixed20_12 a, b, c; 239254885Sdumbbell fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width; 240254885Sdumbbell fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency; 241254885Sdumbbell 242254885Sdumbbell if (!crtc->base.enabled) { 243254885Sdumbbell /* FIXME: wouldn't it better to set priority mark to maximum */ 244254885Sdumbbell wm->lb_request_fifo_depth = 4; 245254885Sdumbbell return; 246254885Sdumbbell } 247254885Sdumbbell 248254885Sdumbbell if (crtc->vsc.full > dfixed_const(2)) 249254885Sdumbbell wm->num_line_pair.full = dfixed_const(2); 250254885Sdumbbell else 251254885Sdumbbell wm->num_line_pair.full = dfixed_const(1); 252254885Sdumbbell 253254885Sdumbbell b.full = dfixed_const(mode->crtc_hdisplay); 254254885Sdumbbell c.full = dfixed_const(256); 255254885Sdumbbell a.full = dfixed_div(b, c); 256254885Sdumbbell request_fifo_depth.full = dfixed_mul(a, wm->num_line_pair); 257254885Sdumbbell request_fifo_depth.full = dfixed_ceil(request_fifo_depth); 258254885Sdumbbell if (a.full < dfixed_const(4)) { 259254885Sdumbbell wm->lb_request_fifo_depth = 4; 260254885Sdumbbell } else { 261254885Sdumbbell wm->lb_request_fifo_depth = dfixed_trunc(request_fifo_depth); 262254885Sdumbbell } 263254885Sdumbbell 264254885Sdumbbell /* Determine consumption rate 265254885Sdumbbell * pclk = pixel clock period(ns) = 1000 / (mode.clock / 1000) 266254885Sdumbbell * vtaps = number of vertical taps, 267254885Sdumbbell * vsc = vertical scaling ratio, defined as source/destination 268254885Sdumbbell * hsc = horizontal scaling ration, defined as source/destination 269254885Sdumbbell */ 270254885Sdumbbell a.full = dfixed_const(mode->clock); 271254885Sdumbbell b.full = dfixed_const(1000); 272254885Sdumbbell a.full = dfixed_div(a, b); 273254885Sdumbbell pclk.full = dfixed_div(b, a); 274254885Sdumbbell if (crtc->rmx_type != RMX_OFF) { 275254885Sdumbbell b.full = dfixed_const(2); 276254885Sdumbbell if (crtc->vsc.full > b.full) 277254885Sdumbbell b.full = crtc->vsc.full; 278254885Sdumbbell b.full = dfixed_mul(b, crtc->hsc); 279254885Sdumbbell c.full = dfixed_const(2); 280254885Sdumbbell b.full = dfixed_div(b, c); 281254885Sdumbbell consumption_time.full = dfixed_div(pclk, b); 282254885Sdumbbell } else { 283254885Sdumbbell consumption_time.full = pclk.full; 284254885Sdumbbell } 285254885Sdumbbell a.full = dfixed_const(1); 286254885Sdumbbell wm->consumption_rate.full = dfixed_div(a, consumption_time); 287254885Sdumbbell 288254885Sdumbbell 289254885Sdumbbell /* Determine line time 290254885Sdumbbell * LineTime = total time for one line of displayhtotal 291254885Sdumbbell * LineTime = total number of horizontal pixels 292254885Sdumbbell * pclk = pixel clock period(ns) 293254885Sdumbbell */ 294254885Sdumbbell a.full = dfixed_const(crtc->base.mode.crtc_htotal); 295254885Sdumbbell line_time.full = dfixed_mul(a, pclk); 296254885Sdumbbell 297254885Sdumbbell /* Determine active time 298254885Sdumbbell * ActiveTime = time of active region of display within one line, 299254885Sdumbbell * hactive = total number of horizontal active pixels 300254885Sdumbbell * htotal = total number of horizontal pixels 301254885Sdumbbell */ 302254885Sdumbbell a.full = dfixed_const(crtc->base.mode.crtc_htotal); 303254885Sdumbbell b.full = dfixed_const(crtc->base.mode.crtc_hdisplay); 304254885Sdumbbell wm->active_time.full = dfixed_mul(line_time, b); 305254885Sdumbbell wm->active_time.full = dfixed_div(wm->active_time, a); 306254885Sdumbbell 307254885Sdumbbell /* Maximun bandwidth is the minimun bandwidth of all component */ 308254885Sdumbbell rdev->pm.max_bandwidth = rdev->pm.core_bandwidth; 309254885Sdumbbell if (rdev->mc.igp_sideport_enabled) { 310254885Sdumbbell if (rdev->pm.max_bandwidth.full > rdev->pm.sideport_bandwidth.full && 311254885Sdumbbell rdev->pm.sideport_bandwidth.full) 312254885Sdumbbell rdev->pm.max_bandwidth = rdev->pm.sideport_bandwidth; 313254885Sdumbbell#ifdef DUMBBELL_WIP 314254885Sdumbbell read_delay_latency.full = dfixed_const(370 * 800 * 1000); 315254885Sdumbbell#endif /* DUMBBELL_WIP */ 316254885Sdumbbell read_delay_latency.full = UINT_MAX; 317254885Sdumbbell read_delay_latency.full = dfixed_div(read_delay_latency, 318254885Sdumbbell rdev->pm.igp_sideport_mclk); 319254885Sdumbbell } else { 320254885Sdumbbell if (rdev->pm.max_bandwidth.full > rdev->pm.k8_bandwidth.full && 321254885Sdumbbell rdev->pm.k8_bandwidth.full) 322254885Sdumbbell rdev->pm.max_bandwidth = rdev->pm.k8_bandwidth; 323254885Sdumbbell if (rdev->pm.max_bandwidth.full > rdev->pm.ht_bandwidth.full && 324254885Sdumbbell rdev->pm.ht_bandwidth.full) 325254885Sdumbbell rdev->pm.max_bandwidth = rdev->pm.ht_bandwidth; 326254885Sdumbbell read_delay_latency.full = dfixed_const(5000); 327254885Sdumbbell } 328254885Sdumbbell 329254885Sdumbbell /* sclk = system clocks(ns) = 1000 / max_bandwidth / 16 */ 330254885Sdumbbell a.full = dfixed_const(16); 331254885Sdumbbell rdev->pm.sclk.full = dfixed_mul(rdev->pm.max_bandwidth, a); 332254885Sdumbbell a.full = dfixed_const(1000); 333254885Sdumbbell rdev->pm.sclk.full = dfixed_div(a, rdev->pm.sclk); 334254885Sdumbbell /* Determine chunk time 335254885Sdumbbell * ChunkTime = the time it takes the DCP to send one chunk of data 336254885Sdumbbell * to the LB which consists of pipeline delay and inter chunk gap 337254885Sdumbbell * sclk = system clock(ns) 338254885Sdumbbell */ 339254885Sdumbbell a.full = dfixed_const(256 * 13); 340254885Sdumbbell chunk_time.full = dfixed_mul(rdev->pm.sclk, a); 341254885Sdumbbell a.full = dfixed_const(10); 342254885Sdumbbell chunk_time.full = dfixed_div(chunk_time, a); 343254885Sdumbbell 344254885Sdumbbell /* Determine the worst case latency 345254885Sdumbbell * NumLinePair = Number of line pairs to request(1=2 lines, 2=4 lines) 346254885Sdumbbell * WorstCaseLatency = worst case time from urgent to when the MC starts 347254885Sdumbbell * to return data 348254885Sdumbbell * READ_DELAY_IDLE_MAX = constant of 1us 349254885Sdumbbell * ChunkTime = time it takes the DCP to send one chunk of data to the LB 350254885Sdumbbell * which consists of pipeline delay and inter chunk gap 351254885Sdumbbell */ 352254885Sdumbbell if (dfixed_trunc(wm->num_line_pair) > 1) { 353254885Sdumbbell a.full = dfixed_const(3); 354254885Sdumbbell wm->worst_case_latency.full = dfixed_mul(a, chunk_time); 355254885Sdumbbell wm->worst_case_latency.full += read_delay_latency.full; 356254885Sdumbbell } else { 357254885Sdumbbell a.full = dfixed_const(2); 358254885Sdumbbell wm->worst_case_latency.full = dfixed_mul(a, chunk_time); 359254885Sdumbbell wm->worst_case_latency.full += read_delay_latency.full; 360254885Sdumbbell } 361254885Sdumbbell 362254885Sdumbbell /* Determine the tolerable latency 363254885Sdumbbell * TolerableLatency = Any given request has only 1 line time 364254885Sdumbbell * for the data to be returned 365254885Sdumbbell * LBRequestFifoDepth = Number of chunk requests the LB can 366254885Sdumbbell * put into the request FIFO for a display 367254885Sdumbbell * LineTime = total time for one line of display 368254885Sdumbbell * ChunkTime = the time it takes the DCP to send one chunk 369254885Sdumbbell * of data to the LB which consists of 370254885Sdumbbell * pipeline delay and inter chunk gap 371254885Sdumbbell */ 372254885Sdumbbell if ((2+wm->lb_request_fifo_depth) >= dfixed_trunc(request_fifo_depth)) { 373254885Sdumbbell tolerable_latency.full = line_time.full; 374254885Sdumbbell } else { 375254885Sdumbbell tolerable_latency.full = dfixed_const(wm->lb_request_fifo_depth - 2); 376254885Sdumbbell tolerable_latency.full = request_fifo_depth.full - tolerable_latency.full; 377254885Sdumbbell tolerable_latency.full = dfixed_mul(tolerable_latency, chunk_time); 378254885Sdumbbell tolerable_latency.full = line_time.full - tolerable_latency.full; 379254885Sdumbbell } 380254885Sdumbbell /* We assume worst case 32bits (4 bytes) */ 381254885Sdumbbell wm->dbpp.full = dfixed_const(4 * 8); 382254885Sdumbbell 383254885Sdumbbell /* Determine the maximum priority mark 384254885Sdumbbell * width = viewport width in pixels 385254885Sdumbbell */ 386254885Sdumbbell a.full = dfixed_const(16); 387254885Sdumbbell wm->priority_mark_max.full = dfixed_const(crtc->base.mode.crtc_hdisplay); 388254885Sdumbbell wm->priority_mark_max.full = dfixed_div(wm->priority_mark_max, a); 389254885Sdumbbell wm->priority_mark_max.full = dfixed_ceil(wm->priority_mark_max); 390254885Sdumbbell 391254885Sdumbbell /* Determine estimated width */ 392254885Sdumbbell estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full; 393254885Sdumbbell estimated_width.full = dfixed_div(estimated_width, consumption_time); 394254885Sdumbbell if (dfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) { 395254885Sdumbbell wm->priority_mark.full = dfixed_const(10); 396254885Sdumbbell } else { 397254885Sdumbbell a.full = dfixed_const(16); 398254885Sdumbbell wm->priority_mark.full = dfixed_div(estimated_width, a); 399254885Sdumbbell wm->priority_mark.full = dfixed_ceil(wm->priority_mark); 400254885Sdumbbell wm->priority_mark.full = wm->priority_mark_max.full - wm->priority_mark.full; 401254885Sdumbbell } 402254885Sdumbbell} 403254885Sdumbbell 404254885Sdumbbellvoid rs690_bandwidth_update(struct radeon_device *rdev) 405254885Sdumbbell{ 406254885Sdumbbell struct drm_display_mode *mode0 = NULL; 407254885Sdumbbell struct drm_display_mode *mode1 = NULL; 408254885Sdumbbell struct rs690_watermark wm0; 409254885Sdumbbell struct rs690_watermark wm1; 410254885Sdumbbell u32 tmp; 411254885Sdumbbell u32 d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); 412254885Sdumbbell u32 d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); 413254885Sdumbbell fixed20_12 priority_mark02, priority_mark12, fill_rate; 414254885Sdumbbell fixed20_12 a, b; 415254885Sdumbbell 416254885Sdumbbell radeon_update_display_priority(rdev); 417254885Sdumbbell 418254885Sdumbbell if (rdev->mode_info.crtcs[0]->base.enabled) 419254885Sdumbbell mode0 = &rdev->mode_info.crtcs[0]->base.mode; 420254885Sdumbbell if (rdev->mode_info.crtcs[1]->base.enabled) 421254885Sdumbbell mode1 = &rdev->mode_info.crtcs[1]->base.mode; 422254885Sdumbbell /* 423254885Sdumbbell * Set display0/1 priority up in the memory controller for 424254885Sdumbbell * modes if the user specifies HIGH for displaypriority 425254885Sdumbbell * option. 426254885Sdumbbell */ 427254885Sdumbbell if ((rdev->disp_priority == 2) && 428254885Sdumbbell ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))) { 429254885Sdumbbell tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER); 430254885Sdumbbell tmp &= C_000104_MC_DISP0R_INIT_LAT; 431254885Sdumbbell tmp &= C_000104_MC_DISP1R_INIT_LAT; 432254885Sdumbbell if (mode0) 433254885Sdumbbell tmp |= S_000104_MC_DISP0R_INIT_LAT(1); 434254885Sdumbbell if (mode1) 435254885Sdumbbell tmp |= S_000104_MC_DISP1R_INIT_LAT(1); 436254885Sdumbbell WREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER, tmp); 437254885Sdumbbell } 438254885Sdumbbell rs690_line_buffer_adjust(rdev, mode0, mode1); 439254885Sdumbbell 440254885Sdumbbell if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) 441254885Sdumbbell WREG32(R_006C9C_DCP_CONTROL, 0); 442254885Sdumbbell if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) 443254885Sdumbbell WREG32(R_006C9C_DCP_CONTROL, 2); 444254885Sdumbbell 445254885Sdumbbell rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0); 446254885Sdumbbell rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1); 447254885Sdumbbell 448254885Sdumbbell tmp = (wm0.lb_request_fifo_depth - 1); 449254885Sdumbbell tmp |= (wm1.lb_request_fifo_depth - 1) << 16; 450254885Sdumbbell WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp); 451254885Sdumbbell 452254885Sdumbbell if (mode0 && mode1) { 453254885Sdumbbell if (dfixed_trunc(wm0.dbpp) > 64) 454254885Sdumbbell a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair); 455254885Sdumbbell else 456254885Sdumbbell a.full = wm0.num_line_pair.full; 457254885Sdumbbell if (dfixed_trunc(wm1.dbpp) > 64) 458254885Sdumbbell b.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair); 459254885Sdumbbell else 460254885Sdumbbell b.full = wm1.num_line_pair.full; 461254885Sdumbbell a.full += b.full; 462254885Sdumbbell fill_rate.full = dfixed_div(wm0.sclk, a); 463254885Sdumbbell if (wm0.consumption_rate.full > fill_rate.full) { 464254885Sdumbbell b.full = wm0.consumption_rate.full - fill_rate.full; 465254885Sdumbbell b.full = dfixed_mul(b, wm0.active_time); 466254885Sdumbbell a.full = dfixed_mul(wm0.worst_case_latency, 467254885Sdumbbell wm0.consumption_rate); 468254885Sdumbbell a.full = a.full + b.full; 469254885Sdumbbell b.full = dfixed_const(16 * 1000); 470254885Sdumbbell priority_mark02.full = dfixed_div(a, b); 471254885Sdumbbell } else { 472254885Sdumbbell a.full = dfixed_mul(wm0.worst_case_latency, 473254885Sdumbbell wm0.consumption_rate); 474254885Sdumbbell b.full = dfixed_const(16 * 1000); 475254885Sdumbbell priority_mark02.full = dfixed_div(a, b); 476254885Sdumbbell } 477254885Sdumbbell if (wm1.consumption_rate.full > fill_rate.full) { 478254885Sdumbbell b.full = wm1.consumption_rate.full - fill_rate.full; 479254885Sdumbbell b.full = dfixed_mul(b, wm1.active_time); 480254885Sdumbbell a.full = dfixed_mul(wm1.worst_case_latency, 481254885Sdumbbell wm1.consumption_rate); 482254885Sdumbbell a.full = a.full + b.full; 483254885Sdumbbell b.full = dfixed_const(16 * 1000); 484254885Sdumbbell priority_mark12.full = dfixed_div(a, b); 485254885Sdumbbell } else { 486254885Sdumbbell a.full = dfixed_mul(wm1.worst_case_latency, 487254885Sdumbbell wm1.consumption_rate); 488254885Sdumbbell b.full = dfixed_const(16 * 1000); 489254885Sdumbbell priority_mark12.full = dfixed_div(a, b); 490254885Sdumbbell } 491254885Sdumbbell if (wm0.priority_mark.full > priority_mark02.full) 492254885Sdumbbell priority_mark02.full = wm0.priority_mark.full; 493254885Sdumbbell if (dfixed_trunc(priority_mark02) < 0) 494254885Sdumbbell priority_mark02.full = 0; 495254885Sdumbbell if (wm0.priority_mark_max.full > priority_mark02.full) 496254885Sdumbbell priority_mark02.full = wm0.priority_mark_max.full; 497254885Sdumbbell if (wm1.priority_mark.full > priority_mark12.full) 498254885Sdumbbell priority_mark12.full = wm1.priority_mark.full; 499254885Sdumbbell if (dfixed_trunc(priority_mark12) < 0) 500254885Sdumbbell priority_mark12.full = 0; 501254885Sdumbbell if (wm1.priority_mark_max.full > priority_mark12.full) 502254885Sdumbbell priority_mark12.full = wm1.priority_mark_max.full; 503254885Sdumbbell d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); 504254885Sdumbbell d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); 505254885Sdumbbell if (rdev->disp_priority == 2) { 506254885Sdumbbell d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); 507254885Sdumbbell d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); 508254885Sdumbbell } 509254885Sdumbbell } else if (mode0) { 510254885Sdumbbell if (dfixed_trunc(wm0.dbpp) > 64) 511254885Sdumbbell a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair); 512254885Sdumbbell else 513254885Sdumbbell a.full = wm0.num_line_pair.full; 514254885Sdumbbell fill_rate.full = dfixed_div(wm0.sclk, a); 515254885Sdumbbell if (wm0.consumption_rate.full > fill_rate.full) { 516254885Sdumbbell b.full = wm0.consumption_rate.full - fill_rate.full; 517254885Sdumbbell b.full = dfixed_mul(b, wm0.active_time); 518254885Sdumbbell a.full = dfixed_mul(wm0.worst_case_latency, 519254885Sdumbbell wm0.consumption_rate); 520254885Sdumbbell a.full = a.full + b.full; 521254885Sdumbbell b.full = dfixed_const(16 * 1000); 522254885Sdumbbell priority_mark02.full = dfixed_div(a, b); 523254885Sdumbbell } else { 524254885Sdumbbell a.full = dfixed_mul(wm0.worst_case_latency, 525254885Sdumbbell wm0.consumption_rate); 526254885Sdumbbell b.full = dfixed_const(16 * 1000); 527254885Sdumbbell priority_mark02.full = dfixed_div(a, b); 528254885Sdumbbell } 529254885Sdumbbell if (wm0.priority_mark.full > priority_mark02.full) 530254885Sdumbbell priority_mark02.full = wm0.priority_mark.full; 531254885Sdumbbell if (dfixed_trunc(priority_mark02) < 0) 532254885Sdumbbell priority_mark02.full = 0; 533254885Sdumbbell if (wm0.priority_mark_max.full > priority_mark02.full) 534254885Sdumbbell priority_mark02.full = wm0.priority_mark_max.full; 535254885Sdumbbell d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); 536254885Sdumbbell if (rdev->disp_priority == 2) 537254885Sdumbbell d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); 538254885Sdumbbell } else if (mode1) { 539254885Sdumbbell if (dfixed_trunc(wm1.dbpp) > 64) 540254885Sdumbbell a.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair); 541254885Sdumbbell else 542254885Sdumbbell a.full = wm1.num_line_pair.full; 543254885Sdumbbell fill_rate.full = dfixed_div(wm1.sclk, a); 544254885Sdumbbell if (wm1.consumption_rate.full > fill_rate.full) { 545254885Sdumbbell b.full = wm1.consumption_rate.full - fill_rate.full; 546254885Sdumbbell b.full = dfixed_mul(b, wm1.active_time); 547254885Sdumbbell a.full = dfixed_mul(wm1.worst_case_latency, 548254885Sdumbbell wm1.consumption_rate); 549254885Sdumbbell a.full = a.full + b.full; 550254885Sdumbbell b.full = dfixed_const(16 * 1000); 551254885Sdumbbell priority_mark12.full = dfixed_div(a, b); 552254885Sdumbbell } else { 553254885Sdumbbell a.full = dfixed_mul(wm1.worst_case_latency, 554254885Sdumbbell wm1.consumption_rate); 555254885Sdumbbell b.full = dfixed_const(16 * 1000); 556254885Sdumbbell priority_mark12.full = dfixed_div(a, b); 557254885Sdumbbell } 558254885Sdumbbell if (wm1.priority_mark.full > priority_mark12.full) 559254885Sdumbbell priority_mark12.full = wm1.priority_mark.full; 560254885Sdumbbell if (dfixed_trunc(priority_mark12) < 0) 561254885Sdumbbell priority_mark12.full = 0; 562254885Sdumbbell if (wm1.priority_mark_max.full > priority_mark12.full) 563254885Sdumbbell priority_mark12.full = wm1.priority_mark_max.full; 564254885Sdumbbell d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); 565254885Sdumbbell if (rdev->disp_priority == 2) 566254885Sdumbbell d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); 567254885Sdumbbell } 568254885Sdumbbell 569254885Sdumbbell WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); 570254885Sdumbbell WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); 571254885Sdumbbell WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); 572254885Sdumbbell WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); 573254885Sdumbbell} 574254885Sdumbbell 575254885Sdumbbelluint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg) 576254885Sdumbbell{ 577254885Sdumbbell uint32_t r; 578254885Sdumbbell 579254885Sdumbbell WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg)); 580254885Sdumbbell r = RREG32(R_00007C_MC_DATA); 581254885Sdumbbell WREG32(R_000078_MC_INDEX, ~C_000078_MC_IND_ADDR); 582254885Sdumbbell return r; 583254885Sdumbbell} 584254885Sdumbbell 585254885Sdumbbellvoid rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) 586254885Sdumbbell{ 587254885Sdumbbell WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg) | 588254885Sdumbbell S_000078_MC_IND_WR_EN(1)); 589254885Sdumbbell WREG32(R_00007C_MC_DATA, v); 590254885Sdumbbell WREG32(R_000078_MC_INDEX, 0x7F); 591254885Sdumbbell} 592254885Sdumbbell 593254885Sdumbbellstatic void rs690_mc_program(struct radeon_device *rdev) 594254885Sdumbbell{ 595254885Sdumbbell struct rv515_mc_save save; 596254885Sdumbbell 597254885Sdumbbell /* Stops all mc clients */ 598254885Sdumbbell rv515_mc_stop(rdev, &save); 599254885Sdumbbell 600254885Sdumbbell /* Wait for mc idle */ 601254885Sdumbbell if (rs690_mc_wait_for_idle(rdev)) 602254885Sdumbbell dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n"); 603254885Sdumbbell /* Program MC, should be a 32bits limited address space */ 604254885Sdumbbell WREG32_MC(R_000100_MCCFG_FB_LOCATION, 605254885Sdumbbell S_000100_MC_FB_START(rdev->mc.vram_start >> 16) | 606254885Sdumbbell S_000100_MC_FB_TOP(rdev->mc.vram_end >> 16)); 607254885Sdumbbell WREG32(R_000134_HDP_FB_LOCATION, 608254885Sdumbbell S_000134_HDP_FB_START(rdev->mc.vram_start >> 16)); 609254885Sdumbbell 610254885Sdumbbell rv515_mc_resume(rdev, &save); 611254885Sdumbbell} 612254885Sdumbbell 613254885Sdumbbellstatic int rs690_startup(struct radeon_device *rdev) 614254885Sdumbbell{ 615254885Sdumbbell int r; 616254885Sdumbbell 617254885Sdumbbell rs690_mc_program(rdev); 618254885Sdumbbell /* Resume clock */ 619254885Sdumbbell rv515_clock_startup(rdev); 620254885Sdumbbell /* Initialize GPU configuration (# pipes, ...) */ 621254885Sdumbbell rs690_gpu_init(rdev); 622254885Sdumbbell /* Initialize GART (initialize after TTM so we can allocate 623254885Sdumbbell * memory through TTM but finalize after TTM) */ 624254885Sdumbbell r = rs400_gart_enable(rdev); 625254885Sdumbbell if (r) 626254885Sdumbbell return r; 627254885Sdumbbell 628254885Sdumbbell /* allocate wb buffer */ 629254885Sdumbbell r = radeon_wb_init(rdev); 630254885Sdumbbell if (r) 631254885Sdumbbell return r; 632254885Sdumbbell 633254885Sdumbbell r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX); 634254885Sdumbbell if (r) { 635254885Sdumbbell dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); 636254885Sdumbbell return r; 637254885Sdumbbell } 638254885Sdumbbell 639254885Sdumbbell /* Enable IRQ */ 640254885Sdumbbell rs600_irq_set(rdev); 641254885Sdumbbell rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); 642254885Sdumbbell /* 1M ring buffer */ 643254885Sdumbbell r = r100_cp_init(rdev, 1024 * 1024); 644254885Sdumbbell if (r) { 645254885Sdumbbell dev_err(rdev->dev, "failed initializing CP (%d).\n", r); 646254885Sdumbbell return r; 647254885Sdumbbell } 648254885Sdumbbell 649254885Sdumbbell r = radeon_ib_pool_init(rdev); 650254885Sdumbbell if (r) { 651254885Sdumbbell dev_err(rdev->dev, "IB initialization failed (%d).\n", r); 652254885Sdumbbell return r; 653254885Sdumbbell } 654254885Sdumbbell 655254885Sdumbbell r = r600_audio_init(rdev); 656254885Sdumbbell if (r) { 657254885Sdumbbell dev_err(rdev->dev, "failed initializing audio\n"); 658254885Sdumbbell return r; 659254885Sdumbbell } 660254885Sdumbbell 661254885Sdumbbell return 0; 662254885Sdumbbell} 663254885Sdumbbell 664254885Sdumbbellint rs690_resume(struct radeon_device *rdev) 665254885Sdumbbell{ 666254885Sdumbbell int r; 667254885Sdumbbell 668254885Sdumbbell /* Make sur GART are not working */ 669254885Sdumbbell rs400_gart_disable(rdev); 670254885Sdumbbell /* Resume clock before doing reset */ 671254885Sdumbbell rv515_clock_startup(rdev); 672254885Sdumbbell /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 673254885Sdumbbell if (radeon_asic_reset(rdev)) { 674254885Sdumbbell dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 675254885Sdumbbell RREG32(R_000E40_RBBM_STATUS), 676254885Sdumbbell RREG32(R_0007C0_CP_STAT)); 677254885Sdumbbell } 678254885Sdumbbell /* post */ 679254885Sdumbbell atom_asic_init(rdev->mode_info.atom_context); 680254885Sdumbbell /* Resume clock after posting */ 681254885Sdumbbell rv515_clock_startup(rdev); 682254885Sdumbbell /* Initialize surface registers */ 683254885Sdumbbell radeon_surface_init(rdev); 684254885Sdumbbell 685254885Sdumbbell rdev->accel_working = true; 686254885Sdumbbell r = rs690_startup(rdev); 687254885Sdumbbell if (r) { 688254885Sdumbbell rdev->accel_working = false; 689254885Sdumbbell } 690254885Sdumbbell return r; 691254885Sdumbbell} 692254885Sdumbbell 693254885Sdumbbellint rs690_suspend(struct radeon_device *rdev) 694254885Sdumbbell{ 695254885Sdumbbell r600_audio_fini(rdev); 696254885Sdumbbell r100_cp_disable(rdev); 697254885Sdumbbell radeon_wb_disable(rdev); 698254885Sdumbbell rs600_irq_disable(rdev); 699254885Sdumbbell rs400_gart_disable(rdev); 700254885Sdumbbell return 0; 701254885Sdumbbell} 702254885Sdumbbell 703254885Sdumbbellvoid rs690_fini(struct radeon_device *rdev) 704254885Sdumbbell{ 705254885Sdumbbell r600_audio_fini(rdev); 706254885Sdumbbell r100_cp_fini(rdev); 707254885Sdumbbell radeon_wb_fini(rdev); 708254885Sdumbbell radeon_ib_pool_fini(rdev); 709254885Sdumbbell radeon_gem_fini(rdev); 710254885Sdumbbell rs400_gart_fini(rdev); 711254885Sdumbbell radeon_irq_kms_fini(rdev); 712254885Sdumbbell radeon_fence_driver_fini(rdev); 713254885Sdumbbell radeon_bo_fini(rdev); 714254885Sdumbbell radeon_atombios_fini(rdev); 715254885Sdumbbell free(rdev->bios, DRM_MEM_DRIVER); 716254885Sdumbbell rdev->bios = NULL; 717254885Sdumbbell} 718254885Sdumbbell 719254885Sdumbbellint rs690_init(struct radeon_device *rdev) 720254885Sdumbbell{ 721254885Sdumbbell int r; 722254885Sdumbbell 723254885Sdumbbell /* Disable VGA */ 724254885Sdumbbell rv515_vga_render_disable(rdev); 725254885Sdumbbell /* Initialize scratch registers */ 726254885Sdumbbell radeon_scratch_init(rdev); 727254885Sdumbbell /* Initialize surface registers */ 728254885Sdumbbell radeon_surface_init(rdev); 729254885Sdumbbell /* restore some register to sane defaults */ 730254885Sdumbbell r100_restore_sanity(rdev); 731254885Sdumbbell /* TODO: disable VGA need to use VGA request */ 732254885Sdumbbell /* BIOS*/ 733254885Sdumbbell if (!radeon_get_bios(rdev)) { 734254885Sdumbbell if (ASIC_IS_AVIVO(rdev)) 735254885Sdumbbell return -EINVAL; 736254885Sdumbbell } 737254885Sdumbbell if (rdev->is_atom_bios) { 738254885Sdumbbell r = radeon_atombios_init(rdev); 739254885Sdumbbell if (r) 740254885Sdumbbell return r; 741254885Sdumbbell } else { 742254885Sdumbbell dev_err(rdev->dev, "Expecting atombios for RV515 GPU\n"); 743254885Sdumbbell return -EINVAL; 744254885Sdumbbell } 745254885Sdumbbell /* Reset gpu before posting otherwise ATOM will enter infinite loop */ 746254885Sdumbbell if (radeon_asic_reset(rdev)) { 747254885Sdumbbell dev_warn(rdev->dev, 748254885Sdumbbell "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", 749254885Sdumbbell RREG32(R_000E40_RBBM_STATUS), 750254885Sdumbbell RREG32(R_0007C0_CP_STAT)); 751254885Sdumbbell } 752254885Sdumbbell /* check if cards are posted or not */ 753254885Sdumbbell if (radeon_boot_test_post_card(rdev) == false) 754254885Sdumbbell return -EINVAL; 755254885Sdumbbell 756254885Sdumbbell /* Initialize clocks */ 757254885Sdumbbell radeon_get_clock_info(rdev->ddev); 758254885Sdumbbell /* initialize memory controller */ 759254885Sdumbbell rs690_mc_init(rdev); 760254885Sdumbbell rv515_debugfs(rdev); 761254885Sdumbbell /* Fence driver */ 762254885Sdumbbell r = radeon_fence_driver_init(rdev); 763254885Sdumbbell if (r) 764254885Sdumbbell return r; 765254885Sdumbbell r = radeon_irq_kms_init(rdev); 766254885Sdumbbell if (r) 767254885Sdumbbell return r; 768254885Sdumbbell /* Memory manager */ 769254885Sdumbbell r = radeon_bo_init(rdev); 770254885Sdumbbell if (r) 771254885Sdumbbell return r; 772254885Sdumbbell r = rs400_gart_init(rdev); 773254885Sdumbbell if (r) 774254885Sdumbbell return r; 775254885Sdumbbell rs600_set_safe_registers(rdev); 776254885Sdumbbell 777254885Sdumbbell rdev->accel_working = true; 778254885Sdumbbell r = rs690_startup(rdev); 779254885Sdumbbell if (r) { 780254885Sdumbbell /* Somethings want wront with the accel init stop accel */ 781254885Sdumbbell dev_err(rdev->dev, "Disabling GPU acceleration\n"); 782254885Sdumbbell r100_cp_fini(rdev); 783254885Sdumbbell radeon_wb_fini(rdev); 784254885Sdumbbell radeon_ib_pool_fini(rdev); 785254885Sdumbbell rs400_gart_fini(rdev); 786254885Sdumbbell radeon_irq_kms_fini(rdev); 787254885Sdumbbell rdev->accel_working = false; 788254885Sdumbbell } 789254885Sdumbbell return 0; 790254885Sdumbbell} 791