summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/r420.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/r420.c')
-rw-r--r--drivers/gpu/drm/radeon/r420.c305
1 files changed, 235 insertions, 70 deletions
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 97426a6f370f..5c7fe52de30e 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -29,47 +29,13 @@
#include "drmP.h"
#include "radeon_reg.h"
#include "radeon.h"
+#include "atom.h"
+#include "r420d.h"
-/* r420,r423,rv410 depends on : */
-void r100_pci_gart_disable(struct radeon_device *rdev);
-void r100_hdp_reset(struct radeon_device *rdev);
-void r100_mc_setup(struct radeon_device *rdev);
-int r100_gui_wait_for_idle(struct radeon_device *rdev);
-void r100_mc_disable_clients(struct radeon_device *rdev);
-void r300_vram_info(struct radeon_device *rdev);
-int r300_mc_wait_for_idle(struct radeon_device *rdev);
-int rv370_pcie_gart_enable(struct radeon_device *rdev);
-void rv370_pcie_gart_disable(struct radeon_device *rdev);
-
-/* This files gather functions specifics to :
- * r420,r423,rv410
- *
- * Some of these functions might be used by newer ASICs.
- */
-void r420_gpu_init(struct radeon_device *rdev);
-int r420_debugfs_pipes_info_init(struct radeon_device *rdev);
-
-
-/*
- * MC
- */
int r420_mc_init(struct radeon_device *rdev)
{
int r;
- if (r100_debugfs_rbbm_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for RBBM !\n");
- }
- if (r420_debugfs_pipes_info_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for pipes !\n");
- }
-
- r420_gpu_init(rdev);
- r100_pci_gart_disable(rdev);
- if (rdev->flags & RADEON_IS_PCIE) {
- rv370_pcie_gart_disable(rdev);
- }
-
/* Setup GPU memory space */
rdev->mc.vram_location = 0xFFFFFFFFUL;
rdev->mc.gtt_location = 0xFFFFFFFFUL;
@@ -87,33 +53,9 @@ int r420_mc_init(struct radeon_device *rdev)
if (r) {
return r;
}
-
- /* Program GPU memory space */
- r100_mc_disable_clients(rdev);
- if (r300_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait MC idle while "
- "programming pipes. Bad things might happen.\n");
- }
- r100_mc_setup(rdev);
return 0;
}
-void r420_mc_fini(struct radeon_device *rdev)
-{
- rv370_pcie_gart_disable(rdev);
- radeon_gart_table_vram_free(rdev);
- radeon_gart_fini(rdev);
-}
-
-
-/*
- * Global GPU functions
- */
-void r420_errata(struct radeon_device *rdev)
-{
- rdev->pll_errata = 0;
-}
-
void r420_pipes_init(struct radeon_device *rdev)
{
unsigned tmp;
@@ -122,6 +64,11 @@ void r420_pipes_init(struct radeon_device *rdev)
/* GA_ENHANCE workaround TCL deadlock issue */
WREG32(0x4274, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3));
+ /* add idle wait as per freedesktop.org bug 24041 */
+ if (r100_gui_wait_for_idle(rdev)) {
+ printk(KERN_WARNING "Failed to wait GUI idle while "
+ "programming pipes. Bad things might happen.\n");
+ }
/* get max number of pipes */
gb_pipe_select = RREG32(0x402C);
num_pipes = ((gb_pipe_select >> 12) & 3) + 1;
@@ -179,25 +126,243 @@ void r420_pipes_init(struct radeon_device *rdev)
rdev->num_gb_pipes, rdev->num_z_pipes);
}
-void r420_gpu_init(struct radeon_device *rdev)
+u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg)
+{
+ u32 r;
+
+ WREG32(R_0001F8_MC_IND_INDEX, S_0001F8_MC_IND_ADDR(reg));
+ r = RREG32(R_0001FC_MC_IND_DATA);
+ return r;
+}
+
+void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v)
{
- r100_hdp_reset(rdev);
+ WREG32(R_0001F8_MC_IND_INDEX, S_0001F8_MC_IND_ADDR(reg) |
+ S_0001F8_MC_IND_WR_EN(1));
+ WREG32(R_0001FC_MC_IND_DATA, v);
+}
+
+static void r420_debugfs(struct radeon_device *rdev)
+{
+ if (r100_debugfs_rbbm_init(rdev)) {
+ DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+ }
+ if (r420_debugfs_pipes_info_init(rdev)) {
+ DRM_ERROR("Failed to register debugfs file for pipes !\n");
+ }
+}
+
+static void r420_clock_resume(struct radeon_device *rdev)
+{
+ u32 sclk_cntl;
+
+ if (radeon_dynclks != -1 && radeon_dynclks)
+ radeon_atom_set_clock_gating(rdev, 1);
+ sclk_cntl = RREG32_PLL(R_00000D_SCLK_CNTL);
+ sclk_cntl |= S_00000D_FORCE_CP(1) | S_00000D_FORCE_VIP(1);
+ if (rdev->family == CHIP_R420)
+ sclk_cntl |= S_00000D_FORCE_PX(1) | S_00000D_FORCE_TX(1);
+ WREG32_PLL(R_00000D_SCLK_CNTL, sclk_cntl);
+}
+
+static int r420_startup(struct radeon_device *rdev)
+{
+ int r;
+
+ r300_mc_program(rdev);
+ /* Resume clock */
+ r420_clock_resume(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;
+ }
r420_pipes_init(rdev);
- if (r300_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait MC idle while "
- "programming pipes. Bad things might happen.\n");
+ /* Enable IRQ */
+ rdev->irq.sw_int = true;
+ r100_irq_set(rdev);
+ /* 1M ring buffer */
+ r = r100_cp_init(rdev, 1024 * 1024);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ return r;
+ }
+ r = r100_wb_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
+ }
+ r = r100_ib_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ return r;
}
+ return 0;
}
+int r420_resume(struct radeon_device *rdev)
+{
+ /* 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 */
+ r420_clock_resume(rdev);
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_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));
+ }
+ /* check if cards are posted or not */
+ if (rdev->is_atom_bios) {
+ atom_asic_init(rdev->mode_info.atom_context);
+ } else {
+ radeon_combios_asic_init(rdev->ddev);
+ }
+ /* Resume clock after posting */
+ r420_clock_resume(rdev);
-/*
- * r420,r423,rv410 VRAM info
- */
-void r420_vram_info(struct radeon_device *rdev)
+ return r420_startup(rdev);
+}
+
+int r420_suspend(struct radeon_device *rdev)
{
- r300_vram_info(rdev);
+ r100_cp_disable(rdev);
+ r100_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;
+}
+
+void r420_fini(struct radeon_device *rdev)
+{
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ radeon_gem_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCIE)
+ rv370_pcie_gart_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_fini(rdev);
+ radeon_agp_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ radeon_fence_driver_fini(rdev);
+ radeon_object_fini(rdev);
+ if (rdev->is_atom_bios) {
+ radeon_atombios_fini(rdev);
+ } else {
+ radeon_combios_fini(rdev);
+ }
+ kfree(rdev->bios);
+ rdev->bios = NULL;
}
+int r420_init(struct radeon_device *rdev)
+{
+ int r;
+
+ /* Initialize scratch registers */
+ radeon_scratch_init(rdev);
+ /* Initialize surface registers */
+ radeon_surface_init(rdev);
+ /* TODO: disable VGA need to use VGA request */
+ /* BIOS*/
+ if (!radeon_get_bios(rdev)) {
+ if (ASIC_IS_AVIVO(rdev))
+ return -EINVAL;
+ }
+ if (rdev->is_atom_bios) {
+ r = radeon_atombios_init(rdev);
+ if (r) {
+ return r;
+ }
+ } else {
+ r = radeon_combios_init(rdev);
+ if (r) {
+ return r;
+ }
+ }
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_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));
+ }
+ /* check if cards are posted or not */
+ if (!radeon_card_posted(rdev) && rdev->bios) {
+ DRM_INFO("GPU not posted. posting now...\n");
+ if (rdev->is_atom_bios) {
+ atom_asic_init(rdev->mode_info.atom_context);
+ } else {
+ radeon_combios_asic_init(rdev->ddev);
+ }
+ }
+ /* Initialize clocks */
+ radeon_get_clock_info(rdev->ddev);
+ /* Get vram informations */
+ r300_vram_info(rdev);
+ /* Initialize memory controller (also test AGP) */
+ r = r420_mc_init(rdev);
+ if (r) {
+ return r;
+ }
+ r420_debugfs(rdev);
+ /* Fence driver */
+ r = radeon_fence_driver_init(rdev);
+ if (r) {
+ return r;
+ }
+ r = radeon_irq_kms_init(rdev);
+ if (r) {
+ return r;
+ }
+ /* Memory manager */
+ r = radeon_object_init(rdev);
+ if (r) {
+ return r;
+ }
+ if (rdev->flags & RADEON_IS_PCIE) {
+ r = rv370_pcie_gart_init(rdev);
+ if (r)
+ return r;
+ }
+ if (rdev->flags & RADEON_IS_PCI) {
+ r = r100_pci_gart_init(rdev);
+ if (r)
+ return r;
+ }
+ r300_set_reg_safe(rdev);
+ rdev->accel_working = true;
+ r = r420_startup(rdev);
+ if (r) {
+ /* Somethings want wront with the accel init stop accel */
+ dev_err(rdev->dev, "Disabling GPU acceleration\n");
+ r420_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCIE)
+ rv370_pcie_gart_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_fini(rdev);
+ radeon_agp_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ rdev->accel_working = false;
+ }
+ return 0;
+}
/*
* Debugfs info