drm/radeon: add initial rs690 support to drm.

This adds support for configuring the RS690 GART.

Signed-off-by: Dave Airlie <airlied@redhat.com>
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 5dc799a..833abc7 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -825,11 +825,19 @@
 	return ret;
 }
 
+static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+{
+	RADEON_WRITE(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK));
+	return RADEON_READ(RS690_MC_DATA);
+}
+
 u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
 {
 
 	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
 		return RADEON_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
+	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+		return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
 	else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
 		return RADEON_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
 	else
@@ -840,6 +848,8 @@
 {
 	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
 		RADEON_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
+	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+		RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
 	else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
 		RADEON_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
 	else
@@ -850,6 +860,8 @@
 {
 	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
 		RADEON_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
+	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+		RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
 	else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
 		RADEON_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
 	else
@@ -1362,6 +1374,70 @@
        }
 }
 
+/* Enable or disable RS690 GART on the chip */
+static void radeon_set_rs690gart(drm_radeon_private_t *dev_priv, int on)
+{
+	u32 temp;
+
+	if (on) {
+		DRM_DEBUG("programming rs690 gart %08X %08lX %08X\n",
+			  dev_priv->gart_vm_start,
+			  (long)dev_priv->gart_info.bus_addr,
+			  dev_priv->gart_size);
+
+		temp = RS690_READ_MCIND(dev_priv, RS690_MC_MISC_CNTL);
+		RS690_WRITE_MCIND(RS690_MC_MISC_CNTL, 0x5000);
+
+		RS690_WRITE_MCIND(RS690_MC_AGP_SIZE,
+				  RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB);
+
+		temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_FEATURE_ID);
+		RS690_WRITE_MCIND(RS690_MC_GART_FEATURE_ID, 0x42040800);
+
+		RS690_WRITE_MCIND(RS690_MC_GART_BASE,
+				  dev_priv->gart_info.bus_addr);
+
+		temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_MODE_CONTROL);
+		RS690_WRITE_MCIND(RS690_MC_AGP_MODE_CONTROL, 0x01400000);
+
+		RS690_WRITE_MCIND(RS690_MC_AGP_BASE,
+				  (unsigned int)dev_priv->gart_vm_start);
+
+		dev_priv->gart_size = 32*1024*1024;
+		temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) &
+			 0xffff0000) | (dev_priv->gart_vm_start >> 16));
+
+		RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, temp);
+
+		temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_SIZE);
+		RS690_WRITE_MCIND(RS690_MC_AGP_SIZE,
+				  RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB);
+
+		do {
+			temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL);
+			if ((temp & RS690_MC_GART_CLEAR_STATUS) ==
+			    RS690_MC_GART_CLEAR_DONE)
+				break;
+			DRM_UDELAY(1);
+		} while (1);
+
+		RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL,
+				  RS690_MC_GART_CC_CLEAR);
+		do {
+			temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL);
+			if ((temp & RS690_MC_GART_CLEAR_STATUS) ==
+				   RS690_MC_GART_CLEAR_DONE)
+				break;
+			DRM_UDELAY(1);
+		} while (1);
+
+		RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL,
+				  RS690_MC_GART_CC_NO_CHANGE);
+	} else {
+		RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, RS690_MC_GART_DIS);
+	}
+}
+
 static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
 {
 	u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
@@ -1396,6 +1472,11 @@
 {
 	u32 tmp;
 
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
+		radeon_set_rs690gart(dev_priv, on);
+		return;
+	}
+
 	if (dev_priv->flags & RADEON_IS_IGPGART) {
 		radeon_set_igpgart(dev_priv, on);
 		return;