1/* 2 * ALi AGPGART routines. 3 */ 4 5#include <linux/types.h> 6#include <linux/module.h> 7#include <linux/pci.h> 8#include <linux/init.h> 9#include <linux/agp_backend.h> 10#include <asm/page.h> /* PAGE_SIZE */ 11#include "agp.h" 12 13#define ALI_AGPCTRL 0xb8 14#define ALI_ATTBASE 0xbc 15#define ALI_TLBCTRL 0xc0 16#define ALI_TAGCTRL 0xc4 17#define ALI_CACHE_FLUSH_CTRL 0xD0 18#define ALI_CACHE_FLUSH_ADDR_MASK 0xFFFFF000 19#define ALI_CACHE_FLUSH_EN 0x100 20 21static int ali_fetch_size(void) 22{ 23 int i; 24 u32 temp; 25 struct aper_size_info_32 *values; 26 27 pci_read_config_dword(agp_bridge->dev, ALI_ATTBASE, &temp); 28 temp &= ~(0xfffffff0); 29 values = A_SIZE_32(agp_bridge->driver->aperture_sizes); 30 31 for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { 32 if (temp == values[i].size_value) { 33 agp_bridge->previous_size = 34 agp_bridge->current_size = (void *) (values + i); 35 agp_bridge->aperture_size_idx = i; 36 return values[i].size; 37 } 38 } 39 40 return 0; 41} 42 43static void ali_tlbflush(struct agp_memory *mem) 44{ 45 u32 temp; 46 47 pci_read_config_dword(agp_bridge->dev, ALI_TLBCTRL, &temp); 48 temp &= 0xfffffff0; 49 temp |= (1<<0 | 1<<1); 50 pci_write_config_dword(agp_bridge->dev, ALI_TAGCTRL, temp); 51} 52 53static void ali_cleanup(void) 54{ 55 struct aper_size_info_32 *previous_size; 56 u32 temp; 57 58 previous_size = A_SIZE_32(agp_bridge->previous_size); 59 60 pci_read_config_dword(agp_bridge->dev, ALI_TLBCTRL, &temp); 61// clear tag 62 pci_write_config_dword(agp_bridge->dev, ALI_TAGCTRL, 63 ((temp & 0xffffff00) | 0x00000001|0x00000002)); 64 65 pci_read_config_dword(agp_bridge->dev, ALI_ATTBASE, &temp); 66 pci_write_config_dword(agp_bridge->dev, ALI_ATTBASE, 67 ((temp & 0x00000ff0) | previous_size->size_value)); 68} 69 70static int ali_configure(void) 71{ 72 u32 temp; 73 struct aper_size_info_32 *current_size; 74 75 current_size = A_SIZE_32(agp_bridge->current_size); 76 77 /* aperture size and gatt addr */ 78 pci_read_config_dword(agp_bridge->dev, ALI_ATTBASE, &temp); 79 temp = (((temp & 0x00000ff0) | (agp_bridge->gatt_bus_addr & 0xfffff000)) 80 | (current_size->size_value & 0xf)); 81 pci_write_config_dword(agp_bridge->dev, ALI_ATTBASE, temp); 82 83 /* tlb control */ 84 pci_read_config_dword(agp_bridge->dev, ALI_TLBCTRL, &temp); 85 pci_write_config_dword(agp_bridge->dev, ALI_TLBCTRL, ((temp & 0xffffff00) | 0x00000010)); 86 87 /* address to map to */ 88 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); 89 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); 90 91 92 pci_read_config_dword(agp_bridge->dev, ALI_TLBCTRL, &temp); 93 temp &= 0xffffff7f; //enable TLB 94 pci_write_config_dword(agp_bridge->dev, ALI_TLBCTRL, temp); 95 96 return 0; 97} 98 99 100static void m1541_cache_flush(void) 101{ 102 int i, page_count; 103 u32 temp; 104 105 global_cache_flush(); 106 107 page_count = 1 << A_SIZE_32(agp_bridge->current_size)->page_order; 108 for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) { 109 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 110 &temp); 111 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 112 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | 113 (agp_bridge->gatt_bus_addr + i)) | 114 ALI_CACHE_FLUSH_EN)); 115 } 116} 117 118static struct page *m1541_alloc_page(struct agp_bridge_data *bridge) 119{ 120 struct page *page = agp_generic_alloc_page(agp_bridge); 121 u32 temp; 122 123 if (!page) 124 return NULL; 125 126 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); 127 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 128 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | 129 page_to_phys(page)) | ALI_CACHE_FLUSH_EN )); 130 return page; 131} 132 133static void ali_destroy_page(struct page *page, int flags) 134{ 135 if (page) { 136 if (flags & AGP_PAGE_DESTROY_UNMAP) { 137 global_cache_flush(); /* is this really needed? --hch */ 138 agp_generic_destroy_page(page, flags); 139 } else 140 agp_generic_destroy_page(page, flags); 141 } 142} 143 144static void m1541_destroy_page(struct page *page, int flags) 145{ 146 u32 temp; 147 148 if (page == NULL) 149 return; 150 151 if (flags & AGP_PAGE_DESTROY_UNMAP) { 152 global_cache_flush(); 153 154 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); 155 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 156 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | 157 page_to_phys(page)) | ALI_CACHE_FLUSH_EN)); 158 } 159 agp_generic_destroy_page(page, flags); 160} 161 162 163/* Setup function */ 164 165static const struct aper_size_info_32 ali_generic_sizes[7] = 166{ 167 {256, 65536, 6, 10}, 168 {128, 32768, 5, 9}, 169 {64, 16384, 4, 8}, 170 {32, 8192, 3, 7}, 171 {16, 4096, 2, 6}, 172 {8, 2048, 1, 4}, 173 {4, 1024, 0, 3} 174}; 175 176static const struct agp_bridge_driver ali_generic_bridge = { 177 .owner = THIS_MODULE, 178 .aperture_sizes = ali_generic_sizes, 179 .size_type = U32_APER_SIZE, 180 .num_aperture_sizes = 7, 181 .needs_scratch_page = true, 182 .configure = ali_configure, 183 .fetch_size = ali_fetch_size, 184 .cleanup = ali_cleanup, 185 .tlb_flush = ali_tlbflush, 186 .mask_memory = agp_generic_mask_memory, 187 .masks = NULL, 188 .agp_enable = agp_generic_enable, 189 .cache_flush = global_cache_flush, 190 .create_gatt_table = agp_generic_create_gatt_table, 191 .free_gatt_table = agp_generic_free_gatt_table, 192 .insert_memory = agp_generic_insert_memory, 193 .remove_memory = agp_generic_remove_memory, 194 .alloc_by_type = agp_generic_alloc_by_type, 195 .free_by_type = agp_generic_free_by_type, 196 .agp_alloc_page = agp_generic_alloc_page, 197 .agp_destroy_page = ali_destroy_page, 198 .agp_type_to_mask_type = agp_generic_type_to_mask_type, 199}; 200 201static const struct agp_bridge_driver ali_m1541_bridge = { 202 .owner = THIS_MODULE, 203 .aperture_sizes = ali_generic_sizes, 204 .size_type = U32_APER_SIZE, 205 .num_aperture_sizes = 7, 206 .configure = ali_configure, 207 .fetch_size = ali_fetch_size, 208 .cleanup = ali_cleanup, 209 .tlb_flush = ali_tlbflush, 210 .mask_memory = agp_generic_mask_memory, 211 .masks = NULL, 212 .agp_enable = agp_generic_enable, 213 .cache_flush = m1541_cache_flush, 214 .create_gatt_table = agp_generic_create_gatt_table, 215 .free_gatt_table = agp_generic_free_gatt_table, 216 .insert_memory = agp_generic_insert_memory, 217 .remove_memory = agp_generic_remove_memory, 218 .alloc_by_type = agp_generic_alloc_by_type, 219 .free_by_type = agp_generic_free_by_type, 220 .agp_alloc_page = m1541_alloc_page, 221 .agp_destroy_page = m1541_destroy_page, 222 .agp_type_to_mask_type = agp_generic_type_to_mask_type, 223}; 224 225 226static struct agp_device_ids ali_agp_device_ids[] __devinitdata = 227{ 228 { 229 .device_id = PCI_DEVICE_ID_AL_M1541, 230 .chipset_name = "M1541", 231 }, 232 { 233 .device_id = PCI_DEVICE_ID_AL_M1621, 234 .chipset_name = "M1621", 235 }, 236 { 237 .device_id = PCI_DEVICE_ID_AL_M1631, 238 .chipset_name = "M1631", 239 }, 240 { 241 .device_id = PCI_DEVICE_ID_AL_M1632, 242 .chipset_name = "M1632", 243 }, 244 { 245 .device_id = PCI_DEVICE_ID_AL_M1641, 246 .chipset_name = "M1641", 247 }, 248 { 249 .device_id = PCI_DEVICE_ID_AL_M1644, 250 .chipset_name = "M1644", 251 }, 252 { 253 .device_id = PCI_DEVICE_ID_AL_M1647, 254 .chipset_name = "M1647", 255 }, 256 { 257 .device_id = PCI_DEVICE_ID_AL_M1651, 258 .chipset_name = "M1651", 259 }, 260 { 261 .device_id = PCI_DEVICE_ID_AL_M1671, 262 .chipset_name = "M1671", 263 }, 264 { 265 .device_id = PCI_DEVICE_ID_AL_M1681, 266 .chipset_name = "M1681", 267 }, 268 { 269 .device_id = PCI_DEVICE_ID_AL_M1683, 270 .chipset_name = "M1683", 271 }, 272 273 { }, /* dummy final entry, always present */ 274}; 275 276static int __devinit agp_ali_probe(struct pci_dev *pdev, 277 const struct pci_device_id *ent) 278{ 279 struct agp_device_ids *devs = ali_agp_device_ids; 280 struct agp_bridge_data *bridge; 281 u8 hidden_1621_id, cap_ptr; 282 int j; 283 284 cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); 285 if (!cap_ptr) 286 return -ENODEV; 287 288 /* probe for known chipsets */ 289 for (j = 0; devs[j].chipset_name; j++) { 290 if (pdev->device == devs[j].device_id) 291 goto found; 292 } 293 294 dev_err(&pdev->dev, "unsupported ALi chipset [%04x/%04x])\n", 295 pdev->vendor, pdev->device); 296 return -ENODEV; 297 298 299found: 300 bridge = agp_alloc_bridge(); 301 if (!bridge) 302 return -ENOMEM; 303 304 bridge->dev = pdev; 305 bridge->capndx = cap_ptr; 306 307 switch (pdev->device) { 308 case PCI_DEVICE_ID_AL_M1541: 309 bridge->driver = &ali_m1541_bridge; 310 break; 311 case PCI_DEVICE_ID_AL_M1621: 312 pci_read_config_byte(pdev, 0xFB, &hidden_1621_id); 313 switch (hidden_1621_id) { 314 case 0x31: 315 devs[j].chipset_name = "M1631"; 316 break; 317 case 0x32: 318 devs[j].chipset_name = "M1632"; 319 break; 320 case 0x41: 321 devs[j].chipset_name = "M1641"; 322 break; 323 case 0x43: 324 devs[j].chipset_name = "M1621"; 325 break; 326 case 0x47: 327 devs[j].chipset_name = "M1647"; 328 break; 329 case 0x51: 330 devs[j].chipset_name = "M1651"; 331 break; 332 default: 333 break; 334 } 335 /*FALLTHROUGH*/ 336 default: 337 bridge->driver = &ali_generic_bridge; 338 } 339 340 dev_info(&pdev->dev, "ALi %s chipset\n", devs[j].chipset_name); 341 342 /* Fill in the mode register */ 343 pci_read_config_dword(pdev, 344 bridge->capndx+PCI_AGP_STATUS, 345 &bridge->mode); 346 347 pci_set_drvdata(pdev, bridge); 348 return agp_add_bridge(bridge); 349} 350 351static void __devexit agp_ali_remove(struct pci_dev *pdev) 352{ 353 struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 354 355 agp_remove_bridge(bridge); 356 agp_put_bridge(bridge); 357} 358 359static struct pci_device_id agp_ali_pci_table[] = { 360 { 361 .class = (PCI_CLASS_BRIDGE_HOST << 8), 362 .class_mask = ~0, 363 .vendor = PCI_VENDOR_ID_AL, 364 .device = PCI_ANY_ID, 365 .subvendor = PCI_ANY_ID, 366 .subdevice = PCI_ANY_ID, 367 }, 368 { } 369}; 370 371MODULE_DEVICE_TABLE(pci, agp_ali_pci_table); 372 373static struct pci_driver agp_ali_pci_driver = { 374 .name = "agpgart-ali", 375 .id_table = agp_ali_pci_table, 376 .probe = agp_ali_probe, 377 .remove = agp_ali_remove, 378}; 379 380static int __init agp_ali_init(void) 381{ 382 if (agp_off) 383 return -EINVAL; 384 return pci_register_driver(&agp_ali_pci_driver); 385} 386 387static void __exit agp_ali_cleanup(void) 388{ 389 pci_unregister_driver(&agp_ali_pci_driver); 390} 391 392module_init(agp_ali_init); 393module_exit(agp_ali_cleanup); 394 395MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); 396MODULE_LICENSE("GPL and additional rights"); 397