1254885Sdumbbell/** 2254885Sdumbbell * \file ati_pcigart.c 3254885Sdumbbell * ATI PCI GART support 4254885Sdumbbell * 5254885Sdumbbell * \author Gareth Hughes <gareth@valinux.com> 6254885Sdumbbell */ 7254885Sdumbbell 8254885Sdumbbell/* 9254885Sdumbbell * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com 10254885Sdumbbell * 11254885Sdumbbell * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 12254885Sdumbbell * All Rights Reserved. 13254885Sdumbbell * 14254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 15254885Sdumbbell * copy of this software and associated documentation files (the "Software"), 16254885Sdumbbell * to deal in the Software without restriction, including without limitation 17254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 18254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 19254885Sdumbbell * Software is furnished to do so, subject to the following conditions: 20254885Sdumbbell * 21254885Sdumbbell * The above copyright notice and this permission notice (including the next 22254885Sdumbbell * paragraph) shall be included in all copies or substantial portions of the 23254885Sdumbbell * Software. 24254885Sdumbbell * 25254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28254885Sdumbbell * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 29254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 30254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31254885Sdumbbell * DEALINGS IN THE SOFTWARE. 32254885Sdumbbell */ 33254885Sdumbbell 34254885Sdumbbell#include <sys/cdefs.h> 35254885Sdumbbell__FBSDID("$FreeBSD$"); 36254885Sdumbbell 37254885Sdumbbell#include <dev/drm2/drmP.h> 38254885Sdumbbell 39254885Sdumbbell# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ 40254885Sdumbbell 41254885Sdumbbellstatic int drm_ati_alloc_pcigart_table(struct drm_device *dev, 42254885Sdumbbell struct drm_ati_pcigart_info *gart_info) 43254885Sdumbbell{ 44254885Sdumbbell gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size, 45254885Sdumbbell PAGE_SIZE, 0xFFFFFFFFUL); 46254885Sdumbbell if (gart_info->table_handle == NULL) 47254885Sdumbbell return -ENOMEM; 48254885Sdumbbell 49254885Sdumbbell return 0; 50254885Sdumbbell} 51254885Sdumbbell 52254885Sdumbbellstatic void drm_ati_free_pcigart_table(struct drm_device *dev, 53254885Sdumbbell struct drm_ati_pcigart_info *gart_info) 54254885Sdumbbell{ 55254885Sdumbbell drm_pci_free(dev, gart_info->table_handle); 56254885Sdumbbell gart_info->table_handle = NULL; 57254885Sdumbbell} 58254885Sdumbbell 59254885Sdumbbellint drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) 60254885Sdumbbell{ 61254885Sdumbbell struct drm_sg_mem *entry = dev->sg; 62254885Sdumbbell#ifdef __linux__ 63254885Sdumbbell unsigned long pages; 64254885Sdumbbell int i; 65254885Sdumbbell int max_pages; 66254885Sdumbbell#endif 67254885Sdumbbell 68254885Sdumbbell /* we need to support large memory configurations */ 69254885Sdumbbell if (!entry) { 70254885Sdumbbell DRM_ERROR("no scatter/gather memory!\n"); 71254885Sdumbbell return 0; 72254885Sdumbbell } 73254885Sdumbbell 74254885Sdumbbell if (gart_info->bus_addr) { 75254885Sdumbbell#ifdef __linux__ 76254885Sdumbbell 77254885Sdumbbell max_pages = (gart_info->table_size / sizeof(u32)); 78254885Sdumbbell pages = (entry->pages <= max_pages) 79254885Sdumbbell ? entry->pages : max_pages; 80254885Sdumbbell 81254885Sdumbbell for (i = 0; i < pages; i++) { 82254885Sdumbbell if (!entry->busaddr[i]) 83254885Sdumbbell break; 84254885Sdumbbell pci_unmap_page(dev->pdev, entry->busaddr[i], 85254885Sdumbbell PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 86254885Sdumbbell } 87254885Sdumbbell#endif 88254885Sdumbbell 89254885Sdumbbell if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) 90254885Sdumbbell gart_info->bus_addr = 0; 91254885Sdumbbell } 92254885Sdumbbell 93254885Sdumbbell if (gart_info->gart_table_location == DRM_ATI_GART_MAIN && 94254885Sdumbbell gart_info->table_handle) { 95254885Sdumbbell drm_ati_free_pcigart_table(dev, gart_info); 96254885Sdumbbell } 97254885Sdumbbell 98254885Sdumbbell return 1; 99254885Sdumbbell} 100254885Sdumbbell 101254885Sdumbbellint drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) 102254885Sdumbbell{ 103254885Sdumbbell struct drm_local_map *map = &gart_info->mapping; 104254885Sdumbbell struct drm_sg_mem *entry = dev->sg; 105254885Sdumbbell void *address = NULL; 106254885Sdumbbell unsigned long pages; 107254885Sdumbbell u32 *pci_gart = NULL, page_base, gart_idx; 108254885Sdumbbell dma_addr_t bus_address = 0; 109254885Sdumbbell int i, j, ret = 0; 110254885Sdumbbell int max_ati_pages, max_real_pages; 111254885Sdumbbell 112254885Sdumbbell if (!entry) { 113254885Sdumbbell DRM_ERROR("no scatter/gather memory!\n"); 114254885Sdumbbell goto done; 115254885Sdumbbell } 116254885Sdumbbell 117254885Sdumbbell if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { 118254885Sdumbbell DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); 119254885Sdumbbell 120254885Sdumbbell#ifdef __linux__ 121254885Sdumbbell if (pci_set_dma_mask(dev->pdev, gart_info->table_mask)) { 122254885Sdumbbell DRM_ERROR("fail to set dma mask to 0x%Lx\n", 123254885Sdumbbell (unsigned long long)gart_info->table_mask); 124254885Sdumbbell ret = 1; 125254885Sdumbbell goto done; 126254885Sdumbbell } 127254885Sdumbbell#endif 128254885Sdumbbell 129254885Sdumbbell ret = drm_ati_alloc_pcigart_table(dev, gart_info); 130254885Sdumbbell if (ret) { 131254885Sdumbbell DRM_ERROR("cannot allocate PCI GART page!\n"); 132254885Sdumbbell goto done; 133254885Sdumbbell } 134254885Sdumbbell 135254885Sdumbbell pci_gart = gart_info->table_handle->vaddr; 136254885Sdumbbell address = gart_info->table_handle->vaddr; 137254885Sdumbbell bus_address = gart_info->table_handle->busaddr; 138254885Sdumbbell } else { 139254885Sdumbbell address = gart_info->addr; 140254885Sdumbbell bus_address = gart_info->bus_addr; 141254885Sdumbbell DRM_DEBUG("PCI: Gart Table: VRAM %08LX mapped at %08lX\n", 142254885Sdumbbell (unsigned long long)bus_address, 143254885Sdumbbell (unsigned long)address); 144254885Sdumbbell } 145254885Sdumbbell 146254885Sdumbbell 147254885Sdumbbell max_ati_pages = (gart_info->table_size / sizeof(u32)); 148254885Sdumbbell max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); 149254885Sdumbbell pages = (entry->pages <= max_real_pages) 150254885Sdumbbell ? entry->pages : max_real_pages; 151254885Sdumbbell 152254885Sdumbbell if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { 153254885Sdumbbell memset(pci_gart, 0, max_ati_pages * sizeof(u32)); 154254885Sdumbbell } else { 155254885Sdumbbell memset_io((void __iomem *)map->handle, 0, max_ati_pages * sizeof(u32)); 156254885Sdumbbell } 157254885Sdumbbell 158254885Sdumbbell gart_idx = 0; 159254885Sdumbbell for (i = 0; i < pages; i++) { 160254885Sdumbbell#ifdef __linux__ 161254885Sdumbbell /* we need to support large memory configurations */ 162254885Sdumbbell entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i], 163254885Sdumbbell 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 164254885Sdumbbell if (pci_dma_mapping_error(dev->pdev, entry->busaddr[i])) { 165254885Sdumbbell DRM_ERROR("unable to map PCIGART pages!\n"); 166254885Sdumbbell drm_ati_pcigart_cleanup(dev, gart_info); 167254885Sdumbbell address = NULL; 168254885Sdumbbell bus_address = 0; 169254885Sdumbbell goto done; 170254885Sdumbbell } 171254885Sdumbbell#endif 172254885Sdumbbell page_base = (u32) entry->busaddr[i]; 173254885Sdumbbell 174254885Sdumbbell for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { 175254885Sdumbbell u32 val; 176254885Sdumbbell 177254885Sdumbbell switch(gart_info->gart_reg_if) { 178254885Sdumbbell case DRM_ATI_GART_IGP: 179254885Sdumbbell val = page_base | 0xc; 180254885Sdumbbell break; 181254885Sdumbbell case DRM_ATI_GART_PCIE: 182254885Sdumbbell val = (page_base >> 8) | 0xc; 183254885Sdumbbell break; 184254885Sdumbbell default: 185254885Sdumbbell case DRM_ATI_GART_PCI: 186254885Sdumbbell val = page_base; 187254885Sdumbbell break; 188254885Sdumbbell } 189254885Sdumbbell if (gart_info->gart_table_location == 190254885Sdumbbell DRM_ATI_GART_MAIN) 191254885Sdumbbell pci_gart[gart_idx] = cpu_to_le32(val); 192254885Sdumbbell else 193254885Sdumbbell DRM_WRITE32(map, gart_idx * sizeof(u32), val); 194254885Sdumbbell gart_idx++; 195254885Sdumbbell page_base += ATI_PCIGART_PAGE_SIZE; 196254885Sdumbbell } 197254885Sdumbbell } 198254885Sdumbbell ret = 1; 199254885Sdumbbell 200254885Sdumbbell#if defined(__i386) || defined(__amd64) 201254885Sdumbbell wbinvd(); 202254885Sdumbbell#else 203254885Sdumbbell mb(); 204254885Sdumbbell#endif 205254885Sdumbbell 206254885Sdumbbell done: 207254885Sdumbbell gart_info->addr = address; 208254885Sdumbbell gart_info->bus_addr = bus_address; 209254885Sdumbbell return ret; 210254885Sdumbbell} 211