summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2009-02-26 00:57:49 +0300
committerDave Airlie <airlied@redhat.com>2009-03-13 07:24:13 +0300
commitc1556f71513f2e660fb2bbdc29344361b1ebff35 (patch)
treea7720f25bf130eb77475b6735fc522e151dcbf9d /drivers
parent7659e9804b7a66047433182d86393d38ba4eff79 (diff)
downloadlinux-c1556f71513f2e660fb2bbdc29344361b1ebff35.tar.xz
radeon: add support for rs600 GPUs
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/radeon/r600_cp.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c127
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.h61
3 files changed, 185 insertions, 5 deletions
diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c
index 3f40558beece..0143a144a294 100644
--- a/drivers/gpu/drm/radeon/r600_cp.c
+++ b/drivers/gpu/drm/radeon/r600_cp.c
@@ -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;
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 596da014dfd9..15cfe56c7aaa 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -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)
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index 86614a27bb6e..7091aafff196 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -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)