]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/radeon/r100.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[karo-tx-linux.git] / drivers / gpu / drm / radeon / r100.c
index 8e10aa9f74b052a25e86d04e65173c8a7a19eb76..46da5142b1314da56b716c8feba1eae082e9e7dd 100644 (file)
@@ -68,6 +68,56 @@ MODULE_FIRMWARE(FIRMWARE_R520);
  * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
  */
 
+void r100_pre_page_flip(struct radeon_device *rdev, int crtc)
+{
+       struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+       u32 tmp;
+
+       /* make sure flip is at vb rather than hb */
+       tmp = RREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset);
+       tmp &= ~RADEON_CRTC_OFFSET_FLIP_CNTL;
+       /* make sure pending bit is asserted */
+       tmp |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN;
+       WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, tmp);
+
+       /* set pageflip to happen as late as possible in the vblank interval.
+        * same field for crtc1/2
+        */
+       tmp = RREG32(RADEON_CRTC_GEN_CNTL);
+       tmp &= ~RADEON_CRTC_VSTAT_MODE_MASK;
+       WREG32(RADEON_CRTC_GEN_CNTL, tmp);
+
+       /* enable the pflip int */
+       radeon_irq_kms_pflip_irq_get(rdev, crtc);
+}
+
+void r100_post_page_flip(struct radeon_device *rdev, int crtc)
+{
+       /* disable the pflip int */
+       radeon_irq_kms_pflip_irq_put(rdev, crtc);
+}
+
+u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
+{
+       struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
+       u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK;
+
+       /* Lock the graphics update lock */
+       /* update the scanout addresses */
+       WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp);
+
+       /* Wait for update_pending to go high. */
+       while (!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET));
+       DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
+
+       /* Unlock the lock, so double-buffering can take place inside vblank */
+       tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK;
+       WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp);
+
+       /* Return current update_pending status: */
+       return RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET;
+}
+
 void r100_pm_get_dynpm_state(struct radeon_device *rdev)
 {
        int i;
@@ -526,10 +576,12 @@ int r100_irq_set(struct radeon_device *rdev)
        if (rdev->irq.gui_idle) {
                tmp |= RADEON_GUI_IDLE_MASK;
        }
-       if (rdev->irq.crtc_vblank_int[0]) {
+       if (rdev->irq.crtc_vblank_int[0] ||
+           rdev->irq.pflip[0]) {
                tmp |= RADEON_CRTC_VBLANK_MASK;
        }
-       if (rdev->irq.crtc_vblank_int[1]) {
+       if (rdev->irq.crtc_vblank_int[1] ||
+           rdev->irq.pflip[1]) {
                tmp |= RADEON_CRTC2_VBLANK_MASK;
        }
        if (rdev->irq.hpd[0]) {
@@ -600,14 +652,22 @@ int r100_irq_process(struct radeon_device *rdev)
                }
                /* Vertical blank interrupts */
                if (status & RADEON_CRTC_VBLANK_STAT) {
-                       drm_handle_vblank(rdev->ddev, 0);
-                       rdev->pm.vblank_sync = true;
-                       wake_up(&rdev->irq.vblank_queue);
+                       if (rdev->irq.crtc_vblank_int[0]) {
+                               drm_handle_vblank(rdev->ddev, 0);
+                               rdev->pm.vblank_sync = true;
+                               wake_up(&rdev->irq.vblank_queue);
+                       }
+                       if (rdev->irq.pflip[0])
+                               radeon_crtc_handle_flip(rdev, 0);
                }
                if (status & RADEON_CRTC2_VBLANK_STAT) {
-                       drm_handle_vblank(rdev->ddev, 1);
-                       rdev->pm.vblank_sync = true;
-                       wake_up(&rdev->irq.vblank_queue);
+                       if (rdev->irq.crtc_vblank_int[1]) {
+                               drm_handle_vblank(rdev->ddev, 1);
+                               rdev->pm.vblank_sync = true;
+                               wake_up(&rdev->irq.vblank_queue);
+                       }
+                       if (rdev->irq.pflip[1])
+                               radeon_crtc_handle_flip(rdev, 1);
                }
                if (status & RADEON_FP_DETECT_STAT) {
                        queue_hotplug = true;
@@ -622,7 +682,7 @@ int r100_irq_process(struct radeon_device *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);
+               schedule_work(&rdev->hotplug_work);
        if (rdev->msi_enabled) {
                switch (rdev->family) {
                case CHIP_RS400:
@@ -2026,12 +2086,13 @@ int r100_asic_reset(struct radeon_device *rdev)
 {
        struct r100_mc_save save;
        u32 status, tmp;
+       int ret = 0;
 
-       r100_mc_stop(rdev, &save);
        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 */
@@ -2071,11 +2132,11 @@ int r100_asic_reset(struct radeon_device *rdev)
                G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) {
                dev_err(rdev->dev, "failed to reset GPU\n");
                rdev->gpu_lockup = true;
-               return -1;
-       }
+               ret = -1;
+       } else
+               dev_info(rdev->dev, "GPU reset succeed\n");
        r100_mc_resume(rdev, &save);
-       dev_info(rdev->dev, "GPU reset succeed\n");
-       return 0;
+       return ret;
 }
 
 void r100_set_common_regs(struct radeon_device *rdev)