Merge branch 'drm-ttm-unmappable' into drm-core-next
[pandora-kernel.git] / drivers / gpu / drm / radeon / r600.c
index dce41b1..c325cb1 100644 (file)
@@ -25,6 +25,7 @@
  *          Alex Deucher
  *          Jerome Glisse
  */
+#include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <linux/firmware.h>
 #include <linux/platform_device.h>
@@ -43,6 +44,9 @@
 #define R700_PFP_UCODE_SIZE 848
 #define R700_PM4_UCODE_SIZE 1360
 #define R700_RLC_UCODE_SIZE 1024
+#define EVERGREEN_PFP_UCODE_SIZE 1120
+#define EVERGREEN_PM4_UCODE_SIZE 1376
+#define EVERGREEN_RLC_UCODE_SIZE 768
 
 /* Firmware Names */
 MODULE_FIRMWARE("radeon/R600_pfp.bin");
@@ -67,6 +71,18 @@ MODULE_FIRMWARE("radeon/RV710_pfp.bin");
 MODULE_FIRMWARE("radeon/RV710_me.bin");
 MODULE_FIRMWARE("radeon/R600_rlc.bin");
 MODULE_FIRMWARE("radeon/R700_rlc.bin");
+MODULE_FIRMWARE("radeon/CEDAR_pfp.bin");
+MODULE_FIRMWARE("radeon/CEDAR_me.bin");
+MODULE_FIRMWARE("radeon/CEDAR_rlc.bin");
+MODULE_FIRMWARE("radeon/REDWOOD_pfp.bin");
+MODULE_FIRMWARE("radeon/REDWOOD_me.bin");
+MODULE_FIRMWARE("radeon/REDWOOD_rlc.bin");
+MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin");
+MODULE_FIRMWARE("radeon/JUNIPER_me.bin");
+MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin");
+MODULE_FIRMWARE("radeon/CYPRESS_pfp.bin");
+MODULE_FIRMWARE("radeon/CYPRESS_me.bin");
+MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin");
 
 int r600_debugfs_mc_info_init(struct radeon_device *rdev);
 
@@ -74,6 +90,7 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev);
 int r600_mc_wait_for_idle(struct radeon_device *rdev);
 void r600_gpu_init(struct radeon_device *rdev);
 void r600_fini(struct radeon_device *rdev);
+void r600_irq_disable(struct radeon_device *rdev);
 
 /* hpd for digital panel detect/disconnect */
 bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
@@ -744,7 +761,6 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
                        S_008014_DB2_BUSY(1) | S_008014_DB3_BUSY(1) |
                        S_008014_CB0_BUSY(1) | S_008014_CB1_BUSY(1) |
                        S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1);
-       u32 srbm_reset = 0;
        u32 tmp;
 
        dev_info(rdev->dev, "GPU softreset \n");
@@ -759,7 +775,7 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
                dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
        }
        /* Disable CP parsing/prefetching */
