summaryrefslogtreecommitdiffstats
path: root/sys/dev/drm/ati_pcigart.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/drm/ati_pcigart.c')
-rw-r--r--sys/dev/drm/ati_pcigart.c148
1 files changed, 103 insertions, 45 deletions
diff --git a/sys/dev/drm/ati_pcigart.c b/sys/dev/drm/ati_pcigart.c
index 386702c..dac400d 100644
--- a/sys/dev/drm/ati_pcigart.c
+++ b/sys/dev/drm/ati_pcigart.c
@@ -1,6 +1,3 @@
-/* ati_pcigart.h -- ATI PCI GART support -*- linux-c -*-
- * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com
- */
/*-
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
@@ -32,72 +29,133 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+/** @file ati_pcigart.c
+ * Implementation of ATI's PCIGART, which provides an aperture in card virtual
+ * address space with addresses remapped to system memory.
+ */
+
#include "dev/drm/drmP.h"
#define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */
-#define ATI_MAX_PCIGART_PAGES 8192 /* 32 MB aperture, 4K pages */
-#define ATI_PCIGART_TABLE_SIZE 32768
+#define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1))
-int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
+#define ATI_PCIE_WRITE 0x4
+#define ATI_PCIE_READ 0x8
+
+static int drm_ati_alloc_pcigart_table(struct drm_device *dev,
+ struct drm_ati_pcigart_info *gart_info)
{
- unsigned long pages;
- u32 *pci_gart = NULL, page_base;
- int i, j;
+ dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size,
+ PAGE_SIZE,
+ gart_info->table_mask);
+ if (dev->sg->dmah == NULL)
+ return ENOMEM;
+
+ return 0;
+}
+
+static void drm_ati_free_pcigart_table(struct drm_device *dev,
+ struct drm_ati_pcigart_info *gart_info)
+{
+ drm_pci_free(dev, dev->sg->dmah);
+ dev->sg->dmah = NULL;
+}
+int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
+{
+ /* we need to support large memory configurations */
if (dev->sg == NULL) {
- DRM_ERROR( "no scatter/gather memory!\n" );
+ DRM_ERROR("no scatter/gather memory!\n");
return 0;
}
+ if (gart_info->bus_addr) {
+ if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
+ gart_info->bus_addr = 0;
+ if (dev->sg->dmah)
+ drm_ati_free_pcigart_table(dev, gart_info);
+ }
+ }
+
+ return 1;
+}
+
+int drm_ati_pcigart_init(struct drm_device *dev,
+ struct drm_ati_pcigart_info *gart_info)
+{
+
+ void *address = NULL;
+ unsigned long pages;
+ u32 *pci_gart, page_base;
+ dma_addr_t bus_address = 0;
+ int i, j, ret = 0;
+ int max_pages;
+ dma_addr_t entry_addr;
+
+ /* we need to support large memory configurations */
+ if (dev->sg == NULL) {
+ DRM_ERROR("no scatter/gather memory!\n");
+ goto done;
+ }
+
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
- /* GART table in system memory */
- dev->sg->dmah = drm_pci_alloc(dev, ATI_PCIGART_TABLE_SIZE, 0,
- 0xfffffffful);
- if (dev->sg->dmah == NULL) {
- DRM_ERROR("cannot allocate PCI GART table!\n");
- return 0;
+ DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
+
+ ret = drm_ati_alloc_pcigart_table(dev, gart_info);
+ if (ret) {
+ DRM_ERROR("cannot allocate PCI GART page!\n");
+ goto done;
}
-
- gart_info->addr = (void *)dev->sg->dmah->vaddr;
- gart_info->bus_addr = dev->sg->dmah->busaddr;
- pci_gart = (u32 *)dev->sg->dmah->vaddr;
+
+ address = (void *)dev->sg->dmah->vaddr;
+ bus_address = dev->sg->dmah->busaddr;
} else {
- /* GART table in framebuffer memory */
- pci_gart = gart_info->addr;
+ address = gart_info->addr;
+ bus_address = gart_info->bus_addr;
+ DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n",
+ (unsigned int)bus_address, (unsigned long)address);
}
-
- pages = DRM_MIN(dev->sg->pages, ATI_MAX_PCIGART_PAGES);
- bzero(pci_gart, ATI_PCIGART_TABLE_SIZE);
+ pci_gart = (u32 *) address;
- KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small"));
+ max_pages = (gart_info->table_size / sizeof(u32));
+ pages = (dev->sg->pages <= max_pages)
+ ? dev->sg->pages : max_pages;
- for ( i = 0 ; i < pages ; i++ ) {
- page_base = (u32) dev->sg->busaddr[i];
+ memset(pci_gart, 0, max_pages * sizeof(u32));
+
+ KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small"));
+ for (i = 0; i < pages; i++) {
+ entry_addr = dev->sg->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
- if (gart_info->is_pcie)
- *pci_gart = (cpu_to_le32(page_base) >> 8) | 0xc;
- else
- *pci_gart = cpu_to_le32(page_base);
+ page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK;
+ switch(gart_info->gart_reg_if) {
+ case DRM_ATI_GART_IGP:
+ page_base |= (upper_32_bits(entry_addr) & 0xff) << 4;
+ page_base |= 0xc;
+ break;
+ case DRM_ATI_GART_PCIE:
+ page_base >>= 8;
+ page_base |= (upper_32_bits(entry_addr) & 0xff) << 24;
+ page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE;
+ break;
+ default:
+ case DRM_ATI_GART_PCI:
+ break;
+ }
+ *pci_gart = cpu_to_le32(page_base);
pci_gart++;
- page_base += ATI_PCIGART_PAGE_SIZE;
+ entry_addr += ATI_PCIGART_PAGE_SIZE;
}
}
DRM_MEMORYBARRIER();
- return 1;
-}
-
-int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
-{
- if (dev->sg == NULL) {
- DRM_ERROR( "no scatter/gather memory!\n" );
- return 0;
- }
+ ret = 1;
- drm_pci_free(dev, dev->sg->dmah);
-
- return 1;
+ done:
+ gart_info->addr = address;
+ gart_info->bus_addr = bus_address;
+ return ret;
}
OpenPOWER on IntegriCloud