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