162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * ATi AGPGART routines. 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/types.h> 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/pci.h> 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/string.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/agp_backend.h> 1262306a36Sopenharmony_ci#include <asm/agp.h> 1362306a36Sopenharmony_ci#include <asm/set_memory.h> 1462306a36Sopenharmony_ci#include "agp.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define ATI_GART_MMBASE_BAR 1 1762306a36Sopenharmony_ci#define ATI_RS100_APSIZE 0xac 1862306a36Sopenharmony_ci#define ATI_RS100_IG_AGPMODE 0xb0 1962306a36Sopenharmony_ci#define ATI_RS300_APSIZE 0xf8 2062306a36Sopenharmony_ci#define ATI_RS300_IG_AGPMODE 0xfc 2162306a36Sopenharmony_ci#define ATI_GART_FEATURE_ID 0x00 2262306a36Sopenharmony_ci#define ATI_GART_BASE 0x04 2362306a36Sopenharmony_ci#define ATI_GART_CACHE_SZBASE 0x08 2462306a36Sopenharmony_ci#define ATI_GART_CACHE_CNTRL 0x0c 2562306a36Sopenharmony_ci#define ATI_GART_CACHE_ENTRY_CNTRL 0x10 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const struct aper_size_info_lvl2 ati_generic_sizes[7] = 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci {2048, 524288, 0x0000000c}, 3162306a36Sopenharmony_ci {1024, 262144, 0x0000000a}, 3262306a36Sopenharmony_ci {512, 131072, 0x00000008}, 3362306a36Sopenharmony_ci {256, 65536, 0x00000006}, 3462306a36Sopenharmony_ci {128, 32768, 0x00000004}, 3562306a36Sopenharmony_ci {64, 16384, 0x00000002}, 3662306a36Sopenharmony_ci {32, 8192, 0x00000000} 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic struct gatt_mask ati_generic_masks[] = 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci { .mask = 1, .type = 0} 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct ati_page_map { 4662306a36Sopenharmony_ci unsigned long *real; 4762306a36Sopenharmony_ci unsigned long __iomem *remapped; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic struct _ati_generic_private { 5162306a36Sopenharmony_ci volatile u8 __iomem *registers; 5262306a36Sopenharmony_ci struct ati_page_map **gatt_pages; 5362306a36Sopenharmony_ci int num_tables; 5462306a36Sopenharmony_ci} ati_generic_private; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int ati_create_page_map(struct ati_page_map *page_map) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci int i, err; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); 6162306a36Sopenharmony_ci if (page_map->real == NULL) 6262306a36Sopenharmony_ci return -ENOMEM; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci set_memory_uc((unsigned long)page_map->real, 1); 6562306a36Sopenharmony_ci err = map_page_into_agp(virt_to_page(page_map->real)); 6662306a36Sopenharmony_ci if (err) { 6762306a36Sopenharmony_ci free_page((unsigned long)page_map->real); 6862306a36Sopenharmony_ci return err; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci page_map->remapped = page_map->real; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { 7362306a36Sopenharmony_ci writel(agp_bridge->scratch_page, page_map->remapped+i); 7462306a36Sopenharmony_ci readl(page_map->remapped+i); /* PCI Posting. */ 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic void ati_free_page_map(struct ati_page_map *page_map) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci unmap_page_from_agp(virt_to_page(page_map->real)); 8462306a36Sopenharmony_ci set_memory_wb((unsigned long)page_map->real, 1); 8562306a36Sopenharmony_ci free_page((unsigned long) page_map->real); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void ati_free_gatt_pages(void) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci int i; 9262306a36Sopenharmony_ci struct ati_page_map **tables; 9362306a36Sopenharmony_ci struct ati_page_map *entry; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci tables = ati_generic_private.gatt_pages; 9662306a36Sopenharmony_ci for (i = 0; i < ati_generic_private.num_tables; i++) { 9762306a36Sopenharmony_ci entry = tables[i]; 9862306a36Sopenharmony_ci if (entry != NULL) { 9962306a36Sopenharmony_ci if (entry->real != NULL) 10062306a36Sopenharmony_ci ati_free_page_map(entry); 10162306a36Sopenharmony_ci kfree(entry); 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci kfree(tables); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int ati_create_gatt_pages(int nr_tables) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct ati_page_map **tables; 11162306a36Sopenharmony_ci struct ati_page_map *entry; 11262306a36Sopenharmony_ci int retval = 0; 11362306a36Sopenharmony_ci int i; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci tables = kcalloc(nr_tables + 1, sizeof(struct ati_page_map *), 11662306a36Sopenharmony_ci GFP_KERNEL); 11762306a36Sopenharmony_ci if (tables == NULL) 11862306a36Sopenharmony_ci return -ENOMEM; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci for (i = 0; i < nr_tables; i++) { 12162306a36Sopenharmony_ci entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL); 12262306a36Sopenharmony_ci tables[i] = entry; 12362306a36Sopenharmony_ci if (entry == NULL) { 12462306a36Sopenharmony_ci retval = -ENOMEM; 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci retval = ati_create_page_map(entry); 12862306a36Sopenharmony_ci if (retval != 0) 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci ati_generic_private.num_tables = i; 13262306a36Sopenharmony_ci ati_generic_private.gatt_pages = tables; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (retval != 0) 13562306a36Sopenharmony_ci ati_free_gatt_pages(); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return retval; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int is_r200(void) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci if ((agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS100) || 14362306a36Sopenharmony_ci (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200) || 14462306a36Sopenharmony_ci (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200_B) || 14562306a36Sopenharmony_ci (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS250)) 14662306a36Sopenharmony_ci return 1; 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int ati_fetch_size(void) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci int i; 15362306a36Sopenharmony_ci u32 temp; 15462306a36Sopenharmony_ci struct aper_size_info_lvl2 *values; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (is_r200()) 15762306a36Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp); 15862306a36Sopenharmony_ci else 15962306a36Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci temp = (temp & 0x0000000e); 16262306a36Sopenharmony_ci values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes); 16362306a36Sopenharmony_ci for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { 16462306a36Sopenharmony_ci if (temp == values[i].size_value) { 16562306a36Sopenharmony_ci agp_bridge->previous_size = 16662306a36Sopenharmony_ci agp_bridge->current_size = (void *) (values + i); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci agp_bridge->aperture_size_idx = i; 16962306a36Sopenharmony_ci return values[i].size; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic void ati_tlbflush(struct agp_memory * mem) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci writel(1, ati_generic_private.registers+ATI_GART_CACHE_CNTRL); 17962306a36Sopenharmony_ci readl(ati_generic_private.registers+ATI_GART_CACHE_CNTRL); /* PCI Posting. */ 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void ati_cleanup(void) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct aper_size_info_lvl2 *previous_size; 18562306a36Sopenharmony_ci u32 temp; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci previous_size = A_SIZE_LVL2(agp_bridge->previous_size); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Write back the previous size and disable gart translation */ 19062306a36Sopenharmony_ci if (is_r200()) { 19162306a36Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp); 19262306a36Sopenharmony_ci temp = ((temp & ~(0x0000000f)) | previous_size->size_value); 19362306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp); 19462306a36Sopenharmony_ci } else { 19562306a36Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp); 19662306a36Sopenharmony_ci temp = ((temp & ~(0x0000000f)) | previous_size->size_value); 19762306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci iounmap((volatile u8 __iomem *)ati_generic_private.registers); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int ati_configure(void) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci phys_addr_t reg; 20662306a36Sopenharmony_ci u32 temp; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Get the memory mapped registers */ 20962306a36Sopenharmony_ci reg = pci_resource_start(agp_bridge->dev, ATI_GART_MMBASE_BAR); 21062306a36Sopenharmony_ci ati_generic_private.registers = (volatile u8 __iomem *) ioremap(reg, 4096); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!ati_generic_private.registers) 21362306a36Sopenharmony_ci return -ENOMEM; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (is_r200()) 21662306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000); 21762306a36Sopenharmony_ci else 21862306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* address to map to */ 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci agp_bridge.gart_bus_addr = pci_bus_address(agp_bridge.dev, 22362306a36Sopenharmony_ci AGP_APERTURE_BAR); 22462306a36Sopenharmony_ci printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr); 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID); 22762306a36Sopenharmony_ci readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/ 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* SIGNALED_SYSTEM_ERROR @ NB_STATUS */ 23062306a36Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, PCI_COMMAND, &temp); 23162306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, PCI_COMMAND, temp | (1<<14)); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Write out the address of the gatt table */ 23462306a36Sopenharmony_ci writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE); 23562306a36Sopenharmony_ci readl(ati_generic_private.registers+ATI_GART_BASE); /* PCI Posting. */ 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int agp_ati_resume(struct device *dev) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci return ati_configure(); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* 24762306a36Sopenharmony_ci *Since we don't need contiguous memory we just try 24862306a36Sopenharmony_ci * to get the gatt table once 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#define GET_PAGE_DIR_OFF(addr) (addr >> 22) 25262306a36Sopenharmony_ci#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ 25362306a36Sopenharmony_ci GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr)) 25462306a36Sopenharmony_ci#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) 25562306a36Sopenharmony_ci#undef GET_GATT 25662306a36Sopenharmony_ci#define GET_GATT(addr) (ati_generic_private.gatt_pages[\ 25762306a36Sopenharmony_ci GET_PAGE_DIR_IDX(addr)]->remapped) 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int ati_insert_memory(struct agp_memory * mem, 26062306a36Sopenharmony_ci off_t pg_start, int type) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci int i, j, num_entries; 26362306a36Sopenharmony_ci unsigned long __iomem *cur_gatt; 26462306a36Sopenharmony_ci unsigned long addr; 26562306a36Sopenharmony_ci int mask_type; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci mask_type = agp_generic_type_to_mask_type(mem->bridge, type); 27062306a36Sopenharmony_ci if (mask_type != 0 || type != mem->type) 27162306a36Sopenharmony_ci return -EINVAL; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (mem->page_count == 0) 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if ((pg_start + mem->page_count) > num_entries) 27762306a36Sopenharmony_ci return -EINVAL; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci j = pg_start; 28062306a36Sopenharmony_ci while (j < (pg_start + mem->page_count)) { 28162306a36Sopenharmony_ci addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; 28262306a36Sopenharmony_ci cur_gatt = GET_GATT(addr); 28362306a36Sopenharmony_ci if (!PGE_EMPTY(agp_bridge,readl(cur_gatt+GET_GATT_OFF(addr)))) 28462306a36Sopenharmony_ci return -EBUSY; 28562306a36Sopenharmony_ci j++; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (!mem->is_flushed) { 28962306a36Sopenharmony_ci /*CACHE_FLUSH(); */ 29062306a36Sopenharmony_ci global_cache_flush(); 29162306a36Sopenharmony_ci mem->is_flushed = true; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 29562306a36Sopenharmony_ci addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; 29662306a36Sopenharmony_ci cur_gatt = GET_GATT(addr); 29762306a36Sopenharmony_ci writel(agp_bridge->driver->mask_memory(agp_bridge, 29862306a36Sopenharmony_ci page_to_phys(mem->pages[i]), 29962306a36Sopenharmony_ci mem->type), 30062306a36Sopenharmony_ci cur_gatt+GET_GATT_OFF(addr)); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */ 30362306a36Sopenharmony_ci agp_bridge->driver->tlb_flush(mem); 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int ati_remove_memory(struct agp_memory * mem, off_t pg_start, 30862306a36Sopenharmony_ci int type) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci int i; 31162306a36Sopenharmony_ci unsigned long __iomem *cur_gatt; 31262306a36Sopenharmony_ci unsigned long addr; 31362306a36Sopenharmony_ci int mask_type; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci mask_type = agp_generic_type_to_mask_type(mem->bridge, type); 31662306a36Sopenharmony_ci if (mask_type != 0 || type != mem->type) 31762306a36Sopenharmony_ci return -EINVAL; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (mem->page_count == 0) 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci for (i = pg_start; i < (mem->page_count + pg_start); i++) { 32362306a36Sopenharmony_ci addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; 32462306a36Sopenharmony_ci cur_gatt = GET_GATT(addr); 32562306a36Sopenharmony_ci writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */ 32962306a36Sopenharmony_ci agp_bridge->driver->tlb_flush(mem); 33062306a36Sopenharmony_ci return 0; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int ati_create_gatt_table(struct agp_bridge_data *bridge) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct aper_size_info_lvl2 *value; 33662306a36Sopenharmony_ci struct ati_page_map page_dir; 33762306a36Sopenharmony_ci unsigned long __iomem *cur_gatt; 33862306a36Sopenharmony_ci unsigned long addr; 33962306a36Sopenharmony_ci int retval; 34062306a36Sopenharmony_ci u32 temp; 34162306a36Sopenharmony_ci int i; 34262306a36Sopenharmony_ci struct aper_size_info_lvl2 *current_size; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci value = A_SIZE_LVL2(agp_bridge->current_size); 34562306a36Sopenharmony_ci retval = ati_create_page_map(&page_dir); 34662306a36Sopenharmony_ci if (retval != 0) 34762306a36Sopenharmony_ci return retval; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci retval = ati_create_gatt_pages(value->num_entries / 1024); 35062306a36Sopenharmony_ci if (retval != 0) { 35162306a36Sopenharmony_ci ati_free_page_map(&page_dir); 35262306a36Sopenharmony_ci return retval; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci agp_bridge->gatt_table_real = (u32 *)page_dir.real; 35662306a36Sopenharmony_ci agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped; 35762306a36Sopenharmony_ci agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* Write out the size register */ 36062306a36Sopenharmony_ci current_size = A_SIZE_LVL2(agp_bridge->current_size); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (is_r200()) { 36362306a36Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp); 36462306a36Sopenharmony_ci temp = (((temp & ~(0x0000000e)) | current_size->size_value) 36562306a36Sopenharmony_ci | 0x00000001); 36662306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp); 36762306a36Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp); 36862306a36Sopenharmony_ci } else { 36962306a36Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp); 37062306a36Sopenharmony_ci temp = (((temp & ~(0x0000000e)) | current_size->size_value) 37162306a36Sopenharmony_ci | 0x00000001); 37262306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp); 37362306a36Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* 37762306a36Sopenharmony_ci * Get the address for the gart region. 37862306a36Sopenharmony_ci * This is a bus address even on the alpha, b/c its 37962306a36Sopenharmony_ci * used to program the agp master not the cpu 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR); 38262306a36Sopenharmony_ci agp_bridge->gart_bus_addr = addr; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Calculate the agp offset */ 38562306a36Sopenharmony_ci for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { 38662306a36Sopenharmony_ci writel(virt_to_phys(ati_generic_private.gatt_pages[i]->real) | 1, 38762306a36Sopenharmony_ci page_dir.remapped+GET_PAGE_DIR_OFF(addr)); 38862306a36Sopenharmony_ci readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr)); /* PCI Posting. */ 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci for (i = 0; i < value->num_entries; i++) { 39262306a36Sopenharmony_ci addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; 39362306a36Sopenharmony_ci cur_gatt = GET_GATT(addr); 39462306a36Sopenharmony_ci writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int ati_free_gatt_table(struct agp_bridge_data *bridge) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct ati_page_map page_dir; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci page_dir.real = (unsigned long *)agp_bridge->gatt_table_real; 40562306a36Sopenharmony_ci page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci ati_free_gatt_pages(); 40862306a36Sopenharmony_ci ati_free_page_map(&page_dir); 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic const struct agp_bridge_driver ati_generic_bridge = { 41362306a36Sopenharmony_ci .owner = THIS_MODULE, 41462306a36Sopenharmony_ci .aperture_sizes = ati_generic_sizes, 41562306a36Sopenharmony_ci .size_type = LVL2_APER_SIZE, 41662306a36Sopenharmony_ci .num_aperture_sizes = 7, 41762306a36Sopenharmony_ci .needs_scratch_page = true, 41862306a36Sopenharmony_ci .configure = ati_configure, 41962306a36Sopenharmony_ci .fetch_size = ati_fetch_size, 42062306a36Sopenharmony_ci .cleanup = ati_cleanup, 42162306a36Sopenharmony_ci .tlb_flush = ati_tlbflush, 42262306a36Sopenharmony_ci .mask_memory = agp_generic_mask_memory, 42362306a36Sopenharmony_ci .masks = ati_generic_masks, 42462306a36Sopenharmony_ci .agp_enable = agp_generic_enable, 42562306a36Sopenharmony_ci .cache_flush = global_cache_flush, 42662306a36Sopenharmony_ci .create_gatt_table = ati_create_gatt_table, 42762306a36Sopenharmony_ci .free_gatt_table = ati_free_gatt_table, 42862306a36Sopenharmony_ci .insert_memory = ati_insert_memory, 42962306a36Sopenharmony_ci .remove_memory = ati_remove_memory, 43062306a36Sopenharmony_ci .alloc_by_type = agp_generic_alloc_by_type, 43162306a36Sopenharmony_ci .free_by_type = agp_generic_free_by_type, 43262306a36Sopenharmony_ci .agp_alloc_page = agp_generic_alloc_page, 43362306a36Sopenharmony_ci .agp_alloc_pages = agp_generic_alloc_pages, 43462306a36Sopenharmony_ci .agp_destroy_page = agp_generic_destroy_page, 43562306a36Sopenharmony_ci .agp_destroy_pages = agp_generic_destroy_pages, 43662306a36Sopenharmony_ci .agp_type_to_mask_type = agp_generic_type_to_mask_type, 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic struct agp_device_ids ati_agp_device_ids[] = 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci { 44362306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS100, 44462306a36Sopenharmony_ci .chipset_name = "IGP320/M", 44562306a36Sopenharmony_ci }, 44662306a36Sopenharmony_ci { 44762306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS200, 44862306a36Sopenharmony_ci .chipset_name = "IGP330/340/345/350/M", 44962306a36Sopenharmony_ci }, 45062306a36Sopenharmony_ci { 45162306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS200_B, 45262306a36Sopenharmony_ci .chipset_name = "IGP345M", 45362306a36Sopenharmony_ci }, 45462306a36Sopenharmony_ci { 45562306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS250, 45662306a36Sopenharmony_ci .chipset_name = "IGP7000/M", 45762306a36Sopenharmony_ci }, 45862306a36Sopenharmony_ci { 45962306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS300_100, 46062306a36Sopenharmony_ci .chipset_name = "IGP9100/M", 46162306a36Sopenharmony_ci }, 46262306a36Sopenharmony_ci { 46362306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS300_133, 46462306a36Sopenharmony_ci .chipset_name = "IGP9100/M", 46562306a36Sopenharmony_ci }, 46662306a36Sopenharmony_ci { 46762306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS300_166, 46862306a36Sopenharmony_ci .chipset_name = "IGP9100/M", 46962306a36Sopenharmony_ci }, 47062306a36Sopenharmony_ci { 47162306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS300_200, 47262306a36Sopenharmony_ci .chipset_name = "IGP9100/M", 47362306a36Sopenharmony_ci }, 47462306a36Sopenharmony_ci { 47562306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS350_133, 47662306a36Sopenharmony_ci .chipset_name = "IGP9000/M", 47762306a36Sopenharmony_ci }, 47862306a36Sopenharmony_ci { 47962306a36Sopenharmony_ci .device_id = PCI_DEVICE_ID_ATI_RS350_200, 48062306a36Sopenharmony_ci .chipset_name = "IGP9100/M", 48162306a36Sopenharmony_ci }, 48262306a36Sopenharmony_ci { }, /* dummy final entry, always present */ 48362306a36Sopenharmony_ci}; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic int agp_ati_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct agp_device_ids *devs = ati_agp_device_ids; 48862306a36Sopenharmony_ci struct agp_bridge_data *bridge; 48962306a36Sopenharmony_ci u8 cap_ptr; 49062306a36Sopenharmony_ci int j; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); 49362306a36Sopenharmony_ci if (!cap_ptr) 49462306a36Sopenharmony_ci return -ENODEV; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* probe for known chipsets */ 49762306a36Sopenharmony_ci for (j = 0; devs[j].chipset_name; j++) { 49862306a36Sopenharmony_ci if (pdev->device == devs[j].device_id) 49962306a36Sopenharmony_ci goto found; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci dev_err(&pdev->dev, "unsupported Ati chipset [%04x/%04x])\n", 50362306a36Sopenharmony_ci pdev->vendor, pdev->device); 50462306a36Sopenharmony_ci return -ENODEV; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cifound: 50762306a36Sopenharmony_ci bridge = agp_alloc_bridge(); 50862306a36Sopenharmony_ci if (!bridge) 50962306a36Sopenharmony_ci return -ENOMEM; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci bridge->dev = pdev; 51262306a36Sopenharmony_ci bridge->capndx = cap_ptr; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci bridge->driver = &ati_generic_bridge; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci dev_info(&pdev->dev, "Ati %s chipset\n", devs[j].chipset_name); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* Fill in the mode register */ 51962306a36Sopenharmony_ci pci_read_config_dword(pdev, 52062306a36Sopenharmony_ci bridge->capndx+PCI_AGP_STATUS, 52162306a36Sopenharmony_ci &bridge->mode); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci pci_set_drvdata(pdev, bridge); 52462306a36Sopenharmony_ci return agp_add_bridge(bridge); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void agp_ati_remove(struct pci_dev *pdev) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci agp_remove_bridge(bridge); 53262306a36Sopenharmony_ci agp_put_bridge(bridge); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic const struct pci_device_id agp_ati_pci_table[] = { 53662306a36Sopenharmony_ci { 53762306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 53862306a36Sopenharmony_ci .class_mask = ~0, 53962306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_ATI, 54062306a36Sopenharmony_ci .device = PCI_ANY_ID, 54162306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 54262306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 54362306a36Sopenharmony_ci }, 54462306a36Sopenharmony_ci { } 54562306a36Sopenharmony_ci}; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, agp_ati_pci_table); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(agp_ati_pm_ops, NULL, agp_ati_resume); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic struct pci_driver agp_ati_pci_driver = { 55262306a36Sopenharmony_ci .name = "agpgart-ati", 55362306a36Sopenharmony_ci .id_table = agp_ati_pci_table, 55462306a36Sopenharmony_ci .probe = agp_ati_probe, 55562306a36Sopenharmony_ci .remove = agp_ati_remove, 55662306a36Sopenharmony_ci .driver.pm = &agp_ati_pm_ops, 55762306a36Sopenharmony_ci}; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic int __init agp_ati_init(void) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci if (agp_off) 56262306a36Sopenharmony_ci return -EINVAL; 56362306a36Sopenharmony_ci return pci_register_driver(&agp_ati_pci_driver); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic void __exit agp_ati_cleanup(void) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci pci_unregister_driver(&agp_ati_pci_driver); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cimodule_init(agp_ati_init); 57262306a36Sopenharmony_cimodule_exit(agp_ati_cleanup); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ciMODULE_AUTHOR("Dave Jones"); 57562306a36Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 57662306a36Sopenharmony_ci 577