radeon: do proper memory controller init and setup
authorDave Airlie <airlied@linux.ie>
Thu, 18 Sep 2008 00:17:27 +0000 (10:17 +1000)
committerDave Airlie <airlied@linux.ie>
Thu, 18 Sep 2008 00:17:27 +0000 (10:17 +1000)
linux-core/radeon_gem.c
shared-core/radeon_cp.c
shared-core/radeon_drv.h

index c0218a3..58162e5 100644 (file)
@@ -707,6 +707,176 @@ int radeon_alloc_gart_objects(struct drm_device *dev)
 
 }
 
+static bool avivo_get_mc_idle(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       if (dev_priv->chip_family >= CHIP_R600) {
+               /* no idea where this is on r600 yet */
+               return true;
+       } else if (dev_priv->chip_family == CHIP_RV515) {
+               if (radeon_read_mc_reg(dev_priv, RV515_MC_STATUS) & RV515_MC_STATUS_IDLE)
+                       return true;
+               else
+                       return false;
+       } else if (dev_priv->chip_family == CHIP_RS600) {
+               if (radeon_read_mc_reg(dev_priv, RS600_MC_STATUS) & RS600_MC_STATUS_IDLE)
+                       return true;
+               else
+                       return false;
+       } else if ((dev_priv->chip_family == CHIP_RS690) ||
+                  (dev_priv->chip_family == CHIP_RS740)) {
+               if (radeon_read_mc_reg(dev_priv, RS690_MC_STATUS) & RS690_MC_STATUS_IDLE)
+                       return true;
+               else
+                       return false;
+       } else {
+               if (radeon_read_mc_reg(dev_priv, R520_MC_STATUS) & R520_MC_STATUS_IDLE)
+                       return true;
+               else
+                       return false;
+       }
+}
+
+
+static void avivo_disable_mc_clients(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       uint32_t tmp;
+       int timeout;
+
+       radeon_do_wait_for_idle(dev_priv);
+
+       RADEON_WRITE(AVIVO_D1VGA_CONTROL, RADEON_READ(AVIVO_D1VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE);
+       RADEON_WRITE(AVIVO_D2VGA_CONTROL, RADEON_READ(AVIVO_D2VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE);
+
+       tmp = RADEON_READ(AVIVO_D1CRTC_CONTROL);        
+       RADEON_WRITE(AVIVO_D1CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN);
+
+       tmp = RADEON_READ(AVIVO_D2CRTC_CONTROL);        
+       RADEON_WRITE(AVIVO_D2CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN);
+
+       tmp = RADEON_READ(AVIVO_D2CRTC_CONTROL);
+
+       udelay(1000);
+
+       timeout = 0;
+       while (!(avivo_get_mc_idle(dev))) {
+               if (++timeout > 100000) {
+                       DRM_ERROR("Timeout waiting for memory controller to update settings\n");
+                       DRM_ERROR("Bad things may or may not happen\n");
+               }
+               udelay(10);
+       }
+}
+
+static inline u32 radeon_busy_wait(struct drm_device *dev, uint32_t reg, uint32_t bits,
+                                 unsigned int timeout)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       u32 status;
+
+       do {
+               udelay(10);
+               status = RADEON_READ(reg);
+               timeout--;
+       } while(status != 0xffffffff && (status & bits) && (timeout > 0));
+
+       if (timeout == 0)
+               status = 0xffffffff;
+            
+       return status;
+}
+
+/* Wait for vertical sync on primary CRTC */
+static void radeon_wait_for_vsync(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       uint32_t       crtc_gen_cntl;
+       int ret;
+
+       crtc_gen_cntl = RADEON_READ(RADEON_CRTC_GEN_CNTL);
+       if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) ||
+           !(crtc_gen_cntl & RADEON_CRTC_EN))
+               return;
+
+       /* Clear the CRTC_VBLANK_SAVE bit */
+       RADEON_WRITE(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR);
+
+       radeon_busy_wait(dev, RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE, 2000);
+
+}
+
+/* Wait for vertical sync on primary CRTC */
+static void radeon_wait_for_vsync2(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       uint32_t       crtc2_gen_cntl;
+       struct timeval timeout;
+
+       crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL);
+       if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) ||
+           !(crtc2_gen_cntl & RADEON_CRTC2_EN))
+               return;
+
+       /* Clear the CRTC_VBLANK_SAVE bit */
+       RADEON_WRITE(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR);
+
+       radeon_busy_wait(dev, RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE, 2000);
+}
+
+static void legacy_disable_mc_clients(struct drm_device *dev)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       uint32_t old_mc_status, status_idle;
+       uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl, crtc2_gen_cntl;
+       uint32_t status;
+
+       radeon_do_wait_for_idle(dev_priv);
+
+       if (dev_priv->flags & RADEON_IS_IGP)
+               return;
+
+       old_mc_status = RADEON_READ(RADEON_MC_STATUS);
+
+       /* stop display and memory access */
+       ov0_scale_cntl = RADEON_READ(RADEON_OV0_SCALE_CNTL);
+       RADEON_WRITE(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl & ~RADEON_SCALER_ENABLE);
+       crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL);
+       RADEON_WRITE(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl | RADEON_CRTC_DISPLAY_DIS);
+       crtc_gen_cntl = RADEON_READ(RADEON_CRTC_GEN_CNTL);
+
+       radeon_wait_for_vsync(dev);
+
+       RADEON_WRITE(RADEON_CRTC_GEN_CNTL,
+                    (crtc_gen_cntl & ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_ICON_EN)) |
+                    RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_EXT_DISP_EN);
+
+       if (!(dev_priv->flags & RADEON_SINGLE_CRTC)) {
+               crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL);
+
+               radeon_wait_for_vsync2(dev);
+               RADEON_WRITE(RADEON_CRTC2_GEN_CNTL,
+                            (crtc2_gen_cntl & 
+                             ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_ICON_EN)) |
+                            RADEON_CRTC2_DISP_REQ_EN_B);
+       }
+
+       udelay(500);
+
+       if (radeon_is_r300(dev_priv))
+               status_idle = R300_MC_IDLE;
+       else
+               status_idle = RADEON_MC_IDLE;
+
+       status = radeon_busy_wait(dev, RADEON_MC_STATUS, status_idle, 200000);
+       if (status == 0xffffffff) {
+               DRM_ERROR("Timeout waiting for memory controller to update settings\n");
+               DRM_ERROR("Bad things may or may not happen\n");
+       }
+}
+
+
 void radeon_init_memory_map(struct drm_device *dev)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -776,6 +946,14 @@ void radeon_init_memory_map(struct drm_device *dev)
        else
                dev_priv->fb_location = (dev_priv->mc_fb_location & 0xffff) << 16;
 