-       WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(0xff));
+       WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
        /* Check if any of the rendering block is busy and reset it */
        if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) ||
            (RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) {
@@ -778,72 +794,56 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
                        S_008020_SOFT_RESET_VGT(1);
                dev_info(rdev->dev, "  R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
                WREG32(R_008020_GRBM_SOFT_RESET, tmp);
-               (void)RREG32(R_008020_GRBM_SOFT_RESET);
-               udelay(50);
+               RREG32(R_008020_GRBM_SOFT_RESET);
+               mdelay(15);
                WREG32(R_008020_GRBM_SOFT_RESET, 0);
-               (void)RREG32(R_008020_GRBM_SOFT_RESET);
        }
        /* Reset CP (we always reset CP) */
        tmp = S_008020_SOFT_RESET_CP(1);
        dev_info(rdev->dev, "R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
        WREG32(R_008020_GRBM_SOFT_RESET, tmp);
-       (void)RREG32(R_008020_GRBM_SOFT_RESET);
-       udelay(50);
+       RREG32(R_008020_GRBM_SOFT_RESET);
+       mdelay(15);
        WREG32(R_008020_GRBM_SOFT_RESET, 0);
-       (void)RREG32(R_008020_GRBM_SOFT_RESET);
-       /* Reset others GPU block if necessary */
-       if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_RLC(1);
-       if (G_000E50_GRBM_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_GRBM(1);
-       if (G_000E50_HI_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_IH(1);
-       if (G_000E50_VMC_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_VMC(1);
-       if (G_000E50_MCB_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_MCDZ_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_MCDY_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_MCDX_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_MCDW_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_MC(1);
-       if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_RLC(1);
-       if (G_000E50_SEM_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_SEM(1);
-       if (G_000E50_BIF_BUSY(RREG32(R_000E50_SRBM_STATUS)))
-               srbm_reset |= S_000E60_SOFT_RESET_BIF(1);
-       dev_info(rdev->dev, "  R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset);
-       WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
-       (void)RREG32(R_000E60_SRBM_SOFT_RESET);
-       udelay(50);
-       WREG32(R_000E60_SRBM_SOFT_RESET, 0);
-       (void)RREG32(R_000E60_SRBM_SOFT_RESET);
-       WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
-       (void)RREG32(R_000E60_SRBM_SOFT_RESET);
-       udelay(50);
-       WREG32(R_000E60_SRBM_SOFT_RESET, 0);
-       (void)RREG32(R_000E60_SRBM_SOFT_RESET);
        /* Wait a little for things to settle down */
-       udelay(50);
+       mdelay(1);
        dev_info(rdev->dev, "  R_008010_GRBM_STATUS=0x%08X\n",
                RREG32(R_008010_GRBM_STATUS));
        dev_info(rdev->dev, "  R_008014_GRBM_STATUS2=0x%08X\n",
                RREG32(R_008014_GRBM_STATUS2));
        dev_info(rdev->dev, "  R_000E50_SRBM_STATUS=0x%08X\n",
                RREG32(R_000E50_SRBM_STATUS));
-       /* After reset we need to reinit the asic as GPU often endup in an
-        * incoherent state.
-        */
-       atom_asic_init(rdev->mode_info.atom_context);
        rv515_mc_resume(rdev, &save);
        return 0;
 }
 
-int r600_gpu_reset(struct radeon_device *rdev)
+bool r600_gpu_is_lockup(struct radeon_device *rdev)
+{
+       u32 srbm_status;
+       u32 grbm_status;
+       u32 grbm_status2;
+       int r;
+
+       srbm_status = RREG32(R_000E50_SRBM_STATUS);
+       grbm_status = RREG32(R_008010_GRBM_STATUS);
+       grbm_status2 = RREG32(R_008014_GRBM_STATUS2);
+       if (!G_008010_GUI_ACTIVE(grbm_status)) {
+               r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp);
+               return false;
+       }
+       /* force CP activities */
+       r = radeon_ring_lock(rdev, 2);
+       if (!r) {
+               /* PACKET2 NOP */
+               radeon_ring_write(rdev, 0x80000000);
+               radeon_ring_write(rdev, 0x80000000);
+               radeon_ring_unlock_commit(rdev);
+       }
+       rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
+       return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
+}
+
+int r600_asic_reset(struct radeon_device *rdev)
 {
        return r600_gpu_soft_reset(rdev);
 }
@@ -1461,10 +1461,31 @@ int r600_init_microcode(struct radeon_device *rdev)
                chip_name = "RV710";
                rlc_chip_name = "R700";
                break;
+       case CHIP_CEDAR:
+               chip_name = "CEDAR";
+               rlc_chip_name = "CEDAR";
+               break;
+       case CHIP_REDWOOD:
+               chip_name = "REDWOOD";
+               rlc_chip_name = "REDWOOD";
+               break;
+       case CHIP_JUNIPER:
+               chip_name = "JUNIPER";
+               rlc_chip_name = "JUNIPER";
+               break;
+       case CHIP_CYPRESS:
+       case CHIP_HEMLOCK:
+               chip_name = "CYPRESS";
+               rlc_chip_name = "CYPRESS";
+               break;
        default: BUG();
        }
 
-       if (rdev->family >= CHIP_RV770) {
+       if (rdev->family >= CHIP_CEDAR) {
+               pfp_req_size = EVERGREEN_PFP_UCODE_SIZE * 4;
+               me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4;
+               rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4;
+       } else if (rdev->family >= CHIP_RV770) {
                pfp_req_size = R700_PFP_UCODE_SIZE * 4;
                me_req_size = R700_PM4_UCODE_SIZE * 4;
                rlc_req_size = R700_RLC_UCODE_SIZE * 4;
@@ -1578,12 +1599,15 @@ int r600_cp_start(struct radeon_device *rdev)
        }
        radeon_ring_write(rdev, PACKET3(PACKET3_ME_INITIALIZE, 5));
        radeon_ring_write(rdev, 0x1);
-       if (rdev->family < CHIP_RV770) {
-               radeon_ring_write(rdev, 0x3);
-               radeon_ring_write(rdev, rdev->config.r600.max_hw_contexts - 1);
-       } else {
+       if (rdev->family >= CHIP_CEDAR) {
+               radeon_ring_write(rdev, 0x0);
+               radeon_ring_write(rdev, rdev->config.evergreen.max_hw_contexts - 1);
+       } else if (rdev->family >= CHIP_RV770) {
                radeon_ring_write(rdev, 0x0);
                radeon_ring_write(rdev, rdev->config.rv770.max_hw_contexts - 1);
+       } else {
+               radeon_ring_write(rdev, 0x3);
+               radeon_ring_write(rdev, rdev->config.r600.max_hw_contexts - 1);
        }
        radeon_ring_write(rdev, PACKET3_ME_INITIALIZE_DEVICE_ID(1));
        radeon_ring_write(rdev, 0);
@@ -2284,10 +2308,11 @@ static void r600_ih_ring_fini(struct radeon_device *rdev)
        }
 }
 
-static void r600_rlc_stop(struct radeon_device *rdev)
+void r600_rlc_stop(struct radeon_device *rdev)
 {
 
-       if (rdev->family >= CHIP_RV770) {
+       if ((rdev->family >= CHIP_RV770) &&
+           (rdev->family <= CHIP_RV740)) {
                /* r7xx asics need to soft reset RLC before halting */
                WREG32(SRBM_SOFT_RESET, SOFT_RESET_RLC);
                RREG32(SRBM_SOFT_RESET);
@@ -2324,7 +2349,12 @@ static int r600_rlc_init(struct radeon_device *rdev)
        WREG32(RLC_UCODE_CNTL, 0);
 
        fw_data = (const __be32 *)rdev->rlc_fw->data;
-       if (rdev->family >= CHIP_RV770) {
+       if (rdev->family >= CHIP_CEDAR) {
+               for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) {
+                       WREG32(RLC_UCODE_ADDR, i);
+                       WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
+               }
+       } else if (rdev->family >= CHIP_RV770) {
                for (i = 0; i < R700_RLC_UCODE_SIZE; i++) {
                        WREG32(RLC_UCODE_ADDR, i);
                        WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
@@ -2354,7 +2384,7 @@ static void r600_enable_interrupts(struct radeon_device *rdev)
        rdev->ih.enabled = true;
 }
 
-static void r600_disable_interrupts(struct radeon_device *rdev)
+void r600_disable_interrupts(struct radeon_device *rdev)
 {
        u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
        u32 ih_cntl = RREG32(IH_CNTL);
@@ -2469,7 +2499,10 @@ int r600_irq_init(struct radeon_device *rdev)
        WREG32(IH_CNTL, ih_cntl);
 
        /* force the active interrupt state to all disabled */
-       r600_disable_interrupt_state(rdev);
+       if (rdev->family >= CHIP_CEDAR)
+               evergreen_disable_interrupt_state(rdev);
+       else
+               r600_disable_interrupt_state(rdev);
 
        /* enable irqs */
        r600_enable_interrupts(rdev);
@@ -2479,7 +2512,7 @@ int r600_irq_init(struct radeon_device *rdev)
 
 void r600_irq_suspend(struct radeon_device *rdev)
 {
-       r600_disable_interrupts(rdev);
+       r600_irq_disable(rdev);
        r600_rlc_stop(rdev);
 }