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 21static 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 43static 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 53static 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 70static 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 agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, 89 AGP_APERTURE_BAR); 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 dev_info(&agp_bridge->dev->dev, "nlvm top &base = %8x\n", 114 nlvm_addr); 115 } 116#endif 117 118 pci_read_config_dword(agp_bridge->dev, ALI_TLBCTRL, &temp); 119 temp &= 0xffffff7f; //enable TLB 120 pci_write_config_dword(agp_bridge->dev, ALI_TLBCTRL, temp); 121 122 return 0; 123} 124 125 126static void m1541_cache_flush(void) 127{ 128 int i, page_count; 129 u32 temp; 130 131 global_cache_flush(); 132 133 page_count = 1 << A_SIZE_32(agp_bridge->current_size)->page_order; 134 for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) { 135 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 136 &temp); 137 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 138 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | 139 (agp_bridge->gatt_bus_addr + i)) | 140 ALI_CACHE_FLUSH_EN)); 141 } 142} 143 144static struct page *m1541_alloc_page(struct agp_bridge_data *bridge) 145{ 146 struct page *page = agp_generic_alloc_page(agp_bridge); 147 u32 temp; 148 149 if (!page) 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 page_to_phys(page)) | ALI_CACHE_FLUSH_EN )); 156 return page; 157} 158 159static void ali_destroy_page(struct page *page, int flags) 160{ 161 if (page) { 162 if (flags & AGP_PAGE_DESTROY_UNMAP) { 163 global_cache_flush(); /* is this really needed? --hch */ 164 agp_generic_destroy_page(page, flags); 165 } else 166 agp_generic_destroy_page(page, flags); 167 } 168} 169 170static void m1541_destroy_page(struct page *page, int flags) 171{ 172 u32 temp; 173 174 if (page == NULL) 175 return; 176 177 if (flags & AGP_PAGE_DESTROY_UNMAP) { 178 global_cache_flush(); 179 180 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); 181 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 182 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | 183 page_to_phys(page)) | ALI_CACHE_FLUSH_EN)); 184 } 185 agp_generic_destroy_page(page, flags); 186} 187 188 189/* Setup function */ 190 191static const struct aper_size_info_32 ali_generic_sizes[7] = 192{ 193 {256, 65536, 6, 10}, 194 {128, 32768, 5, 9}, 195 {64, 16384, 4, 8}, 196 {32, 8192, 3, 7}, 197 {16, 4096, 2, 6}, 198 {8, 2048, 1, 4}, 199 {4, 1024, 0, 3} 200}; 201 202static const struct agp_bridge_driver ali_generic_bridge = { 203 .owner = THIS_MODULE, 204 .aperture_sizes = ali_generic_sizes, 205 .size_type = U32_APER_SIZE, 206 .num_aperture_sizes = 7, 207 .needs_scratch_page = true, 208 .configure = ali_configure, 209 .fetch_size = ali_fetch_size, 210 .cleanup = ali_cleanup, 211 .tlb_flush = ali_tlbflush, 212 .mask_memory = agp_generic_mask_memory, 213 .masks = NULL, 214 .agp_enable = agp_generic_enable, 215 .cache_flush = global_cache_flush, 216 .create_gatt_table = agp_generic_create_gatt_table, 217 .free_gatt_table = agp_generic_free_gatt_table, 218 .insert_memory = agp_generic_insert_memory, 219 .remove_memory = agp_generic_remove_memory, 220 .alloc_by_type = agp_generic_alloc_by_type, 221 .free_by_type = agp_generic_free_by_type, 222 .agp_alloc_page = agp_generic_alloc_page, 223 .agp_destroy_page = ali_destroy_page, 224 .agp_type_to_mask_type = agp_generic_type_to_mask_type, 225}; 226 227static const struct agp_bridge_driver ali_m1541_bridge = { 228 .owner = THIS_MODULE, 229 .aperture_sizes = ali_generic_sizes, 230 .size_type = U32_APER_SIZE, 231 .num_aperture_sizes = 7, 232 .configure = ali_configure, 233 .fetch_size = ali_fetch_size, 234 .cleanup = ali_cleanup, 235 .tlb_flush = ali_tlbflush, 236 .mask_memory = agp_generic_mask_memory, 237 .masks = NULL, 238 .agp_enable = agp_generic_enable, 239 .cache_flush = m1541_cache_flush, 240 .create_gatt_table = agp_generic_create_gatt_table, 241 .free_gatt_table = agp_generic_free_gatt_table, 242 .insert_memory = agp_generic_insert_memory, 243 .remove_memory = agp_generic_remove_memory, 244 .alloc_by_type = agp_generic_alloc_by_type, 245 .free_by_type = agp_generic_free_by_type, 246 .agp_alloc_page = m1541_alloc_page, 247 .agp_destroy_page = m1541_destroy_page, 248 .agp_type_to_mask_type = agp_generic_type_to_mask_type, 249}; 250 251 252static struct agp_device_ids ali_agp_device_ids[] = 253{ 254 { 255 .device_id = PCI_DEVICE_ID_AL_M1541, 256 .chipset_name = "M1541", 257 }, 258 { 259 .device_id = PCI_DEVICE_ID_AL_M1621, 260 .chipset_name = "M1621", 261 }, 262 { 263 .device_id = PCI_DEVICE_ID_AL_M1631, 264 .chipset_name = "M1631", 265 }, 266 { 267 .device_id = PCI_DEVICE_ID_AL_M1632, 268 .chipset_name = "M1632", 269 }, 270 { 271 .device_id = PCI_DEVICE_ID_AL_M1641, 272 .chipset_name = "M1641", 273 }, 274 { 275 .device_id = PCI_DEVICE_ID_AL_M1644, 276 .chipset_name = "M1644", 277 }, 278 { 279 .device_id = PCI_DEVICE_ID_AL_M1647, 280 .chipset_name = "M1647", 281 }, 282 { 283 .device_id = PCI_DEVICE_ID_AL_M1651, 284 .chipset_name = "M1651", 285 }, 286 { 287 .device_id = PCI_DEVICE_ID_AL_M1671, 288 .chipset_name = "M1671", 289 }, 290 { 291 .device_id = PCI_DEVICE_ID_AL_M1681, 292 .chipset_name = "M1681", 293 }, 294 { 295 .device_id = PCI_DEVICE_ID_AL_M1683, 296 .chipset_name = "M1683", 297 }, 298 299 { }, /* dummy final entry, always present */ 300}; 301 302static int agp_ali_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 303{ 304 struct agp_device_ids *devs = ali_agp_device_ids; 305 struct agp_bridge_data *bridge; 306 u8 hidden_1621_id, cap_ptr; 307 int j; 308 309 cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); 310 if (!cap_ptr) 311 return -ENODEV; 312 313 /* probe for known chipsets */ 314 for (j = 0; devs[j].chipset_name; j++) { 315 if (pdev->device == devs[j].device_id) 316 goto found; 317 } 318 319 dev_err(&pdev->dev, "unsupported ALi chipset [%04x/%04x])\n", 320 pdev->vendor, pdev->device); 321 return -ENODEV; 322 323 324found: 325 bridge = agp_alloc_bridge(); 326 if (!bridge) 327 return -ENOMEM; 328 329 bridge->dev = pdev; 330 bridge->capndx = cap_ptr; 331 332 switch (pdev->device) { 333 case PCI_DEVICE_ID_AL_M1541: 334 bridge->driver = &ali_m1541_bridge; 335 break; 336 case PCI_DEVICE_ID_AL_M1621: 337 pci_read_config_byte(pdev, 0xFB, &hidden_1621_id); 338 switch (hidden_1621_id) { 339 case 0x31: 340 devs[j].chipset_name = "M1631"; 341 break; 342 case 0x32: 343 devs[j].chipset_name = "M1632"; 344 break; 345 case 0x41: 346 devs[j].chipset_name = "M1641"; 347 break; 348 case 0x43: 349 devs[j].chipset_name = "M1621"; 350 break; 351 case 0x47: 352 devs[j].chipset_name = "M1647"; 353 break; 354 case 0x51: 355 devs[j].chipset_name = "M1651"; 356 break; 357 default: 358 break; 359 } 360 /*FALLTHROUGH*/ 361 default: 362 bridge->driver = &ali_generic_bridge; 363 } 364 365 dev_info(&pdev->dev, "ALi %s chipset\n", 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 376static void 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 384static 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 396MODULE_DEVICE_TABLE(pci, agp_ali_pci_table); 397 398static 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 405static 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 412static void __exit agp_ali_cleanup(void) 413{ 414 pci_unregister_driver(&agp_ali_pci_driver); 415} 416 417module_init(agp_ali_init); 418module_exit(agp_ali_cleanup); 419 420MODULE_AUTHOR("Dave Jones"); 421MODULE_LICENSE("GPL and additional rights"); 422 423