drm/radeon/kms: add support for gui idle interrupts (v4)
[deliverable/linux.git] / drivers / gpu / drm / radeon / rs600.c
index c3818562a13eb64f647ec74922605bf673bdf0e6..b312b72d76ce57979ecb5c9b7820be8db67c5b01 100644 (file)
@@ -37,6 +37,7 @@
  */
 #include "drmP.h"
 #include "radeon.h"
+#include "radeon_asic.h"
 #include "atom.h"
 #include "rs600d.h"
 
 void rs600_gpu_init(struct radeon_device *rdev);
 int rs600_mc_wait_for_idle(struct radeon_device *rdev);
 
-int rs600_mc_init(struct radeon_device *rdev)
-{
-       /* read back the MC value from the hw */
-       int r;
-       u32 tmp;
-
-       /* Setup GPU memory space */
-       tmp = RREG32_MC(R_000004_MC_FB_LOCATION);
-       rdev->mc.vram_location = G_000004_MC_FB_START(tmp) << 16;
-       rdev->mc.gtt_location = 0xffffffffUL;
-       r = radeon_mc_setup(rdev);
-       rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
-       if (r)
-               return r;
-       return 0;
-}
-
 /* hpd for digital panel detect/disconnect */
 bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
 {
@@ -163,6 +147,78 @@ void rs600_hpd_fini(struct radeon_device *rdev)
        }
 }
 
+void rs600_bm_disable(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       /* disable bus mastering */
+       pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp);
+       pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
+       mdelay(1);
+}
+
+int rs600_asic_reset(struct radeon_device *rdev)
+{
+       u32 status, tmp;
+
+       struct rv515_mc_save save;
+
+       /* Stops all mc clients */
+       rv515_mc_stop(rdev, &save);
+       status = RREG32(R_000E40_RBBM_STATUS);
+       if (!G_000E40_GUI_ACTIVE(status)) {
+               return 0;
+       }
+       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);
+       pci_save_state(rdev->pdev);
+       /* disable bus mastering */
+       rs600_bm_disable(rdev);
+       /* reset GA+VAP */
+       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);
+       /* reset CP */
+       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);
+       /* reset MC */
+       WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(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);
+       /* 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");
+               rdev->gpu_lockup = true;
+               return -1;
+       }
+       rv515_mc_resume(rdev, &save);
+       dev_info(rdev->dev, "GPU reset succeed\n");
+       return 0;
+}
+
 /*
  * GART.
  */
@@ -175,7 +231,7 @@ void rs600_gart_tlb_flush(struct radeon_device *rdev)
        WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
 
        tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
-       tmp |= S_000100_INVALIDATE_ALL_L1_TLBS(1) & S_000100_INVALIDATE_L2_CACHE(1);
+       tmp |= S_000100_INVALIDATE_ALL_L1_TLBS(1) | S_000100_INVALIDATE_L2_CACHE(1);
        WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
 
        tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
@@ -213,6 +269,7 @@ int rs600_gart_enable(struct radeon_device *rdev)
        r = radeon_gart_table_vram_pin(rdev);
        if (r)
                return r;
+       radeon_gart_restore(rdev);
        /* Enable bus master */
        tmp = RREG32(R_00004C_BUS_CNTL) & C_00004C_BUS_MASTER_DIS;
        WREG32(R_00004C_BUS_CNTL, tmp);
@@ -283,9 +340,9 @@ void rs600_gart_disable(struct radeon_device *rdev)
 
 void rs600_gart_fini(struct radeon_device *rdev)
 {
+       radeon_gart_fini(rdev);
        rs600_gart_disable(rdev);
        radeon_gart_table_vram_free(rdev);
-       radeon_gart_fini(rdev);
 }
 
 #define R600_PTE_VALID     (1 << 0)
@@ -325,6 +382,9 @@ int rs600_irq_set(struct radeon_device *rdev)
        if (rdev->irq.sw_int) {
                tmp |= S_000040_SW_INT_EN(1);
        }
+       if (rdev->irq.gui_idle) {
+               tmp |= S_000040_GUI_IDLE(1);
+       }
        if (rdev->irq.crtc_vblank_int[0]) {
                mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1);
        }
@@ -347,9 +407,15 @@ int rs600_irq_set(struct radeon_device *rdev)
 static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_int)
 {
        uint32_t irqs = RREG32(R_000044_GEN_INT_STATUS);
-       uint32_t irq_mask = ~C_000044_SW_INT;
+       uint32_t irq_mask = S_000044_SW_INT(1);
        u32 tmp;
 
+       /* the interrupt works, but the status bit is permanently asserted */
+       if (rdev->irq.gui_idle && radeon_gui_idle(rdev)) {
+               if (!rdev->irq.gui_idle_acked)
+                       irq_mask |= S_000044_GUI_IDLE_STAT(1);
+       }
+
        if (G_000044_DISPLAY_INT_STAT(irqs)) {
                *r500_disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS);
                if (G_007EDC_LB_D1_VBLANK_INTERRUPT(*r500_disp_int)) {
@@ -397,6 +463,9 @@ int rs600_irq_process(struct radeon_device *rdev)
        uint32_t r500_disp_int;
        bool queue_hotplug = false;
 
+       /* reset gui idle ack.  the status bit is broken */
+       rdev->irq.gui_idle_acked = false;
+
        status = rs600_irq_ack(rdev, &r500_disp_int);
        if (!status && !r500_disp_int) {
                return IRQ_NONE;
@@ -405,11 +474,23 @@ int rs600_irq_process(struct radeon_device *rdev)
                /* SW interrupt */
                if (G_000044_SW_INT(status))
                        radeon_fence_process(rdev);
+               /* GUI idle */
+               if (G_000040_GUI_IDLE(status)) {
+                       rdev->irq.gui_idle_acked = true;
+                       rdev->pm.gui_idle = true;
+                       wake_up(&rdev->irq.idle_queue);
+               }
                /* Vertical blank interrupts */
-               if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int))
+               if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) {
                        drm_handle_vblank(rdev->ddev, 0);
-               if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int))
+                       rdev->pm.vblank_sync = true;
+                       wake_up(&rdev->irq.vblank_queue);
+               }
+               if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) {
                        drm_handle_vblank(rdev->ddev, 1);
+                       rdev->pm.vblank_sync = true;
+                       wake_up(&rdev->irq.vblank_queue);
+               }
                if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) {
                        queue_hotplug = true;
                        DRM_DEBUG("HPD1\n");
@@ -420,6 +501,8 @@ int rs600_irq_process(struct radeon_device *rdev)
                }
                status = rs600_irq_ack(rdev, &r500_disp_int);
        }
