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