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 bool __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 .needs_scratch_page = true, 129 .configure = sis_configure, 130 .fetch_size = sis_fetch_size, 131 .cleanup = sis_cleanup, 132 .tlb_flush = sis_tlbflush, 133 .mask_memory = agp_generic_mask_memory, 134 .masks = NULL, 135 .agp_enable = agp_generic_enable, 136 .cache_flush = global_cache_flush, 137 .create_gatt_table = agp_generic_create_gatt_table, 138 .free_gatt_table = agp_generic_free_gatt_table, 139 .insert_memory = agp_generic_insert_memory, 140 .remove_memory = agp_generic_remove_memory, 141 .alloc_by_type = agp_generic_alloc_by_type, 142 .free_by_type = agp_generic_free_by_type, 143 .agp_alloc_page = agp_generic_alloc_page, 144 .agp_alloc_pages = agp_generic_alloc_pages, 145 .agp_destroy_page = agp_generic_destroy_page, 146 .agp_destroy_pages = agp_generic_destroy_pages, 147 .agp_type_to_mask_type = agp_generic_type_to_mask_type, 148 }; 149 150 // chipsets that require the 'delay hack' 151 static int sis_broken_chipsets[] __devinitdata = { 152 PCI_DEVICE_ID_SI_648, 153 PCI_DEVICE_ID_SI_746, 154 0 // terminator 155 }; 156 157 static void __devinit sis_get_driver(struct agp_bridge_data *bridge) 158 { 159 int i; 160 161 for (i=0; sis_broken_chipsets[i]!=0; ++i) 162 if (bridge->dev->device==sis_broken_chipsets[i]) 163 break; 164 165 if (sis_broken_chipsets[i] || agp_sis_force_delay) 166 sis_driver.agp_enable=sis_delayed_enable; 167 168 // sis chipsets that indicate less than agp3.5 169 // are not actually fully agp3 compliant 170 if ((agp_bridge->major_version == 3 && agp_bridge->minor_version >= 5 171 && agp_sis_agp_spec!=0) || agp_sis_agp_spec==1) { 172 sis_driver.aperture_sizes = agp3_generic_sizes; 173 sis_driver.size_type = U16_APER_SIZE; 174 sis_driver.num_aperture_sizes = AGP_GENERIC_SIZES_ENTRIES; 175 sis_driver.configure = agp3_generic_configure; 176 sis_driver.fetch_size = agp3_generic_fetch_size; 177 sis_driver.cleanup = agp3_generic_cleanup; 178 sis_driver.tlb_flush = agp3_generic_tlbflush; 179 } 180 } 181 182 183 static int __devinit agp_sis_probe(struct pci_dev *pdev, 184 const struct pci_device_id *ent) 185 { 186 struct agp_bridge_data *bridge; 187 u8 cap_ptr; 188 189 cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); 190 if (!cap_ptr) 191 return -ENODEV; 192 193 194 dev_info(&pdev->dev, "SiS chipset [%04x/%04x]\n", 195 pdev->vendor, pdev->device); 196 bridge = agp_alloc_bridge(); 197 if (!bridge) 198 return -ENOMEM; 199 200 bridge->driver = &sis_driver; 201 bridge->dev = pdev; 202 bridge->capndx = cap_ptr; 203 204 get_agp_version(bridge); 205 206 /* Fill in the mode register */ 207 pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode); 208 sis_get_driver(bridge); 209 210 pci_set_drvdata(pdev, bridge); 211 return agp_add_bridge(bridge); 212 } 213 214 static void __devexit agp_sis_remove(struct pci_dev *pdev) 215 { 216 struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 217 218 agp_remove_bridge(bridge); 219 agp_put_bridge(bridge); 220 } 221 222 #ifdef CONFIG_PM 223 224 static int agp_sis_suspend(struct pci_dev *pdev, pm_message_t state) 225 { 226 pci_save_state(pdev); 227 pci_set_power_state(pdev, pci_choose_state(pdev, state)); 228 229 return 0; 230 } 231 232 static int agp_sis_resume(struct pci_dev *pdev) 233 { 234 pci_set_power_state(pdev, PCI_D0); 235 pci_restore_state(pdev); 236 237 return sis_driver.configure(); 238 } 239 240 #endif /* CONFIG_PM */ 241 242 static struct pci_device_id agp_sis_pci_table[] = { 243 { 244 .class = (PCI_CLASS_BRIDGE_HOST << 8), 245 .class_mask = ~0, 246 .vendor = PCI_VENDOR_ID_SI, 247 .device = PCI_DEVICE_ID_SI_5591, 248 .subvendor = PCI_ANY_ID, 249 .subdevice = PCI_ANY_ID, 250 }, 251 { 252 .class = (PCI_CLASS_BRIDGE_HOST << 8), 253 .class_mask = ~0, 254 .vendor = PCI_VENDOR_ID_SI, 255 .device = PCI_DEVICE_ID_SI_530, 256 .subvendor = PCI_ANY_ID, 257 .subdevice = PCI_ANY_ID, 258 }, 259 { 260 .class = (PCI_CLASS_BRIDGE_HOST << 8), 261 .class_mask = ~0, 262 .vendor = PCI_VENDOR_ID_SI, 263 .device = PCI_DEVICE_ID_SI_540, 264 .subvendor = PCI_ANY_ID, 265 .subdevice = PCI_ANY_ID, 266 }, 267 { 268 .class = (PCI_CLASS_BRIDGE_HOST << 8), 269 .class_mask = ~0, 270 .vendor = PCI_VENDOR_ID_SI, 271 .device = PCI_DEVICE_ID_SI_550, 272 .subvendor = PCI_ANY_ID, 273 .subdevice = PCI_ANY_ID, 274 }, 275 { 276 .class = (PCI_CLASS_BRIDGE_HOST << 8), 277 .class_mask = ~0, 278 .vendor = PCI_VENDOR_ID_SI, 279 .device = PCI_DEVICE_ID_SI_620, 280 .subvendor = PCI_ANY_ID, 281 .subdevice = PCI_ANY_ID, 282 }, 283 { 284 .class = (PCI_CLASS_BRIDGE_HOST << 8), 285 .class_mask = ~0, 286 .vendor = PCI_VENDOR_ID_SI, 287 .device = PCI_DEVICE_ID_SI_630, 288 .subvendor = PCI_ANY_ID, 289 .subdevice = PCI_ANY_ID, 290 }, 291 { 292 .class = (PCI_CLASS_BRIDGE_HOST << 8), 293 .class_mask = ~0, 294 .vendor = PCI_VENDOR_ID_SI, 295 .device = PCI_DEVICE_ID_SI_635, 296 .subvendor = PCI_ANY_ID, 297 .subdevice = PCI_ANY_ID, 298 }, 299 { 300 .class = (PCI_CLASS_BRIDGE_HOST << 8), 301 .class_mask = ~0, 302 .vendor = PCI_VENDOR_ID_SI, 303 .device = PCI_DEVICE_ID_SI_645, 304 .subvendor = PCI_ANY_ID, 305 .subdevice = PCI_ANY_ID, 306 }, 307 { 308 .class = (PCI_CLASS_BRIDGE_HOST << 8), 309 .class_mask = ~0, 310 .vendor = PCI_VENDOR_ID_SI, 311 .device = PCI_DEVICE_ID_SI_646, 312 .subvendor = PCI_ANY_ID, 313 .subdevice = PCI_ANY_ID, 314 }, 315 { 316 .class = (PCI_CLASS_BRIDGE_HOST << 8), 317 .class_mask = ~0, 318 .vendor = PCI_VENDOR_ID_SI, 319 .device = PCI_DEVICE_ID_SI_648, 320 .subvendor = PCI_ANY_ID, 321 .subdevice = PCI_ANY_ID, 322 }, 323 { 324 .class = (PCI_CLASS_BRIDGE_HOST << 8), 325 .class_mask = ~0, 326 .vendor = PCI_VENDOR_ID_SI, 327 .device = PCI_DEVICE_ID_SI_650, 328 .subvendor = PCI_ANY_ID, 329 .subdevice = PCI_ANY_ID, 330 }, 331 { 332 .class = (PCI_CLASS_BRIDGE_HOST << 8), 333 .class_mask = ~0, 334 .vendor = PCI_VENDOR_ID_SI, 335 .device = PCI_DEVICE_ID_SI_651, 336 .subvendor = PCI_ANY_ID, 337 .subdevice = PCI_ANY_ID, 338 }, 339 { 340 .class = (PCI_CLASS_BRIDGE_HOST << 8), 341 .class_mask = ~0, 342 .vendor = PCI_VENDOR_ID_SI, 343 .device = PCI_DEVICE_ID_SI_655, 344 .subvendor = PCI_ANY_ID, 345 .subdevice = PCI_ANY_ID, 346 }, 347 { 348 .class = (PCI_CLASS_BRIDGE_HOST << 8), 349 .class_mask = ~0, 350 .vendor = PCI_VENDOR_ID_SI, 351 .device = PCI_DEVICE_ID_SI_661, 352 .subvendor = PCI_ANY_ID, 353 .subdevice = PCI_ANY_ID, 354 }, 355 { 356 .class = (PCI_CLASS_BRIDGE_HOST << 8), 357 .class_mask = ~0, 358 .vendor = PCI_VENDOR_ID_SI, 359 .device = PCI_DEVICE_ID_SI_662, 360 .subvendor = PCI_ANY_ID, 361 .subdevice = PCI_ANY_ID, 362 }, 363 { 364 .class = (PCI_CLASS_BRIDGE_HOST << 8), 365 .class_mask = ~0, 366 .vendor = PCI_VENDOR_ID_SI, 367 .device = PCI_DEVICE_ID_SI_671, 368 .subvendor = PCI_ANY_ID, 369 .subdevice = PCI_ANY_ID, 370 }, 371 { 372 .class = (PCI_CLASS_BRIDGE_HOST << 8), 373 .class_mask = ~0, 374 .vendor = PCI_VENDOR_ID_SI, 375 .device = PCI_DEVICE_ID_SI_730, 376 .subvendor = PCI_ANY_ID, 377 .subdevice = PCI_ANY_ID, 378 }, 379 { 380 .class = (PCI_CLASS_BRIDGE_HOST << 8), 381 .class_mask = ~0, 382 .vendor = PCI_VENDOR_ID_SI, 383 .device = PCI_DEVICE_ID_SI_735, 384 .subvendor = PCI_ANY_ID, 385 .subdevice = PCI_ANY_ID, 386 }, 387 { 388 .class = (PCI_CLASS_BRIDGE_HOST << 8), 389 .class_mask = ~0, 390 .vendor = PCI_VENDOR_ID_SI, 391 .device = PCI_DEVICE_ID_SI_740, 392 .subvendor = PCI_ANY_ID, 393 .subdevice = PCI_ANY_ID, 394 }, 395 { 396 .class = (PCI_CLASS_BRIDGE_HOST << 8), 397 .class_mask = ~0, 398 .vendor = PCI_VENDOR_ID_SI, 399 .device = PCI_DEVICE_ID_SI_741, 400 .subvendor = PCI_ANY_ID, 401 .subdevice = PCI_ANY_ID, 402 }, 403 { 404 .class = (PCI_CLASS_BRIDGE_HOST << 8), 405 .class_mask = ~0, 406 .vendor = PCI_VENDOR_ID_SI, 407 .device = PCI_DEVICE_ID_SI_745, 408 .subvendor = PCI_ANY_ID, 409 .subdevice = PCI_ANY_ID, 410 }, 411 { 412 .class = (PCI_CLASS_BRIDGE_HOST << 8), 413 .class_mask = ~0, 414 .vendor = PCI_VENDOR_ID_SI, 415 .device = PCI_DEVICE_ID_SI_746, 416 .subvendor = PCI_ANY_ID, 417 .subdevice = PCI_ANY_ID, 418 }, 419 { } 420 }; 421 422 MODULE_DEVICE_TABLE(pci, agp_sis_pci_table); 423 424 static struct pci_driver agp_sis_pci_driver = { 425 .name = "agpgart-sis", 426 .id_table = agp_sis_pci_table, 427 .probe = agp_sis_probe, 428 .remove = agp_sis_remove, 429 #ifdef CONFIG_PM 430 .suspend = agp_sis_suspend, 431 .resume = agp_sis_resume, 432 #endif 433 }; 434 435 static int __init agp_sis_init(void) 436 { 437 if (agp_off) 438 return -EINVAL; 439 return pci_register_driver(&agp_sis_pci_driver); 440 } 441 442 static void __exit agp_sis_cleanup(void) 443 { 444 pci_unregister_driver(&agp_sis_pci_driver); 445 } 446 447 module_init(agp_sis_init); 448 module_exit(agp_sis_cleanup); 449 450 module_param(agp_sis_force_delay, bool, 0); 451 MODULE_PARM_DESC(agp_sis_force_delay,"forces sis delay hack"); 452 module_param(agp_sis_agp_spec, int, 0); 453 MODULE_PARM_DESC(agp_sis_agp_spec,"0=force sis init, 1=force generic agp3 init, default: autodetect"); 454 MODULE_LICENSE("GPL and additional rights"); 455