+       /* reset gui idle ack.  the status bit is broken */
+       rdev->irq.gui_idle_acked = false;
        if (queue_hotplug)
                queue_work(rdev->wq, &rdev->hotplug_work);
        if (rdev->msi_enabled) {
@@ -463,34 +546,58 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev)
 
 void rs600_gpu_init(struct radeon_device *rdev)
 {
-       r100_hdp_reset(rdev);
        r420_pipes_init(rdev);
        /* Wait for mc idle */
        if (rs600_mc_wait_for_idle(rdev))
                dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
 }
 
-void rs600_vram_info(struct radeon_device *rdev)
+void rs600_mc_init(struct radeon_device *rdev)
 {
+       u64 base;
+
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
        rdev->mc.vram_is_ddr = true;
        rdev->mc.vram_width = 128;
-
        rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
        rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
-
-       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
-       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
-
-       if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
-               rdev->mc.mc_vram_size = rdev->mc.aper_size;
-
-       if (rdev->mc.real_vram_size > rdev->mc.aper_size)
-               rdev->mc.real_vram_size = rdev->mc.aper_size;
+       rdev->mc.visible_vram_size = rdev->mc.aper_size;
+       rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
+       base = RREG32_MC(R_000004_MC_FB_LOCATION);
+       base = G_000004_MC_FB_START(base) << 16;
+       rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
+       radeon_vram_location(rdev, &rdev->mc, base);
+       radeon_gtt_location(rdev, &rdev->mc);
+       radeon_update_bandwidth_info(rdev);
 }
 
 void rs600_bandwidth_update(struct radeon_device *rdev)
 {
-       /* FIXME: implement, should this be like rs690 ? */
+       struct drm_display_mode *mode0 = NULL;
+       struct drm_display_mode *mode1 = NULL;
+       u32 d1mode_priority_a_cnt, d2mode_priority_a_cnt;
+       /* FIXME: implement full support */
+
+       radeon_update_display_priority(rdev);
+
+       if (rdev->mode_info.crtcs[0]->base.enabled)
+               mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+       if (rdev->mode_info.crtcs[1]->base.enabled)
+               mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+
+       rs690_line_buffer_adjust(rdev, mode0, mode1);
+
+       if (rdev->disp_priority == 2) {
+               d1mode_priority_a_cnt = RREG32(R_006548_D1MODE_PRIORITY_A_CNT);
+               d2mode_priority_a_cnt = RREG32(R_006D48_D2MODE_PRIORITY_A_CNT);
+               d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
+               d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
+               WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
+               WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
+               WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
+               WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
+       }
 }
 
 uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg)
@@ -585,7 +692,7 @@ int rs600_resume(struct radeon_device *rdev)
        /* Resume clock before doing reset */
        rv515_clock_startup(rdev);
        /* Reset gpu before posting otherwise ATOM will enter infinite loop */
-       if (radeon_gpu_reset(rdev)) {
+       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));
@@ -610,6 +717,7 @@ int rs600_suspend(struct radeon_device *rdev)
 
 void rs600_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r100_cp_fini(rdev);
        r100_wb_fini(rdev);
        r100_ib_fini(rdev);
@@ -647,7 +755,7 @@ int rs600_init(struct radeon_device *rdev)
                return -EINVAL;
        }
        /* Reset gpu before posting otherwise ATOM will enter infinite loop */
-       if (radeon_gpu_reset(rdev)) {
+       if (radeon_asic_reset(rdev)) {
                dev_warn(rdev->dev,
                        "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
                        RREG32(R_000E40_RBBM_STATUS),
@@ -661,12 +769,8 @@ int rs600_init(struct radeon_device *rdev)
        radeon_get_clock_info(rdev->ddev);
        /* Initialize power management */
        radeon_pm_init(rdev);
-       /* Get vram informations */
-       rs600_vram_info(rdev);
-       /* Initialize memory controller (also test AGP) */
-       r = rs600_mc_init(rdev);
-       if (r)
-               return r;
+       /* initialize memory controller */
+       rs600_mc_init(rdev);
        rs600_debugfs(rdev);
        /* Fence driver */
        r = radeon_fence_driver_init(rdev);
This page took 0.027576 seconds and 5 git commands to generate.