+       /* updating mc regs here */
+       if (radeon_is_avivo(dev_priv))
+               avivo_disable_mc_clients(dev);
+       else
+               legacy_disable_mc_clients(dev);
+
+       radeon_write_fb_location(dev_priv, dev_priv->mc_fb_location);
+
        if (radeon_is_avivo(dev_priv)) {
                if (dev_priv->chip_family >= CHIP_R600) 
                        RADEON_WRITE(R600_HDP_NONSURFACE_BASE, (dev_priv->mc_fb_location << 16) & 0xff0000);
@@ -783,8 +961,6 @@ void radeon_init_memory_map(struct drm_device *dev)
                        RADEON_WRITE(AVIVO_HDP_FB_LOCATION, dev_priv->mc_fb_location);
        }
 
-       radeon_write_fb_location(dev_priv, dev_priv->mc_fb_location);
-
        dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16;
        dev_priv->fb_size =
                ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000)
index 8fc4375..63957cd 100644 (file)
@@ -356,7 +356,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
        return -EBUSY;
 }
 
-static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
+int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
 {
        int i, ret;
 
index 96f9a98..82d9d00 100644 (file)
@@ -491,6 +491,7 @@ extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);
 
 extern int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n);
 
+extern int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv);
 extern int radeon_do_cp_idle(drm_radeon_private_t * dev_priv);
 
 extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv);