radeon: add support for rs600 GPUs
authorAlex Deucher <alexdeucher@gmail.com>
Wed, 25 Feb 2009 21:57:49 +0000 (16:57 -0500)
committerDave Airlie <airlied@redhat.com>
Fri, 13 Mar 2009 04:24:13 +0000 (14:24 +1000)
RS600s are an AMD IGP for Intel CPUs, that look like RS690s from
a lot of perspectives but look like r600s from a memory controller
point of view.

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_drv.h

index 3f40558..0143a14 100644 (file)
@@ -114,7 +114,7 @@ static int r600_do_wait_for_idle(drm_radeon_private_t *dev_priv)
        return -EBUSY;
 }
 
-static void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
+void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
 {
        struct drm_sg_mem *entry = dev->sg;
        int max_pages;
index 596da01..15cfe56 100644 (file)
@@ -142,11 +142,22 @@ static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
        return ret;
 }
 
+static u32 RS600_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+{
+       u32 ret;
+       RADEON_WRITE(RS600_MC_INDEX, ((addr & RS600_MC_ADDR_MASK) |
+                                     RS600_MC_IND_CITF_ARB0));
+       ret = RADEON_READ(RS600_MC_DATA);
+       return ret;
+}
+
 static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
 {
        if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
            ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                return RS690_READ_MCIND(dev_priv, addr);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+               return RS600_READ_MCIND(dev_priv, addr);
        else
                return RS480_READ_MCIND(dev_priv, addr);
 }
@@ -163,6 +174,8 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
        else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
                 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+               return RS600_READ_MCIND(dev_priv, RS600_MC_FB_LOCATION);
        else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
                return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
        else
@@ -180,6 +193,8 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
        else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
                 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+               RS600_WRITE_MCIND(RS600_MC_FB_LOCATION, fb_loc);
        else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
                R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
        else
@@ -200,6 +215,8 @@ void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
        else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
                 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
                RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+               RS600_WRITE_MCIND(RS600_MC_AGP_LOCATION, agp_loc);
        else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
                R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
        else
@@ -224,6 +241,9 @@ void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
                 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
                RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
                RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
+       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
+               RS600_WRITE_MCIND(RS600_AGP_BASE, agp_base_lo);
+               RS600_WRITE_MCIND(RS600_AGP_BASE_2, agp_base_hi);
        } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
                R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
                R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
@@ -494,6 +514,14 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
                        RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
                                     RS690_cp_microcode[i][0]);
                }
+       } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
+               DRM_INFO("Loading RS600 Microcode\n");
+               for (i = 0; i < 256; i++) {
+                       RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
+                                    RS600_cp_microcode[i][1]);
+                       RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
+                                    RS600_cp_microcode[i][0]);
+               }
        } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) ||
                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) ||
                   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) ||
@@ -899,6 +927,82 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
        }
 }
 
+/* Enable or disable IGP GART on the chip */
+static void rs600_set_igpgart(drm_radeon_private_t *dev_priv, int on)
+{
+       u32 temp;
+       int i;
+
+       if (on) {
+               DRM_DEBUG("programming igp gart %08X %08lX %08X\n",
+                        dev_priv->gart_vm_start,
+                        (long)dev_priv->gart_info.bus_addr,
+                        dev_priv->gart_size);
+
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (RS600_EFFECTIVE_L2_CACHE_SIZE(6) |
+                                                   RS600_EFFECTIVE_L2_QUEUE_SIZE(6)));
+
+               for (i = 0; i < 19; i++)
+                       IGP_WRITE_MCIND(RS600_MC_PT0_CLIENT0_CNTL + i,
+                                       (RS600_ENABLE_TRANSLATION_MODE_OVERRIDE |
+                                        RS600_SYSTEM_ACCESS_MODE_IN_SYS |
+                                        RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH |
+                                        RS600_EFFECTIVE_L1_CACHE_SIZE(3) |
+                                        RS600_ENABLE_FRAGMENT_PROCESSING |
+                                        RS600_EFFECTIVE_L1_QUEUE_SIZE(3)));
+
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL, (RS600_ENABLE_PAGE_TABLE |
+                                                            RS600_PAGE_TABLE_TYPE_FLAT));
+
+               /* disable all other contexts */
+               for (i = 1; i < 8; i++)
+                       IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL + i, 0);
+
+               /* setup the page table aperture */
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR,
+                               dev_priv->gart_info.bus_addr);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR,
+                               dev_priv->gart_vm_start);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR,
+                               (dev_priv->gart_vm_start + dev_priv->gart_size - 1));
+               IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0);
+
+               /* setup the system aperture */
+               IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR,
+                               dev_priv->gart_vm_start);
+               IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR,
+                               (dev_priv->gart_vm_start + dev_priv->gart_size - 1));
+
+               /* enable page tables */
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (temp | RS600_ENABLE_PT));
+
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1);
+               IGP_WRITE_MCIND(RS600_MC_CNTL1, (temp | RS600_ENABLE_PAGE_TABLES));
+
+               /* invalidate the cache */
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+
+               temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+
+               temp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE;
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+
+               temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
+
+       } else {
+               IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, 0);
+               temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1);
+               temp &= ~RS600_ENABLE_PAGE_TABLES;
+               IGP_WRITE_MCIND(RS600_MC_CNTL1, temp);
+       }
+}
+
 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);
@@ -940,6 +1044,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
                return;
        }
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
+               rs600_set_igpgart(dev_priv, on);
+               return;
+       }
+
        if (dev_priv->flags & RADEON_IS_PCIE) {
                radeon_set_pciegart(dev_priv, on);
                return;
@@ -1350,7 +1459,10 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
 
                sctrl = RADEON_READ(RADEON_SURFACE_CNTL);
                RADEON_WRITE(RADEON_SURFACE_CNTL, 0);
-               ret = drm_ati_pcigart_init(dev, &dev_priv->gart_info);
+               if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+                       ret = r600_page_table_init(dev);
+               else
+                       ret = drm_ati_pcigart_init(dev, &dev_priv->gart_info);
                RADEON_WRITE(RADEON_SURFACE_CNTL, sctrl);
 
                if (!ret) {
@@ -1362,7 +1474,10 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
                ret = radeon_setup_pcigart_surface(dev_priv);
                if (ret) {
                        DRM_ERROR("failed to setup GART surface!\n");
-                       drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info);
+                       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+                               r600_page_table_cleanup(dev, &dev_priv->gart_info);
+                       else
+                               drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info);
                        radeon_do_cleanup_cp(dev);
                        return ret;
                }
@@ -1415,8 +1530,12 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
                if (dev_priv->gart_info.bus_addr) {
                        /* Turn off PCI GART */
                        radeon_set_pcigart(dev_priv, 0);
-                       if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
-                               DRM_ERROR("failed to cleanup PCI GART!\n");
+                       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
+                               r600_page_table_cleanup(dev, &dev_priv->gart_info);
+                       else {
+                               if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
+                                       DRM_ERROR("failed to cleanup PCI GART!\n");
+                       }
                }
 
                if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
index 86614a2..7091aaf 100644 (file)
@@ -126,6 +126,7 @@ enum radeon_family {
        CHIP_RV410,
        CHIP_RS400,
        CHIP_RS480,
+       CHIP_RS600,
        CHIP_RS690,
        CHIP_RS740,
        CHIP_RV515,
@@ -474,6 +475,8 @@ extern void r600_do_cp_reset(drm_radeon_private_t *dev_priv);
 extern void r600_do_cp_stop(drm_radeon_private_t *dev_priv);
 extern int r600_cp_dispatch_indirect(struct drm_device *dev,
                                     struct drm_buf *buf, int start, int end);
+extern int r600_page_table_init(struct drm_device *dev);
+extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info);
 
 /* Flags for stats.boxes
  */
@@ -610,6 +613,56 @@ extern int r600_cp_dispatch_indirect(struct drm_device *dev,
 #define RS690_MC_AGP_BASE               0x102
 #define RS690_MC_AGP_BASE_2             0x103
 
+#define RS600_MC_INDEX                          0x70
+#       define RS600_MC_ADDR_MASK               0xffff
+#       define RS600_MC_IND_SEQ_RBS_0           (1 << 16)
+#       define RS600_MC_IND_SEQ_RBS_1           (1 << 17)
+#       define RS600_MC_IND_SEQ_RBS_2           (1 << 18)
+#       define RS600_MC_IND_SEQ_RBS_3           (1 << 19)
+#       define RS600_MC_IND_AIC_RBS             (1 << 20)
+#       define RS600_MC_IND_CITF_ARB0           (1 << 21)
+#       define RS600_MC_IND_CITF_ARB1           (1 << 22)
+#       define RS600_MC_IND_WR_EN               (1 << 23)
+#define RS600_MC_DATA                           0x74
+
+#define RS600_MC_STATUS                         0x0
+#       define RS600_MC_IDLE                    (1 << 1)
+#define RS600_MC_FB_LOCATION                    0x4
+#define RS600_MC_AGP_LOCATION                   0x5
+#define RS600_AGP_BASE                          0x6
+#define RS600_AGP_BASE_2                        0x7
+#define RS600_MC_CNTL1                          0x9
+#       define RS600_ENABLE_PAGE_TABLES         (1 << 26)
+#define RS600_MC_PT0_CNTL                       0x100
+#       define RS600_ENABLE_PT                  (1 << 0)
+#       define RS600_EFFECTIVE_L2_CACHE_SIZE(x) ((x) << 15)
+#       define RS600_EFFECTIVE_L2_QUEUE_SIZE(x) ((x) << 21)
+#       define RS600_INVALIDATE_ALL_L1_TLBS     (1 << 28)
+#       define RS600_INVALIDATE_L2_CACHE        (1 << 29)
+#define RS600_MC_PT0_CONTEXT0_CNTL              0x102
+#       define RS600_ENABLE_PAGE_TABLE          (1 << 0)
+#       define RS600_PAGE_TABLE_TYPE_FLAT       (0 << 1)
+#define RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR   0x112
+#define RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR  0x114
+#define RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR 0x11c
+#define RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR    0x12c
+#define RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR   0x13c
+#define RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR     0x14c
+#define RS600_MC_PT0_CLIENT0_CNTL               0x16c
+#       define RS600_ENABLE_TRANSLATION_MODE_OVERRIDE       (1 << 0)
+#       define RS600_TRANSLATION_MODE_OVERRIDE              (1 << 1)
+#       define RS600_SYSTEM_ACCESS_MODE_MASK                (3 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_PA_ONLY             (0 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_USE_SYS_MAP         (1 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_IN_SYS              (2 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_NOT_IN_SYS          (3 << 8)
+#       define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH        (0 << 10)
+#       define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE       (1 << 10)
+#       define RS600_EFFECTIVE_L1_CACHE_SIZE(x) ((x) << 11)
+#       define RS600_ENABLE_FRAGMENT_PROCESSING (1 << 14)
+#       define RS600_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 15)
+#       define RS600_INVALIDATE_L1_TLB          (1 << 20)
+
 #define R520_MC_IND_INDEX 0x70
 #define R520_MC_IND_WR_EN (1 << 24)
 #define R520_MC_IND_DATA  0x74
@@ -1743,11 +1796,19 @@ do {                                                            \
        RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK);    \
 } while (0)
 
+#define RS600_WRITE_MCIND(addr, val)                           \
+do {                                                           \
+       RADEON_WRITE(RS600_MC_INDEX, RS600_MC_IND_WR_EN | RS600_MC_IND_CITF_ARB0 | ((addr) & RS600_MC_ADDR_MASK)); \
+       RADEON_WRITE(RS600_MC_DATA, val);                       \
+} while (0)
+
 #define IGP_WRITE_MCIND(addr, val)                             \
 do {                                                                   \
        if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||   \
            ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))      \
                RS690_WRITE_MCIND(addr, val);                           \
+       else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)  \
+               RS600_WRITE_MCIND(addr, val);                           \
        else                                                            \
                RS480_WRITE_MCIND(addr, val);                           \
 } while (0)