/* * Copyright 2008 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * Copyright 2009 Jerome Glisse. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie * Alex Deucher * Jerome Glisse
*/
/* This files gather functions specifics to: r300,r350,rv350,rv370,rv380 * * GPU Errata: * - HOST_PATH_CNTL: r300 family seems to dislike write to HOST_PATH_CNTL * using MMIO to flush host path read cache, this lead to HARDLOCKUP. * However, scheduling such write to the ring seems harmless, i suspect * the CP read collide with the flush somehow, or maybe the MC, hard to * tell. (Jerome Glisse)
*/
/* on x86 we want this to be CPU endian, on powerpc * on powerpc without HW swappers, it'll get swapped on way
* into VRAM - so no need for cpu_to_le32 on VRAM tables */
writel(entry, ((void __iomem *)ptr) + (i * 4));
}
int rv370_pcie_gart_init(struct radeon_device *rdev)
{ int r;
if (rdev->gart.robj) {
WARN(1, "RV370 PCIE GART already initialized\n"); return 0;
} /* Initialize common gart structure */
r = radeon_gart_init(rdev); if (r) return r;
rv370_debugfs_pcie_gart_info_init(rdev);
/* Sub pixel 1/12 so we can have 4K rendering according to doc */
gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16); switch (rdev->num_gb_pipes) { case 2:
gb_tile_config |= R300_PIPE_COUNT_R300; break; case 3:
gb_tile_config |= R300_PIPE_COUNT_R420_3P; break; case 4:
gb_tile_config |= R300_PIPE_COUNT_R420; break; case 1: default:
gb_tile_config |= R300_PIPE_COUNT_RV350; break;
}
if (r100_gui_wait_for_idle(rdev)) {
pr_warn("Failed to wait GUI idle while programming pipes. Bad things might happen.\n");
} if (r300_mc_wait_for_idle(rdev)) {
pr_warn("Failed to wait MC idle while programming pipes. Bad things might happen.\n");
}
DRM_INFO("radeon: %d quad pipes, %d Z pipes initialized\n",
rdev->num_gb_pipes, rdev->num_z_pipes);
}
int r300_asic_reset(struct radeon_device *rdev, bool hard)
{ struct r100_mc_save save;
u32 status, tmp; int ret = 0;
status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(status)) { return 0;
}
r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* stop CP */
WREG32(RADEON_CP_CSQ_CNTL, 0);
tmp = RREG32(RADEON_CP_RB_CNTL);
WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
WREG32(RADEON_CP_RB_RPTR_WR, 0);
WREG32(RADEON_CP_RB_WPTR, 0);
WREG32(RADEON_CP_RB_CNTL, tmp); /* save PCI state */
pci_save_state(rdev->pdev); /* disable bus mastering */
r100_bm_disable(rdev);
WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) |
S_0000F0_SOFT_RESET_GA(1));
RREG32(R_0000F0_RBBM_SOFT_RESET);
mdelay(500);
WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
mdelay(1);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* resetting the CP seems to be problematic sometimes it end up * hard locking the computer, but it's necessary for successful * reset more test & playing is needed on R3XX/R4XX to find a * reliable (if any solution)
*/
WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1));
RREG32(R_0000F0_RBBM_SOFT_RESET);
mdelay(500);
WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
mdelay(1);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* restore PCI & busmastering */
pci_restore_state(rdev->pdev);
r100_enable_bm(rdev); /* Check if GPU is idle */ if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
ret = -1;
} else
dev_info(rdev->dev, "GPU reset succeed\n");
r100_mc_resume(rdev, &save); return ret;
}
/* wait for lane set to complete */
link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); while (link_width_cntl == 0xffffffff)
link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
}
int rv370_get_pcie_lanes(struct radeon_device *rdev)
{
u32 link_width_cntl;
switch (reg) { case AVIVO_D1MODE_VLINE_START_END: case RADEON_CRTC_GUI_TRIG_VLINE:
r = r100_cs_packet_parse_vline(p); if (r) {
DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
idx, reg);
radeon_cs_dump_packet(p, pkt); return r;
} break; case RADEON_DST_PITCH_OFFSET: case RADEON_SRC_PITCH_OFFSET:
r = r100_reloc_pitch_offset(p, pkt, idx, reg); if (r) return r; break; case R300_RB3D_COLOROFFSET0: case R300_RB3D_COLOROFFSET1: case R300_RB3D_COLOROFFSET2: case R300_RB3D_COLOROFFSET3:
i = (reg - R300_RB3D_COLOROFFSET0) >> 2;
r = radeon_cs_packet_next_reloc(p, &reloc, 0); if (r) {
DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
idx, reg);
radeon_cs_dump_packet(p, pkt); return r;
}
track->cb[i].robj = reloc->robj;
track->cb[i].offset = idx_value;
track->cb_dirty = true;
ib[idx] = idx_value + ((u32)reloc->gpu_offset); break; case R300_ZB_DEPTHOFFSET:
r = radeon_cs_packet_next_reloc(p, &reloc, 0); if (r) {
DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
idx, reg);
radeon_cs_dump_packet(p, pkt); return r;
}
track->zb.robj = reloc->robj;
track->zb.offset = idx_value;
track->zb_dirty = true;
ib[idx] = idx_value + ((u32)reloc->gpu_offset); break; case R300_TX_OFFSET_0: case R300_TX_OFFSET_0+4: case R300_TX_OFFSET_0+8: case R300_TX_OFFSET_0+12: case R300_TX_OFFSET_0+16: case R300_TX_OFFSET_0+20: case R300_TX_OFFSET_0+24: case R300_TX_OFFSET_0+28: case R300_TX_OFFSET_0+32: case R300_TX_OFFSET_0+36: case R300_TX_OFFSET_0+40: case R300_TX_OFFSET_0+44: case R300_TX_OFFSET_0+48: case R300_TX_OFFSET_0+52: case R300_TX_OFFSET_0+56: case R300_TX_OFFSET_0+60:
i = (reg - R300_TX_OFFSET_0) >> 2;
r = radeon_cs_packet_next_reloc(p, &reloc, 0); if (r) {
DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
idx, reg);
radeon_cs_dump_packet(p, pkt); return r;
}
tmp = idx_value & ~(0x7 << 16);
tmp |= tile_flags;
ib[idx] = tmp;
}
track->zb.pitch = idx_value & 0x3FFC;
track->zb_dirty = true; break; case 0x4104: /* TX_ENABLE */ for (i = 0; i < 16; i++) { bool enabled;
enabled = !!(idx_value & (1 << i));
track->textures[i].enabled = enabled;
}
track->tex_dirty = true; break; case 0x44C0: case 0x44C4: case 0x44C8: case 0x44CC: case 0x44D0: case 0x44D4: case 0x44D8: case 0x44DC: case 0x44E0: case 0x44E4: case 0x44E8: case 0x44EC: case 0x44F0: case 0x44F4: case 0x44F8: case 0x44FC: /* TX_FORMAT1_[0-15] */
i = (reg - 0x44C0) >> 2;
tmp = (idx_value >> 25) & 0x3;
track->textures[i].tex_coord_type = tmp; switch ((idx_value & 0x1F)) { case R300_TX_FORMAT_X8: case R300_TX_FORMAT_Y4X4: case R300_TX_FORMAT_Z3Y3X2:
track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_NONE; break; case R300_TX_FORMAT_X16: case R300_TX_FORMAT_FL_I16: case R300_TX_FORMAT_Y8X8: case R300_TX_FORMAT_Z5Y6X5: case R300_TX_FORMAT_Z6Y5X5: case R300_TX_FORMAT_W4Z4Y4X4: case R300_TX_FORMAT_W1Z5Y5X5: case R300_TX_FORMAT_D3DMFT_CxV8U8: case R300_TX_FORMAT_B8G8_B8G8: case R300_TX_FORMAT_G8R8_G8B8:
track->textures[i].cpp = 2;
track->textures[i].compress_format = R100_TRACK_COMP_NONE; break; case R300_TX_FORMAT_Y16X16: case R300_TX_FORMAT_FL_I16A16: case R300_TX_FORMAT_Z11Y11X10: case R300_TX_FORMAT_Z10Y11X11: case R300_TX_FORMAT_W8Z8Y8X8: case R300_TX_FORMAT_W2Z10Y10X10: case 0x17: case R300_TX_FORMAT_FL_I32: case 0x1e:
track->textures[i].cpp = 4;
track->textures[i].compress_format = R100_TRACK_COMP_NONE; break; case R300_TX_FORMAT_W16Z16Y16X16: case R300_TX_FORMAT_FL_R16G16B16A16: case R300_TX_FORMAT_FL_I32A32:
track->textures[i].cpp = 8;
track->textures[i].compress_format = R100_TRACK_COMP_NONE; break; case R300_TX_FORMAT_FL_R32G32B32A32:
track->textures[i].cpp = 16;
track->textures[i].compress_format = R100_TRACK_COMP_NONE; break; case R300_TX_FORMAT_DXT1:
track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_DXT1; break; case R300_TX_FORMAT_ATI2N: if (p->rdev->family < CHIP_R420) {
DRM_ERROR("Invalid texture format %u\n",
(idx_value & 0x1F)); return -EINVAL;
} /* The same rules apply as for DXT3/5. */
fallthrough; case R300_TX_FORMAT_DXT3: case R300_TX_FORMAT_DXT5:
track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_DXT35; break; default:
DRM_ERROR("Invalid texture format %u\n",
(idx_value & 0x1F)); return -EINVAL;
}
track->tex_dirty = true; break; case 0x4400: case 0x4404: case 0x4408: case 0x440C: case 0x4410: case 0x4414: case 0x4418: case 0x441C: case 0x4420: case 0x4424: case 0x4428: case 0x442C: case 0x4430: case 0x4434: case 0x4438: case 0x443C: /* TX_FILTER0_[0-15] */
i = (reg - 0x4400) >> 2;
tmp = idx_value & 0x7; if (tmp == 2 || tmp == 4 || tmp == 6) {
track->textures[i].roundup_w = false;
}
tmp = (idx_value >> 3) & 0x7; if (tmp == 2 || tmp == 4 || tmp == 6) {
track->textures[i].roundup_h = false;
}
track->tex_dirty = true; break; case 0x4500: case 0x4504: case 0x4508: case 0x450C: case 0x4510: case 0x4514: case 0x4518: case 0x451C: case 0x4520: case 0x4524: case 0x4528: case 0x452C: case 0x4530: case 0x4534: case 0x4538: case 0x453C: /* TX_FORMAT2_[0-15] */
i = (reg - 0x4500) >> 2;
tmp = idx_value & 0x3FFF;
track->textures[i].pitch = tmp + 1; if (p->rdev->family >= CHIP_RV515) {
tmp = ((idx_value >> 15) & 1) << 11;
track->textures[i].width_11 = tmp;
tmp = ((idx_value >> 16) & 1) << 11;
track->textures[i].height_11 = tmp;
/* ATI1N */ if (idx_value & (1 << 14)) { /* The same rules apply as for DXT1. */
track->textures[i].compress_format =
R100_TRACK_COMP_DXT1;
}
} elseif (idx_value & (1 << 14)) {
DRM_ERROR("Forbidden bit TXFORMAT_MSB\n"); return -EINVAL;
}
track->tex_dirty = true; break; case 0x4480: case 0x4484: case 0x4488: case 0x448C: case 0x4490: case 0x4494: case 0x4498: case 0x449C: case 0x44A0: case 0x44A4: case 0x44A8: case 0x44AC: case 0x44B0: case 0x44B4: case 0x44B8: case 0x44BC: /* TX_FORMAT0_[0-15] */
i = (reg - 0x4480) >> 2;
tmp = idx_value & 0x7FF;
track->textures[i].width = tmp + 1;
tmp = (idx_value >> 11) & 0x7FF;
track->textures[i].height = tmp + 1;
tmp = (idx_value >> 26) & 0xF;
track->textures[i].num_levels = tmp;
tmp = idx_value & (1 << 31);
track->textures[i].use_pitch = !!tmp;
tmp = (idx_value >> 22) & 0xF;
track->textures[i].txdepth = tmp;
track->tex_dirty = true; break; case R300_ZB_ZPASS_ADDR:
r = radeon_cs_packet_next_reloc(p, &reloc, 0); if (r) {
DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
idx, reg);
radeon_cs_dump_packet(p, pkt); return r;
}
ib[idx] = idx_value + ((u32)reloc->gpu_offset); break; case 0x4e0c: /* RB3D_COLOR_CHANNEL_MASK */
track->color_channel_mask = idx_value;
track->cb_dirty = true; break; case 0x43a4: /* SC_HYPERZ_EN */ /* r300c emits this register - we need to disable hyperz for it
* without complaining */ if (p->rdev->hyperz_filp != p->filp) { if (idx_value & 0x1)
ib[idx] = idx_value & ~1;
} break; case 0x4f1c: /* ZB_BW_CNTL */
track->zb_cb_clear = !!(idx_value & (1 << 5));
track->cb_dirty = true;
track->zb_dirty = true; if (p->rdev->hyperz_filp != p->filp) { if (idx_value & (R300_HIZ_ENABLE |
R300_RD_COMP_ENABLE |
R300_WR_COMP_ENABLE |
R300_FAST_FILL_ENABLE)) goto fail;
} break; case 0x4e04: /* RB3D_BLENDCNTL */
track->blend_read_enable = !!(idx_value & (1 << 2));
track->cb_dirty = true; break; case R300_RB3D_AARESOLVE_OFFSET:
r = radeon_cs_packet_next_reloc(p, &reloc, 0); if (r) {
DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
idx, reg);
radeon_cs_dump_packet(p, pkt); return r;
}
track->aa.robj = reloc->robj;
track->aa.offset = idx_value;
track->aa_dirty = true;
ib[idx] = idx_value + ((u32)reloc->gpu_offset); break; case R300_RB3D_AARESOLVE_PITCH:
track->aa.pitch = idx_value & 0x3FFE;
track->aa_dirty = true; break; case R300_RB3D_AARESOLVE_CTL:
track->aaresolve = idx_value & 0x1;
track->aa_dirty = true; break; case 0x4f30: /* ZB_MASK_OFFSET */ case 0x4f34: /* ZB_ZMASK_PITCH */ case 0x4f44: /* ZB_HIZ_OFFSET */ case 0x4f54: /* ZB_HIZ_PITCH */ if (idx_value && (p->rdev->hyperz_filp != p->filp)) goto fail; break; case 0x4028: if (idx_value && (p->rdev->hyperz_filp != p->filp)) goto fail; /* GB_Z_PEQ_CONFIG */ if (p->rdev->family >= CHIP_RV350) break; goto fail; break; case 0x4be8: /* valid register only on RV530 */ if (p->rdev->family == CHIP_RV530) break;
fallthrough; /* fallthrough do not move */ default: goto fail;
} return 0;
fail:
pr_err("Forbidden register 0x%04X in cs at %d (val=%08x)\n",
reg, idx, idx_value); return -EINVAL;
}
if (radeon_dynclks != -1 && radeon_dynclks)
radeon_legacy_set_clock_gating(rdev, 1); /* We need to force on some of the block */
tmp = RREG32_PLL(R_00000D_SCLK_CNTL);
tmp |= S_00000D_FORCE_CP(1) | S_00000D_FORCE_VIP(1); if ((rdev->family == CHIP_RV350) || (rdev->family == CHIP_RV380))
tmp |= S_00000D_FORCE_VAP(1);
WREG32_PLL(R_00000D_SCLK_CNTL, tmp);
}
staticint r300_startup(struct radeon_device *rdev)
{ int r;
/* set common regs */
r100_set_common_regs(rdev); /* program mc */
r300_mc_program(rdev); /* Resume clock */
r300_clock_startup(rdev); /* Initialize GPU configuration (# pipes, ...) */
r300_gpu_init(rdev); /* Initialize GART (initialize after TTM so we can allocate
* memory through TTM but finalize after TTM) */ if (rdev->flags & RADEON_IS_PCIE) {
r = rv370_pcie_gart_enable(rdev); if (r) return r;
}
if (rdev->flags & RADEON_IS_PCI) {
r = r100_pci_gart_enable(rdev); if (r) return r;
}
/* allocate wb buffer */
r = radeon_wb_init(rdev); if (r) return r;
r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX); if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); return r;
}
/* Enable IRQ */ if (!rdev->irq.installed) {
r = radeon_irq_kms_init(rdev); if (r) return r;
}
r100_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024); if (r) {
dev_err(rdev->dev, "failed initializing CP (%d).\n", r); return r;
}
r = radeon_ib_pool_init(rdev); if (r) {
dev_err(rdev->dev, "IB initialization failed (%d).\n", r); return r;
}
return 0;
}
int r300_resume(struct radeon_device *rdev)
{ int r;
/* Make sur GART are not working */ if (rdev->flags & RADEON_IS_PCIE)
rv370_pcie_gart_disable(rdev); if (rdev->flags & RADEON_IS_PCI)
r100_pci_gart_disable(rdev); /* Resume clock before doing reset */
r300_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ if (radeon_asic_reset(rdev)) {
dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
RREG32(R_000E40_RBBM_STATUS),
RREG32(R_0007C0_CP_STAT));
} /* post */
radeon_combios_asic_init(rdev_to_drm(rdev)); /* Resume clock after posting */
r300_clock_startup(rdev); /* Initialize surface registers */
radeon_surface_init(rdev);
rdev->accel_working = true;
r = r300_startup(rdev); if (r) {
rdev->accel_working = false;
} return r;
}
int r300_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
r100_cp_disable(rdev);
radeon_wb_disable(rdev);
r100_irq_disable(rdev); if (rdev->flags & RADEON_IS_PCIE)
rv370_pcie_gart_disable(rdev); if (rdev->flags & RADEON_IS_PCI)
r100_pci_gart_disable(rdev); return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.