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 21 static 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 43 static 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 53 static 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 70 static 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 #if 0 92 if (agp_bridge->type == ALI_M1541) { 93 u32 nlvm_addr = 0; 94 95 switch (current_size->size_value) { 96 case 0: break; 97 case 1: nlvm_addr = 0x100000;break; 98 case 2: nlvm_addr = 0x200000;break; 99 case 3: nlvm_addr = 0x400000;break; 100 case 4: nlvm_addr = 0x800000;break; 101 case 6: nlvm_addr = 0x1000000;break; 102 case 7: nlvm_addr = 0x2000000;break; 103 case 8: nlvm_addr = 0x4000000;break; 104 case 9: nlvm_addr = 0x8000000;break; 105 case 10: nlvm_addr = 0x10000000;break; 106 default: break; 107 } 108 nlvm_addr--; 109 nlvm_addr&=0xfff00000; 110 111 nlvm_addr+= agp_bridge->gart_bus_addr; 112 nlvm_addr|=(agp_bridge->gart_bus_addr>>12); 113 printk(KERN_INFO PFX "nlvm top &base = %8x\n",nlvm_addr); 114 } 115 #endif 116 117 pci_read_config_dword(agp_bridge->dev, ALI_TLBCTRL, &temp); 118 temp &= 0xffffff7f; //enable TLB 119 pci_write_config_dword(agp_bridge->dev, ALI_TLBCTRL, temp); 120 121 return 0; 122 } 123 124 125 static void m1541_cache_flush(void) 126 { 127 int i, page_count; 128 u32 temp; 129 130 global_cache_flush(); 131 132 page_count = 1 << A_SIZE_32(agp_bridge->current_size)->page_order; 133 for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) { 134 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 135 &temp); 136 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 137 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | 138 (agp_bridge->gatt_bus_addr + i)) | 139 ALI_CACHE_FLUSH_EN)); 140 } 141 } 142 143 static void *m1541_alloc_page(struct agp_bridge_data *bridge) 144 { 145 void *addr = agp_generic_alloc_page(agp_bridge); 146 u32 temp; 147 148 if (!addr) 149 return NULL; 150 151 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); 152 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 153 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | 154 virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN )); 155 return addr; 156 } 157 158 static void ali_destroy_page(void * addr) 159 { 160 if (addr) { 161 global_cache_flush(); /* is this really needed? --hch */ 162 agp_generic_destroy_page(addr); 163 } 164 } 165 166 static void m1541_destroy_page(void * addr) 167 { 168 u32 temp; 169 170 if (addr == NULL) 171 return; 172 173 global_cache_flush(); 174 175 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); 176 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 177 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | 178 virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN)); 179 agp_generic_destroy_page(addr); 180 } 181 182 183 /* Setup function */ 184 185 static struct aper_size_info_32 ali_generic_sizes[7] = 186 { 187 {256, 65536, 6, 10}, 188 {128, 32768, 5, 9}, 189 {64, 16384, 4, 8}, 190 {32, 8192, 3, 7}, 191 {16, 4096, 2, 6}, 192 {8, 2048, 1, 4}, 193 {4, 1024, 0, 3} 194 }; 195 196 static struct agp_bridge_driver ali_generic_bridge = { 197 .owner = THIS_MODULE, 198 .aperture_sizes = ali_generic_sizes, 199 .size_type = U32_APER_SIZE, 200 .num_aperture_sizes = 7, 201 .configure = ali_configure, 202 .fetch_size = ali_fetch_size, 203 .cleanup = ali_cleanup, 204 .tlb_flush = ali_tlbflush, 205 .mask_memory = agp_generic_mask_memory, 206 .masks = NULL, 207 .agp_enable = agp_generic_enable, 208 .cache_flush = global_cache_flush, 209 .create_gatt_table = agp_generic_create_gatt_table, 210 .free_gatt_table = agp_generic_free_gatt_table, 211 .insert_memory = agp_generic_insert_memory, 212 .remove_memory = agp_generic_remove_memory, 213 .alloc_by_type = agp_generic_alloc_by_type, 214 .free_by_type = agp_generic_free_by_type, 215 .agp_alloc_page = agp_generic_alloc_page, 216 .agp_destroy_page = ali_destroy_page, 217 }; 218 219 static struct agp_bridge_driver ali_m1541_bridge = { 220 .owner = THIS_MODULE, 221 .aperture_sizes = ali_generic_sizes, 222 .size_type = U32_APER_SIZE, 223 .num_aperture_sizes = 7, 224 .configure = ali_configure, 225 .fetch_size = ali_fetch_size, 226 .cleanup = ali_cleanup, 227 .tlb_flush = ali_tlbflush, 228 .mask_memory = agp_generic_mask_memory, 229 .masks = NULL, 230 .agp_enable = agp_generic_enable, 231 .cache_flush = m1541_cache_flush, 232 .create_gatt_table = agp_generic_create_gatt_table, 233 .free_gatt_table = agp_generic_free_gatt_table, 234 .insert_memory = agp_generic_insert_memory, 235 .remove_memory = agp_generic_remove_memory, 236 .alloc_by_type = agp_generic_alloc_by_type, 237 .free_by_type = agp_generic_free_by_type, 238 .agp_alloc_page = m1541_alloc_page, 239 .agp_destroy_page = m1541_destroy_page, 240 }; 241 242 243 static struct agp_device_ids ali_agp_device_ids[] __devinitdata = 244 { 245 { 246 .device_id = PCI_DEVICE_ID_AL_M1541, 247 .chipset_name = "M1541", 248 }, 249 { 250 .device_id = PCI_DEVICE_ID_AL_M1621, 251 .chipset_name = "M1621", 252 }, 253 { 254 .device_id = PCI_DEVICE_ID_AL_M1631, 255 .chipset_name = "M1631", 256 }, 257 { 258 .device_id = PCI_DEVICE_ID_AL_M1632, 259 .chipset_name = "M1632", 260 }, 261 { 262 .device_id = PCI_DEVICE_ID_AL_M1641, 263 .chipset_name = "M1641", 264 }, 265 { 266 .device_id = PCI_DEVICE_ID_AL_M1644, 267 .chipset_name = "M1644", 268 }, 269 { 270 .device_id = PCI_DEVICE_ID_AL_M1647, 271 .chipset_name = "M1647", 272 }, 273 { 274 .device_id = PCI_DEVICE_ID_AL_M1651, 275 .chipset_name = "M1651", 276 }, 277 { 278 .device_id = PCI_DEVICE_ID_AL_M1671, 279 .chipset_name = "M1671", 280 }, 281 { 282 .device_id = PCI_DEVICE_ID_AL_M1681, 283 .chipset_name = "M1681", 284 }, 285 { 286 .device_id = PCI_DEVICE_ID_AL_M1683, 287 .chipset_name = "M1683", 288 }, 289 290 { }, /* dummy final entry, always present */ 291 }; 292 293 static int __devinit agp_ali_probe(struct pci_dev *pdev, 294 const struct pci_device_id *ent) 295 { 296 struct agp_device_ids *devs = ali_agp_device_ids; 297 struct agp_bridge_data *bridge; 298 u8 hidden_1621_id, cap_ptr; 299 int j; 300 301 cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); 302 if (!cap_ptr) 303 return -ENODEV; 304 305 /* probe for known chipsets */ 306 for (j = 0; devs[j].chipset_name; j++) { 307 if (pdev->device == devs[j].device_id) 308 goto found; 309 } 310 311 printk(KERN_ERR PFX "Unsupported ALi chipset (device id: %04x)\n", 312 pdev->device); 313 return -ENODEV; 314 315 316 found: 317 bridge = agp_alloc_bridge(); 318 if (!bridge) 319 return -ENOMEM; 320 321 bridge->dev = pdev; 322 bridge->capndx = cap_ptr; 323 324 switch (pdev->device) { 325 case PCI_DEVICE_ID_AL_M1541: 326 bridge->driver = &ali_m1541_bridge; 327 break; 328 case PCI_DEVICE_ID_AL_M1621: 329 pci_read_config_byte(pdev, 0xFB, &hidden_1621_id); 330 switch (hidden_1621_id) { 331 case 0x31: 332 devs[j].chipset_name = "M1631"; 333 break; 334 case 0x32: 335 devs[j].chipset_name = "M1632"; 336 break; 337 case 0x41: 338 devs[j].chipset_name = "M1641"; 339 break; 340 case 0x43: 341 devs[j].chipset_name = "M????"; 342 break; 343 case 0x47: 344 devs[j].chipset_name = "M1647"; 345 break; 346 case 0x51: 347 devs[j].chipset_name = "M1651"; 348 break; 349 default: 350 break; 351 } 352 /*FALLTHROUGH*/ 353 default: 354 bridge->driver = &ali_generic_bridge; 355 } 356 357 printk(KERN_INFO PFX "Detected ALi %s chipset\n", 358 devs[j].chipset_name); 359 360 /* Fill in the mode register */ 361 pci_read_config_dword(pdev, 362 bridge->capndx+PCI_AGP_STATUS, 363 &bridge->mode); 364 365 pci_set_drvdata(pdev, bridge); 366 return agp_add_bridge(bridge); 367 } 368 369 static void __devexit agp_ali_remove(struct pci_dev *pdev) 370 { 371 struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 372 373 agp_remove_bridge(bridge); 374 agp_put_bridge(bridge); 375 } 376 377 static struct pci_device_id agp_ali_pci_table[] = { 378 { 379 .class = (PCI_CLASS_BRIDGE_HOST << 8), 380 .class_mask = ~0, 381 .vendor = PCI_VENDOR_ID_AL, 382 .device = PCI_ANY_ID, 383 .subvendor = PCI_ANY_ID, 384 .subdevice = PCI_ANY_ID, 385 }, 386 { } 387 }; 388 389 MODULE_DEVICE_TABLE(pci, agp_ali_pci_table); 390 391 static struct pci_driver agp_ali_pci_driver = { 392 .name = "agpgart-ali", 393 .id_table = agp_ali_pci_table, 394 .probe = agp_ali_probe, 395 .remove = agp_ali_remove, 396 }; 397 398 static int __init agp_ali_init(void) 399 { 400 if (agp_off) 401 return -EINVAL; 402 return pci_register_driver(&agp_ali_pci_driver); 403 } 404 405 static void __exit agp_ali_cleanup(void) 406 { 407 pci_unregister_driver(&agp_ali_pci_driver); 408 } 409 410 module_init(agp_ali_init); 411 module_exit(agp_ali_cleanup); 412 413 MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>"); 414 MODULE_LICENSE("GPL and additional rights"); 415 416