1 /* 2 * SiS AGPGART routines. 3 */ 4 5 #include <linux/module.h> 6 #include <linux/pci.h> 7 #include <linux/init.h> 8 #include <linux/agp_backend.h> 9 #include <linux/delay.h> 10 #include "agp.h" 11 12 #define SIS_ATTBASE 0x90 13 #define SIS_APSIZE 0x94 14 #define SIS_TLBCNTRL 0x97 15 #define SIS_TLBFLUSH 0x98 16 17 #define PCI_DEVICE_ID_SI_662 0x0662 18 #define PCI_DEVICE_ID_SI_671 0x0671 19 20 static int __devinitdata agp_sis_force_delay = 0; 21 static int __devinitdata agp_sis_agp_spec = -1; 22 23 static int sis_fetch_size(void) 24 { 25 u8 temp_size; 26 int i; 27 struct aper_size_info_8 *values; 28 29 pci_read_config_byte(agp_bridge->dev, SIS_APSIZE, &temp_size); 30 values = A_SIZE_8(agp_bridge->driver->aperture_sizes); 31 for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { 32 if ((temp_size == values[i].size_value) || 33 ((temp_size & ~(0x07)) == 34 (values[i].size_value & ~(0x07)))) { 35 agp_bridge->previous_size = 36 agp_bridge->current_size = (void *) (values + i); 37 38 agp_bridge->aperture_size_idx = i; 39 return values[i].size; 40 } 41 } 42 43 return 0; 44 } 45 46 static void sis_tlbflush(struct agp_memory *mem) 47 { 48 pci_write_config_byte(agp_bridge->dev, SIS_TLBFLUSH, 0x02); 49 } 50 51 static int sis_configure(void) 52 { 53 u32 temp; 54 struct aper_size_info_8 *current_size; 55 56 current_size = A_SIZE_8(agp_bridge->current_size); 57 pci_write_config_byte(agp_bridge->dev, SIS_TLBCNTRL, 0x05); 58 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); 59 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); 60 pci_write_config_dword(agp_bridge->dev, SIS_ATTBASE, 61 agp_bridge->gatt_bus_addr); 62 pci_write_config_byte(agp_bridge->dev, SIS_APSIZE, 63 current_size->size_value); 64 return 0; 65 } 66 67 static void sis_cleanup(void) 68 { 69 struct aper_size_info_8 *previous_size; 70 71 previous_size = A_SIZE_8(agp_bridge->previous_size); 72 pci_write_config_byte(agp_bridge->dev, SIS_APSIZE, 73 (previous_size->size_value & ~(0x03))); 74 } 75 76 static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode) 77 { 78 struct pci_dev *device = NULL; 79 u32 command; 80 int rate; 81 82 dev_info(&agp_bridge->dev->dev, "AGP %d.%d bridge\n", 83 agp_bridge->major_version, agp_bridge->minor_version); 84 85 pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + PCI_AGP_STATUS, &command); 86 command = agp_collect_device_status(bridge, mode, command); 87 command |= AGPSTAT_AGP_ENABLE; 88 rate = (command & 0x7) << 2; 89 90 for_each_pci_dev(device) { 91 u8 agp = pci_find_capability(device, PCI_CAP_ID_AGP); 92 if (!agp) 93 continue; 94 95 dev_info(&agp_bridge->dev->dev, "putting AGP V3 device at %s into %dx mode\n", 96 pci_name(device), rate); 97 98 pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command); 99 100 /* 101 * Weird: on some sis chipsets any rate change in the target 102 * command register triggers a 5ms screwup during which the master 103 * cannot be configured 104 */ 105 if (device->device == bridge->dev->device) { 106 dev_info(&agp_bridge->dev->dev, "SiS delay workaround: giving bridge time to recover\n"); 107 msleep(10); 108 } 109 } 110 } 111 112 static const struct aper_size_info_8 sis_generic_sizes[7] = 113 { 114 {256, 65536, 6, 99}, 115 {128, 32768, 5, 83}, 116 {64, 16384, 4, 67}, 117 {32, 8192, 3, 51}, 118 {16, 4096, 2, 35}, 119 {8, 2048, 1, 19}, 120 {4, 1024, 0, 3} 121 }; 122 123 static struct agp_bridge_driver sis_driver = { 124 .owner = THIS_MODULE, 125 .aperture_sizes = sis_generic_sizes, 126 .size_type = U8_APER_SIZE, 127 .num_aperture_sizes = 7, 128 .configure = sis_configure, 129 .fetch_size = sis_fetch_size, 130 .cleanup = sis_cleanup, 131 .tlb_flush = sis_tlbflush, 132 .mask_memory = agp_generic_mask_memory, 133 .masks = NULL, 134 .agp_enable = agp_generic_enable, 135 .cache_flush = global_cache_flush, 136 .create_gatt_table = agp_generic_create_gatt_table, 137 .free_gatt_table = agp_generic_free_gatt_table, 138 .insert_memory = agp_generic_insert_memory, 139 .remove_memory = agp_generic_remove_memory, 140 .alloc_by_type = agp_generic_alloc_by_type, 141 .free_by_type = agp_generic_free_by_type, 142 .agp_alloc_page = agp_generic_alloc_page, 143 .agp_destroy_page = agp_generic_destroy_page, 144 .agp_type_to_mask_type = agp_generic_type_to_mask_type, 145 }; 146 147 // chipsets that require the 'delay hack' 148 static int sis_broken_chipsets[] __devinitdata = { 149 PCI_DEVICE_ID_SI_648, 150 PCI_DEVICE_ID_SI_746, 151 0 // terminator 152 }; 153 154 static void __devinit sis_get_driver(struct agp_bridge_data *bridge) 155 { 156 int i; 157 158 for (i=0; sis_broken_chipsets[i]!=0; ++i) 159 if (bridge->dev->device==sis_broken_chipsets[i]) 160 break; 161 162 if (sis_broken_chipsets[i] || agp_sis_force_delay) 163 sis_driver.agp_enable=sis_delayed_enable; 164 165 // sis chipsets that indicate less than agp3.5 166 // are not actually fully agp3 compliant 167 if ((agp_bridge->major_version == 3 && agp_bridge->minor_version >= 5 168 && agp_sis_agp_spec!=0) || agp_sis_agp_spec==1) { 169 sis_driver.aperture_sizes = agp3_generic_sizes; 170 sis_driver.size_type = U16_APER_SIZE; 171 sis_driver.num_aperture_sizes = AGP_GENERIC_SIZES_ENTRIES; 172 sis_driver.configure = agp3_generic_configure; 173 sis_driver.fetch_size = agp3_generic_fetch_size; 174 sis_driver.cleanup = agp3_generic_cleanup; 175 sis_driver.tlb_flush = agp3_generic_tlbflush; 176 } 177 } 178 179 180 static int __devinit agp_sis_probe(struct pci_dev *pdev, 181 const struct pci_device_id *ent) 182 { 183 struct agp_bridge_data *bridge; 184 u8 cap_ptr; 185 186 cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); 187 if (!cap_ptr) 188 return -ENODEV; 189 190 191 dev_info(&pdev->dev, "SiS chipset [%04x/%04x]\n", 192 pdev->vendor, pdev->device); 193 bridge = agp_alloc_bridge(); 194 if (!bridge) 195 return -ENOMEM; 196 197 bridge->driver = &sis_driver; 198 bridge->dev = pdev; 199 bridge->capndx = cap_ptr; 200 201 get_agp_version(bridge); 202 203 /* Fill in the mode register */ 204 pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode); 205 sis_get_driver(bridge); 206 207 pci_set_drvdata(pdev, bridge); 208 return agp_add_bridge(bridge); 209 } 210 211 static void __devexit agp_sis_remove(struct pci_dev *pdev) 212 { 213 struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 214 215 agp_remove_bridge(bridge); 216 agp_put_bridge(bridge); 217 } 218 219 #ifdef CONFIG_PM 220 221 static int agp_sis_suspend(struct pci_dev *pdev, pm_message_t state) 222 { 223 pci_save_state(pdev); 224 pci_set_power_state(pdev, pci_choose_state(pdev, state)); 225 226 return 0; 227 } 228 229 static int agp_sis_resume(struct pci_dev *pdev) 230 { 231 pci_set_power_state(pdev, PCI_D0); 232 pci_restore_state(pdev); 233 234 return sis_driver.configure(); 235 } 236 237 #endif /* CONFIG_PM */ 238 239 static struct pci_device_id agp_sis_pci_table[] = { 240 { 241 .class = (PCI_CLASS_BRIDGE_HOST << 8), 242 .class_mask = ~0, 243 .vendor = PCI_VENDOR_ID_SI, 244 .device = PCI_DEVICE_ID_SI_5591, 245 .subvendor = PCI_ANY_ID, 246 .subdevice = PCI_ANY_ID, 247 }, 248 { 249 .class = (PCI_CLASS_BRIDGE_HOST << 8), 250 .class_mask = ~0, 251 .vendor = PCI_VENDOR_ID_SI, 252 .device = PCI_DEVICE_ID_SI_530, 253 .subvendor = PCI_ANY_ID, 254 .subdevice = PCI_ANY_ID, 255 }, 256 { 257 .class = (PCI_CLASS_BRIDGE_HOST << 8), 258 .class_mask = ~0, 259 .vendor = PCI_VENDOR_ID_SI, 260 .device = PCI_DEVICE_ID_SI_540, 261 .subvendor = PCI_ANY_ID, 262 .subdevice = PCI_ANY_ID, 263 }, 264 { 265 .class = (PCI_CLASS_BRIDGE_HOST << 8), 266 .class_mask = ~0, 267 .vendor = PCI_VENDOR_ID_SI, 268 .device = PCI_DEVICE_ID_SI_550, 269 .subvendor = PCI_ANY_ID, 270 .subdevice = PCI_ANY_ID, 271 }, 272 { 273 .class = (PCI_CLASS_BRIDGE_HOST << 8), 274 .class_mask = ~0, 275 .vendor = PCI_VENDOR_ID_SI, 276 .device = PCI_DEVICE_ID_SI_620, 277 .subvendor = PCI_ANY_ID, 278 .subdevice = PCI_ANY_ID, 279 }, 280 { 281 .class = (PCI_CLASS_BRIDGE_HOST << 8), 282 .class_mask = ~0, 283 .vendor = PCI_VENDOR_ID_SI, 284 .device = PCI_DEVICE_ID_SI_630, 285 .subvendor = PCI_ANY_ID, 286 .subdevice = PCI_ANY_ID, 287 }, 288 { 289 .class = (PCI_CLASS_BRIDGE_HOST << 8), 290 .class_mask = ~0, 291 .vendor = PCI_VENDOR_ID_SI, 292 .device = PCI_DEVICE_ID_SI_635, 293 .subvendor = PCI_ANY_ID, 294 .subdevice = PCI_ANY_ID, 295 }, 296 { 297 .class = (PCI_CLASS_BRIDGE_HOST << 8), 298 .class_mask = ~0, 299 .vendor = PCI_VENDOR_ID_SI, 300 .device = PCI_DEVICE_ID_SI_645, 301 .subvendor = PCI_ANY_ID, 302 .subdevice = PCI_ANY_ID, 303 }, 304 { 305 .class = (PCI_CLASS_BRIDGE_HOST << 8), 306 .class_mask = ~0, 307 .vendor = PCI_VENDOR_ID_SI, 308 .device = PCI_DEVICE_ID_SI_646, 309 .subvendor = PCI_ANY_ID, 310 .subdevice = PCI_ANY_ID, 311 }, 312 { 313 .class = (PCI_CLASS_BRIDGE_HOST << 8), 314 .class_mask = ~0, 315 .vendor = PCI_VENDOR_ID_SI, 316 .device = PCI_DEVICE_ID_SI_648, 317 .subvendor = PCI_ANY_ID, 318 .subdevice = PCI_ANY_ID, 319 }, 320 { 321 .class = (PCI_CLASS_BRIDGE_HOST << 8), 322 .class_mask = ~0, 323 .vendor = PCI_VENDOR_ID_SI, 324 .device = PCI_DEVICE_ID_SI_650, 325 .subvendor = PCI_ANY_ID, 326 .subdevice = PCI_ANY_ID, 327 }, 328 { 329 .class = (PCI_CLASS_BRIDGE_HOST << 8), 330 .class_mask = ~0, 331 .vendor = PCI_VENDOR_ID_SI, 332 .device = PCI_DEVICE_ID_SI_651, 333 .subvendor = PCI_ANY_ID, 334 .subdevice = PCI_ANY_ID, 335 }, 336 { 337 .class = (PCI_CLASS_BRIDGE_HOST << 8), 338 .class_mask = ~0, 339 .vendor = PCI_VENDOR_ID_SI, 340 .device = PCI_DEVICE_ID_SI_655, 341 .subvendor = PCI_ANY_ID, 342 .subdevice = PCI_ANY_ID, 343 }, 344 { 345 .class = (PCI_CLASS_BRIDGE_HOST << 8), 346 .class_mask = ~0, 347 .vendor = PCI_VENDOR_ID_SI, 348 .device = PCI_DEVICE_ID_SI_661, 349 .subvendor = PCI_ANY_ID, 350 .subdevice = PCI_ANY_ID, 351 }, 352 { 353 .class = (PCI_CLASS_BRIDGE_HOST << 8), 354 .class_mask = ~0, 355 .vendor = PCI_VENDOR_ID_SI, 356 .device = PCI_DEVICE_ID_SI_662, 357 .subvendor = PCI_ANY_ID, 358 .subdevice = PCI_ANY_ID, 359 }, 360 { 361 .class = (PCI_CLASS_BRIDGE_HOST << 8), 362 .class_mask = ~0, 363 .vendor = PCI_VENDOR_ID_SI, 364 .device = PCI_DEVICE_ID_SI_671, 365 .subvendor = PCI_ANY_ID, 366 .subdevice = PCI_ANY_ID, 367 }, 368 { 369 .class = (PCI_CLASS_BRIDGE_HOST << 8), 370 .class_mask = ~0, 371 .vendor = PCI_VENDOR_ID_SI, 372 .device = PCI_DEVICE_ID_SI_730, 373 .subvendor = PCI_ANY_ID, 374 .subdevice = PCI_ANY_ID, 375 }, 376 { 377 .class = (PCI_CLASS_BRIDGE_HOST << 8), 378 .class_mask = ~0, 379 .vendor = PCI_VENDOR_ID_SI, 380 .device = PCI_DEVICE_ID_SI_735, 381 .subvendor = PCI_ANY_ID, 382 .subdevice = PCI_ANY_ID, 383 }, 384 { 385 .class = (PCI_CLASS_BRIDGE_HOST << 8), 386 .class_mask = ~0, 387 .vendor = PCI_VENDOR_ID_SI, 388 .device = PCI_DEVICE_ID_SI_740, 389 .subvendor = PCI_ANY_ID, 390 .subdevice = PCI_ANY_ID, 391 }, 392 { 393 .class = (PCI_CLASS_BRIDGE_HOST << 8), 394 .class_mask = ~0, 395 .vendor = PCI_VENDOR_ID_SI, 396 .device = PCI_DEVICE_ID_SI_741, 397 .subvendor = PCI_ANY_ID, 398 .subdevice = PCI_ANY_ID, 399 }, 400 { 401 .class = (PCI_CLASS_BRIDGE_HOST << 8), 402 .class_mask = ~0, 403 .vendor = PCI_VENDOR_ID_SI, 404 .device = PCI_DEVICE_ID_SI_745, 405 .subvendor = PCI_ANY_ID, 406 .subdevice = PCI_ANY_ID, 407 }, 408 { 409 .class = (PCI_CLASS_BRIDGE_HOST << 8), 410 .class_mask = ~0, 411 .vendor = PCI_VENDOR_ID_SI, 412 .device = PCI_DEVICE_ID_SI_746, 413 .subvendor = PCI_ANY_ID, 414 .subdevice = PCI_ANY_ID, 415 }, 416 { 417 .class = (PCI_CLASS_BRIDGE_HOST << 8), 418 .class_mask = ~0, 419 .vendor = PCI_VENDOR_ID_SI, 420 .device = PCI_DEVICE_ID_SI_760, 421 .subvendor = PCI_ANY_ID, 422 .subdevice = PCI_ANY_ID, 423 }, 424 { } 425 }; 426 427 MODULE_DEVICE_TABLE(pci, agp_sis_pci_table); 428 429 static struct pci_driver agp_sis_pci_driver = { 430 .name = "agpgart-sis", 431 .id_table = agp_sis_pci_table, 432 .probe = agp_sis_probe, 433 .remove = agp_sis_remove, 434 #ifdef CONFIG_PM 435 .suspend = agp_sis_suspend, 436 .resume = agp_sis_resume, 437 #endif 438 }; 439 440 static int __init agp_sis_init(void) 441 { 442 if (agp_off) 443 return -EINVAL; 444 return pci_register_driver(&agp_sis_pci_driver); 445 } 446 447 static void __exit agp_sis_cleanup(void) 448 { 449 pci_unregister_driver(&agp_sis_pci_driver); 450 } 451 452 module_init(agp_sis_init); 453 module_exit(agp_sis_cleanup); 454 455 module_param(agp_sis_force_delay, bool, 0); 456 MODULE_PARM_DESC(agp_sis_force_delay,"forces sis delay hack"); 457 module_param(agp_sis_agp_spec, int, 0); 458 MODULE_PARM_DESC(agp_sis_agp_spec,"0=force sis init, 1=force generic agp3 init, default: autodetect"); 459 MODULE_LICENSE("GPL and additional rights"); 460