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