581 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * VIA AGPGART routines.4 */5 6#include <linux/types.h>7#include <linux/module.h>8#include <linux/pci.h>9#include <linux/init.h>10#include <linux/agp_backend.h>11#include "agp.h"12 13static const struct pci_device_id agp_via_pci_table[];14 15#define VIA_GARTCTRL 0x8016#define VIA_APSIZE 0x8417#define VIA_ATTBASE 0x8818 19#define VIA_AGP3_GARTCTRL 0x9020#define VIA_AGP3_APSIZE 0x9421#define VIA_AGP3_ATTBASE 0x9822#define VIA_AGPSEL 0xfd23 24static int via_fetch_size(void)25{26 int i;27 u8 temp;28 struct aper_size_info_8 *values;29 30 values = A_SIZE_8(agp_bridge->driver->aperture_sizes);31 pci_read_config_byte(agp_bridge->dev, VIA_APSIZE, &temp);32 for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {33 if (temp == values[i].size_value) {34 agp_bridge->previous_size =35 agp_bridge->current_size = (void *) (values + i);36 agp_bridge->aperture_size_idx = i;37 return values[i].size;38 }39 }40 printk(KERN_ERR PFX "Unknown aperture size from AGP bridge (0x%x)\n", temp);41 return 0;42}43 44 45static int via_configure(void)46{47 struct aper_size_info_8 *current_size;48 49 current_size = A_SIZE_8(agp_bridge->current_size);50 /* aperture size */51 pci_write_config_byte(agp_bridge->dev, VIA_APSIZE,52 current_size->size_value);53 /* address to map to */54 agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,55 AGP_APERTURE_BAR);56 57 /* GART control register */58 pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, 0x0000000f);59 60 /* attbase - aperture GATT base */61 pci_write_config_dword(agp_bridge->dev, VIA_ATTBASE,62 (agp_bridge->gatt_bus_addr & 0xfffff000) | 3);63 return 0;64}65 66 67static void via_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, VIA_APSIZE,73 previous_size->size_value);74 /* Do not disable by writing 0 to VIA_ATTBASE, it screws things up75 * during reinitialization.76 */77}78 79 80static void via_tlbflush(struct agp_memory *mem)81{82 u32 temp;83 84 pci_read_config_dword(agp_bridge->dev, VIA_GARTCTRL, &temp);85 temp |= (1<<7);86 pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, temp);87 temp &= ~(1<<7);88 pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, temp);89}90 91 92static const struct aper_size_info_8 via_generic_sizes[9] =93{94 {256, 65536, 6, 0},95 {128, 32768, 5, 128},96 {64, 16384, 4, 192},97 {32, 8192, 3, 224},98 {16, 4096, 2, 240},99 {8, 2048, 1, 248},100 {4, 1024, 0, 252},101 {2, 512, 0, 254},102 {1, 256, 0, 255}103};104 105 106static int via_fetch_size_agp3(void)107{108 int i;109 u16 temp;110 struct aper_size_info_16 *values;111 112 values = A_SIZE_16(agp_bridge->driver->aperture_sizes);113 pci_read_config_word(agp_bridge->dev, VIA_AGP3_APSIZE, &temp);114 temp &= 0xfff;115 116 for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {117 if (temp == values[i].size_value) {118 agp_bridge->previous_size =119 agp_bridge->current_size = (void *) (values + i);120 agp_bridge->aperture_size_idx = i;121 return values[i].size;122 }123 }124 return 0;125}126 127 128static int via_configure_agp3(void)129{130 u32 temp;131 132 /* address to map to */133 agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,134 AGP_APERTURE_BAR);135 136 /* attbase - aperture GATT base */137 pci_write_config_dword(agp_bridge->dev, VIA_AGP3_ATTBASE,138 agp_bridge->gatt_bus_addr & 0xfffff000);139 140 /* 1. Enable GTLB in RX90<7>, all AGP aperture access needs to fetch141 * translation table first.142 * 2. Enable AGP aperture in RX91<0>. This bit controls the enabling of the143 * graphics AGP aperture for the AGP3.0 port.144 */145 pci_read_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, &temp);146 pci_write_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, temp | (3<<7));147 return 0;148}149 150 151static void via_cleanup_agp3(void)152{153 struct aper_size_info_16 *previous_size;154 155 previous_size = A_SIZE_16(agp_bridge->previous_size);156 pci_write_config_byte(agp_bridge->dev, VIA_APSIZE, previous_size->size_value);157}158 159 160static void via_tlbflush_agp3(struct agp_memory *mem)161{162 u32 temp;163 164 pci_read_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, &temp);165 pci_write_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, temp & ~(1<<7));166 pci_write_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, temp);167}168 169 170static const struct agp_bridge_driver via_agp3_driver = {171 .owner = THIS_MODULE,172 .aperture_sizes = agp3_generic_sizes,173 .size_type = U8_APER_SIZE,174 .num_aperture_sizes = 10,175 .needs_scratch_page = true,176 .configure = via_configure_agp3,177 .fetch_size = via_fetch_size_agp3,178 .cleanup = via_cleanup_agp3,179 .tlb_flush = via_tlbflush_agp3,180 .mask_memory = agp_generic_mask_memory,181 .masks = NULL,182 .agp_enable = agp_generic_enable,183 .cache_flush = global_cache_flush,184 .create_gatt_table = agp_generic_create_gatt_table,185 .free_gatt_table = agp_generic_free_gatt_table,186 .insert_memory = agp_generic_insert_memory,187 .remove_memory = agp_generic_remove_memory,188 .alloc_by_type = agp_generic_alloc_by_type,189 .free_by_type = agp_generic_free_by_type,190 .agp_alloc_page = agp_generic_alloc_page,191 .agp_alloc_pages = agp_generic_alloc_pages,192 .agp_destroy_page = agp_generic_destroy_page,193 .agp_destroy_pages = agp_generic_destroy_pages,194 .agp_type_to_mask_type = agp_generic_type_to_mask_type,195};196 197static const struct agp_bridge_driver via_driver = {198 .owner = THIS_MODULE,199 .aperture_sizes = via_generic_sizes,200 .size_type = U8_APER_SIZE,201 .num_aperture_sizes = 9,202 .needs_scratch_page = true,203 .configure = via_configure,204 .fetch_size = via_fetch_size,205 .cleanup = via_cleanup,206 .tlb_flush = via_tlbflush,207 .mask_memory = agp_generic_mask_memory,208 .masks = NULL,209 .agp_enable = agp_generic_enable,210 .cache_flush = global_cache_flush,211 .create_gatt_table = agp_generic_create_gatt_table,212 .free_gatt_table = agp_generic_free_gatt_table,213 .insert_memory = agp_generic_insert_memory,214 .remove_memory = agp_generic_remove_memory,215 .alloc_by_type = agp_generic_alloc_by_type,216 .free_by_type = agp_generic_free_by_type,217 .agp_alloc_page = agp_generic_alloc_page,218 .agp_alloc_pages = agp_generic_alloc_pages,219 .agp_destroy_page = agp_generic_destroy_page,220 .agp_destroy_pages = agp_generic_destroy_pages,221 .agp_type_to_mask_type = agp_generic_type_to_mask_type,222};223 224static struct agp_device_ids via_agp_device_ids[] =225{226 {227 .device_id = PCI_DEVICE_ID_VIA_82C597_0,228 .chipset_name = "Apollo VP3",229 },230 231 {232 .device_id = PCI_DEVICE_ID_VIA_82C598_0,233 .chipset_name = "Apollo MVP3",234 },235 236 {237 .device_id = PCI_DEVICE_ID_VIA_8501_0,238 .chipset_name = "Apollo MVP4",239 },240 241 /* VT8601 */242 {243 .device_id = PCI_DEVICE_ID_VIA_8601_0,244 .chipset_name = "Apollo ProMedia/PLE133Ta",245 },246 247 /* VT82C693A / VT28C694T */248 {249 .device_id = PCI_DEVICE_ID_VIA_82C691_0,250 .chipset_name = "Apollo Pro 133",251 },252 253 {254 .device_id = PCI_DEVICE_ID_VIA_8371_0,255 .chipset_name = "KX133",256 },257 258 /* VT8633 */259 {260 .device_id = PCI_DEVICE_ID_VIA_8633_0,261 .chipset_name = "Pro 266",262 },263 264 {265 .device_id = PCI_DEVICE_ID_VIA_XN266,266 .chipset_name = "Apollo Pro266",267 },268 269 /* VT8361 */270 {271 .device_id = PCI_DEVICE_ID_VIA_8361,272 .chipset_name = "KLE133",273 },274 275 /* VT8365 / VT8362 */276 {277 .device_id = PCI_DEVICE_ID_VIA_8363_0,278 .chipset_name = "Twister-K/KT133x/KM133",279 },280 281 /* VT8753A */282 {283 .device_id = PCI_DEVICE_ID_VIA_8753_0,284 .chipset_name = "P4X266",285 },286 287 /* VT8366 */288 {289 .device_id = PCI_DEVICE_ID_VIA_8367_0,290 .chipset_name = "KT266/KY266x/KT333",291 },292 293 /* VT8633 (for CuMine/ Celeron) */294 {295 .device_id = PCI_DEVICE_ID_VIA_8653_0,296 .chipset_name = "Pro266T",297 },298 299 /* KM266 / PM266 */300 {301 .device_id = PCI_DEVICE_ID_VIA_XM266,302 .chipset_name = "PM266/KM266",303 },304 305 /* CLE266 */306 {307 .device_id = PCI_DEVICE_ID_VIA_862X_0,308 .chipset_name = "CLE266",309 },310 311 {312 .device_id = PCI_DEVICE_ID_VIA_8377_0,313 .chipset_name = "KT400/KT400A/KT600",314 },315 316 /* VT8604 / VT8605 / VT8603317 * (Apollo Pro133A chipset with S3 Savage4) */318 {319 .device_id = PCI_DEVICE_ID_VIA_8605_0,320 .chipset_name = "ProSavage PM133/PL133/PN133"321 },322 323 /* P4M266x/P4N266 */324 {325 .device_id = PCI_DEVICE_ID_VIA_8703_51_0,326 .chipset_name = "P4M266x/P4N266",327 },328 329 /* VT8754 */330 {331 .device_id = PCI_DEVICE_ID_VIA_8754C_0,332 .chipset_name = "PT800",333 },334 335 /* P4X600 */336 {337 .device_id = PCI_DEVICE_ID_VIA_8763_0,338 .chipset_name = "P4X600"339 },340 341 /* KM400 */342 {343 .device_id = PCI_DEVICE_ID_VIA_8378_0,344 .chipset_name = "KM400/KM400A",345 },346 347 /* PT880 */348 {349 .device_id = PCI_DEVICE_ID_VIA_PT880,350 .chipset_name = "PT880",351 },352 353 /* PT880 Ultra */354 {355 .device_id = PCI_DEVICE_ID_VIA_PT880ULTRA,356 .chipset_name = "PT880 Ultra",357 },358 359 /* PT890 */360 {361 .device_id = PCI_DEVICE_ID_VIA_8783_0,362 .chipset_name = "PT890",363 },364 365 /* PM800/PN800/PM880/PN880 */366 {367 .device_id = PCI_DEVICE_ID_VIA_PX8X0_0,368 .chipset_name = "PM800/PN800/PM880/PN880",369 },370 /* KT880 */371 {372 .device_id = PCI_DEVICE_ID_VIA_3269_0,373 .chipset_name = "KT880",374 },375 /* KTxxx/Px8xx */376 {377 .device_id = PCI_DEVICE_ID_VIA_83_87XX_1,378 .chipset_name = "VT83xx/VT87xx/KTxxx/Px8xx",379 },380 /* P4M800 */381 {382 .device_id = PCI_DEVICE_ID_VIA_3296_0,383 .chipset_name = "P4M800",384 },385 /* P4M800CE */386 {387 .device_id = PCI_DEVICE_ID_VIA_P4M800CE,388 .chipset_name = "VT3314",389 },390 /* VT3324 / CX700 */391 {392 .device_id = PCI_DEVICE_ID_VIA_VT3324,393 .chipset_name = "CX700",394 },395 /* VT3336 - this is a chipset for AMD Athlon/K8 CPU. Due to K8's unique396 * architecture, the AGP resource and behavior are different from397 * the traditional AGP which resides only in chipset. AGP is used398 * by 3D driver which wasn't available for the VT3336 and VT3364399 * generation until now. Unfortunately, by testing, VT3364 works400 * but VT3336 doesn't. - explanation from via, just leave this as401 * as a placeholder to avoid future patches adding it back in.402 */403#if 0404 {405 .device_id = PCI_DEVICE_ID_VIA_VT3336,406 .chipset_name = "VT3336",407 },408#endif409 /* P4M890 */410 {411 .device_id = PCI_DEVICE_ID_VIA_P4M890,412 .chipset_name = "P4M890",413 },414 /* P4M900 */415 {416 .device_id = PCI_DEVICE_ID_VIA_VT3364,417 .chipset_name = "P4M900",418 },419 { }, /* dummy final entry, always present */420};421 422 423/*424 * VIA's AGP3 chipsets do magick to put the AGP bridge compliant425 * with the same standards version as the graphics card.426 */427static void check_via_agp3 (struct agp_bridge_data *bridge)428{429 u8 reg;430 431 pci_read_config_byte(bridge->dev, VIA_AGPSEL, ®);432 /* Check AGP 2.0 compatibility mode. */433 if ((reg & (1<<1))==0)434 bridge->driver = &via_agp3_driver;435}436 437 438static int agp_via_probe(struct pci_dev *pdev, const struct pci_device_id *ent)439{440 struct agp_device_ids *devs = via_agp_device_ids;441 struct agp_bridge_data *bridge;442 int j = 0;443 u8 cap_ptr;444 445 cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);446 if (!cap_ptr)447 return -ENODEV;448 449 j = ent - agp_via_pci_table;450 printk (KERN_INFO PFX "Detected VIA %s chipset\n", devs[j].chipset_name);451 452 bridge = agp_alloc_bridge();453 if (!bridge)454 return -ENOMEM;455 456 bridge->dev = pdev;457 bridge->capndx = cap_ptr;458 bridge->driver = &via_driver;459 460 /*461 * Garg, there are KT400s with KT266 IDs.462 */463 if (pdev->device == PCI_DEVICE_ID_VIA_8367_0) {464 /* Is there a KT400 subsystem ? */465 if (pdev->subsystem_device == PCI_DEVICE_ID_VIA_8377_0) {466 printk(KERN_INFO PFX "Found KT400 in disguise as a KT266.\n");467 check_via_agp3(bridge);468 }469 }470 471 /* If this is an AGP3 bridge, check which mode its in and adjust. */472 get_agp_version(bridge);473 if (bridge->major_version >= 3)474 check_via_agp3(bridge);475 476 /* Fill in the mode register */477 pci_read_config_dword(pdev,478 bridge->capndx+PCI_AGP_STATUS, &bridge->mode);479 480 pci_set_drvdata(pdev, bridge);481 return agp_add_bridge(bridge);482}483 484static void agp_via_remove(struct pci_dev *pdev)485{486 struct agp_bridge_data *bridge = pci_get_drvdata(pdev);487 488 agp_remove_bridge(bridge);489 agp_put_bridge(bridge);490}491 492static int agp_via_resume(struct device *dev)493{494 struct agp_bridge_data *bridge = dev_get_drvdata(dev);495 496 if (bridge->driver == &via_agp3_driver)497 return via_configure_agp3();498 else if (bridge->driver == &via_driver)499 return via_configure();500 501 return 0;502}503 504/* must be the same order as name table above */505static const struct pci_device_id agp_via_pci_table[] = {506#define ID(x) \507 { \508 .class = (PCI_CLASS_BRIDGE_HOST << 8), \509 .class_mask = ~0, \510 .vendor = PCI_VENDOR_ID_VIA, \511 .device = x, \512 .subvendor = PCI_ANY_ID, \513 .subdevice = PCI_ANY_ID, \514 }515 ID(PCI_DEVICE_ID_VIA_82C597_0),516 ID(PCI_DEVICE_ID_VIA_82C598_0),517 ID(PCI_DEVICE_ID_VIA_8501_0),518 ID(PCI_DEVICE_ID_VIA_8601_0),519 ID(PCI_DEVICE_ID_VIA_82C691_0),520 ID(PCI_DEVICE_ID_VIA_8371_0),521 ID(PCI_DEVICE_ID_VIA_8633_0),522 ID(PCI_DEVICE_ID_VIA_XN266),523 ID(PCI_DEVICE_ID_VIA_8361),524 ID(PCI_DEVICE_ID_VIA_8363_0),525 ID(PCI_DEVICE_ID_VIA_8753_0),526 ID(PCI_DEVICE_ID_VIA_8367_0),527 ID(PCI_DEVICE_ID_VIA_8653_0),528 ID(PCI_DEVICE_ID_VIA_XM266),529 ID(PCI_DEVICE_ID_VIA_862X_0),530 ID(PCI_DEVICE_ID_VIA_8377_0),531 ID(PCI_DEVICE_ID_VIA_8605_0),532 ID(PCI_DEVICE_ID_VIA_8703_51_0),533 ID(PCI_DEVICE_ID_VIA_8754C_0),534 ID(PCI_DEVICE_ID_VIA_8763_0),535 ID(PCI_DEVICE_ID_VIA_8378_0),536 ID(PCI_DEVICE_ID_VIA_PT880),537 ID(PCI_DEVICE_ID_VIA_PT880ULTRA),538 ID(PCI_DEVICE_ID_VIA_8783_0),539 ID(PCI_DEVICE_ID_VIA_PX8X0_0),540 ID(PCI_DEVICE_ID_VIA_3269_0),541 ID(PCI_DEVICE_ID_VIA_83_87XX_1),542 ID(PCI_DEVICE_ID_VIA_3296_0),543 ID(PCI_DEVICE_ID_VIA_P4M800CE),544 ID(PCI_DEVICE_ID_VIA_VT3324),545 ID(PCI_DEVICE_ID_VIA_P4M890),546 ID(PCI_DEVICE_ID_VIA_VT3364),547 { }548};549 550MODULE_DEVICE_TABLE(pci, agp_via_pci_table);551 552static DEFINE_SIMPLE_DEV_PM_OPS(agp_via_pm_ops, NULL, agp_via_resume);553 554static struct pci_driver agp_via_pci_driver = {555 .name = "agpgart-via",556 .id_table = agp_via_pci_table,557 .probe = agp_via_probe,558 .remove = agp_via_remove,559 .driver.pm = &agp_via_pm_ops,560};561 562 563static int __init agp_via_init(void)564{565 if (agp_off)566 return -EINVAL;567 return pci_register_driver(&agp_via_pci_driver);568}569 570static void __exit agp_via_cleanup(void)571{572 pci_unregister_driver(&agp_via_pci_driver);573}574 575module_init(agp_via_init);576module_exit(agp_via_cleanup);577 578MODULE_DESCRIPTION("VIA AGPGART routines");579MODULE_LICENSE("GPL");580MODULE_AUTHOR("Dave Jones");581