diff options
-rw-r--r-- | drivers/gpu/drm/radeon/evergreen.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r100.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_reg.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rs600.c | 22 |
9 files changed, 74 insertions, 1 deletions
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index b3d168fb89e..0137a4cd90f 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1418,6 +1418,7 @@ int evergreen_irq_set(struct radeon_device *rdev) u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0; u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; + u32 grbm_int_cntl = 0; if (!rdev->irq.installed) { WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); @@ -1490,8 +1491,13 @@ int evergreen_irq_set(struct radeon_device *rdev) DRM_DEBUG("evergreen_irq_set: hpd 6\n"); hpd6 |= DC_HPDx_INT_EN; } + if (rdev->irq.gui_idle) { + DRM_DEBUG("gui idle\n"); + grbm_int_cntl |= GUI_IDLE_INT_ENABLE; + } WREG32(CP_INT_CNTL, cp_int_cntl); + WREG32(GRBM_INT_CNTL, grbm_int_cntl); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); @@ -1853,6 +1859,11 @@ restart_ih: case 181: /* CP EOP event */ DRM_DEBUG("IH: CP EOP\n"); break; + case 233: /* GUI IDLE */ + DRM_DEBUG("IH: CP EOP\n"); + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index e62116e222a..d35298684f3 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -262,6 +262,9 @@ int r100_irq_set(struct radeon_device *rdev) if (rdev->irq.sw_int) { tmp |= RADEON_SW_INT_ENABLE; } + if (rdev->irq.gui_idle) { + tmp |= RADEON_GUI_IDLE_MASK; + } if (rdev->irq.crtc_vblank_int[0]) { tmp |= RADEON_CRTC_VBLANK_MASK; } @@ -296,6 +299,12 @@ static inline uint32_t r100_irq_ack(struct radeon_device *rdev) RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT | RADEON_FP_DETECT_STAT | RADEON_FP2_DETECT_STAT; + /* 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 |= RADEON_GUI_IDLE_STAT; + } + if (irqs) { WREG32(RADEON_GEN_INT_STATUS, irqs); } @@ -307,6 +316,9 @@ int r100_irq_process(struct radeon_device *rdev) uint32_t status, msi_rearm; bool queue_hotplug = false; + /* reset gui idle ack. the status bit is broken */ + rdev->irq.gui_idle_acked = false; + status = r100_irq_ack(rdev); if (!status) { return IRQ_NONE; @@ -319,6 +331,12 @@ int r100_irq_process(struct radeon_device *rdev) if (status & RADEON_SW_INT_TEST) { radeon_fence_process(rdev); } + /* gui idle interrupt */ + if (status & RADEON_GUI_IDLE_STAT) { + rdev->irq.gui_idle_acked = true; + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + } /* Vertical blank interrupts */ if (status & RADEON_CRTC_VBLANK_STAT) { drm_handle_vblank(rdev->ddev, 0); @@ -340,6 +358,8 @@ int r100_irq_process(struct radeon_device *rdev) } status = r100_irq_ack(rdev); } + /* 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) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1c85dcb168a..094c29dd96e 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2535,6 +2535,7 @@ int r600_irq_set(struct radeon_device *rdev) u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; u32 mode_int = 0; u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0; + u32 grbm_int_cntl = 0; u32 hdmi1, hdmi2; if (!rdev->irq.installed) { @@ -2611,9 +2612,14 @@ int r600_irq_set(struct radeon_device *rdev) DRM_DEBUG("r600_irq_set: hdmi 2\n"); hdmi2 |= R600_HDMI_INT_EN; } + if (rdev->irq.gui_idle) { + DRM_DEBUG("gui idle\n"); + grbm_int_cntl |= GUI_IDLE_INT_ENABLE; + } WREG32(CP_INT_CNTL, cp_int_cntl); WREG32(DxMODE_INT_MASK, mode_int); + WREG32(GRBM_INT_CNTL, grbm_int_cntl); WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1); if (ASIC_IS_DCE3(rdev)) { WREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, hdmi2); @@ -2929,6 +2935,11 @@ restart_ih: case 181: /* CP EOP event */ DRM_DEBUG("IH: CP EOP\n"); break; + case 233: /* GUI IDLE */ + DRM_DEBUG("IH: CP EOP\n"); + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bb4a2a66f07..433937109af 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -376,6 +376,9 @@ struct radeon_irq { wait_queue_head_t vblank_queue; /* FIXME: use defines for max hpd/dacs */ bool hpd[6]; + bool gui_idle; + bool gui_idle_acked; + wait_queue_head_t idle_queue; /* FIXME: use defines for max HDMI blocks */ bool hdmi[2]; spinlock_t sw_lock; @@ -694,6 +697,7 @@ struct radeon_pm { int active_crtcs; int req_vblank; bool vblank_sync; + bool gui_idle; fixed20_12 max_bandwidth; fixed20_12 igp_sideport_mclk; fixed20_12 igp_system_mclk; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 26217ffe035..53a2c27dd8f 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -602,6 +602,7 @@ int radeon_device_init(struct radeon_device *rdev, rwlock_init(&rdev->fence_drv.lock); INIT_LIST_HEAD(&rdev->gem.objects); init_waitqueue_head(&rdev->irq.vblank_queue); + init_waitqueue_head(&rdev->irq.idle_queue); /* setup workqueue */ rdev->wq = create_workqueue("radeon"); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 8fa40ed397e..059bfa4098d 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -68,6 +68,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ rdev->irq.sw_int = false; + rdev->irq.gui_idle = false; for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; for (i = 0; i < 6; i++) @@ -97,6 +98,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) } /* Disable *all* interrupts */ rdev->irq.sw_int = false; + rdev->irq.gui_idle = false; for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; for (i = 0; i < 6; i++) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a4b57493aa7..6dfeb9cf16b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -27,6 +27,7 @@ #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 #define RADEON_WAIT_VBLANK_TIMEOUT 200 +#define RADEON_WAIT_IDLE_TIMEOUT 200 static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index eabbc9cf30a..74d1cbfa23a 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -995,6 +995,7 @@ # define RADEON_FP_DETECT_MASK (1 << 4) # define RADEON_CRTC2_VBLANK_MASK (1 << 9) # define RADEON_FP2_DETECT_MASK (1 << 10) +# define RADEON_GUI_IDLE_MASK (1 << 19) # define RADEON_SW_INT_ENABLE (1 << 25) #define RADEON_GEN_INT_STATUS 0x0044 # define AVIVO_DISPLAY_INT_STATUS (1 << 0) @@ -1006,6 +1007,8 @@ # define RADEON_CRTC2_VBLANK_STAT_ACK (1 << 9) # define RADEON_FP2_DETECT_STAT (1 << 10) # define RADEON_FP2_DETECT_STAT_ACK (1 << 10) +# define RADEON_GUI_IDLE_STAT (1 << 19) +# define RADEON_GUI_IDLE_STAT_ACK (1 << 19) # define RADEON_SW_INT_FIRE (1 << 26) # define RADEON_SW_INT_TEST (1 << 25) # define RADEON_SW_INT_TEST_ACK (1 << 25) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 5e3f21861f4..b312b72d76c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -382,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); } @@ -404,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)) { @@ -454,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; @@ -462,6 +474,12 @@ 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)) { drm_handle_vblank(rdev->ddev, 0); @@ -483,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) { |