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