summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2008-09-10 02:11:33 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2008-09-10 02:11:33 +0000
commit48ac92e8ee739d7a7fc8a9e9c5d9bbf0ca615f4d (patch)
tree325bd90c6614b4b510f9f75dc8e7454f3cb0253f
parentfd80257e2ebe4148c596e26a045b325e35353afc (diff)
40-bit GART support for PCIE devices. From drm git a while ago.
Tested by a few, no regressions for normal use.
-rw-r--r--sys/dev/pci/drm/ati_pcigart.c140
1 files changed, 99 insertions, 41 deletions
diff --git a/sys/dev/pci/drm/ati_pcigart.c b/sys/dev/pci/drm/ati_pcigart.c
index 1f3e461aa24..a4627413b21 100644
--- a/sys/dev/pci/drm/ati_pcigart.c
+++ b/sys/dev/pci/drm/ati_pcigart.c
@@ -34,80 +34,138 @@
#include "drmP.h"
#define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */
+#define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1))
-int drm_ati_pcigart_init(struct drm_device *dev,
+#define ATI_PCIE_WRITE 0x4
+#define ATI_PCIE_READ 0x8
+
+int drm_ati_alloc_pcigart_table(struct drm_device *,
+ struct drm_ati_pcigart_info *);
+void drm_ati_free_pcigart_table(struct drm_device *,
+ struct drm_ati_pcigart_info *);
+
+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;
+}
+
+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, gart_info->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, gart_info->table_size / sizeof(u32));
- bzero(pci_gart, gart_info->table_size);
+ pci_gart = (u32 *) address;
+
+ max_pages = (gart_info->table_size / sizeof(u32));
+ pages = (dev->sg->pages <= max_pages)
+ ? dev->sg->pages : max_pages;
+
+ memset(pci_gart, 0, max_pages * sizeof(u32));
-#if defined(__FreeBSD__)
+#ifdef __FreeBSD__
KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small"));
#else
KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE);
#endif
- for ( i = 0 ; i < pages ; i++ ) {
- page_base = (u32) dev->sg->busaddr[i];
-
+ for (i = 0; i < pages; i++) {
+ entry_addr = dev->sg->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
+ page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK;
switch(gart_info->gart_reg_if) {
case DRM_ATI_GART_IGP:
- *pci_gart = cpu_to_le32(page_base | 0xc);
+ page_base |= (upper_32_bits(entry_addr) & 0xff) << 4;
+ page_base |= 0xc;
break;
case DRM_ATI_GART_PCIE:
- *pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
+ page_base >>= 8;
+ page_base |= (upper_32_bits(entry_addr) & 0xff) << 24;
+ page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE;
break;
default:
- *pci_gart = cpu_to_le32(page_base);
+ 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(struct drm_device *dev,
- struct 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;
}