162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * VIA AGPGART routines.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/types.h>
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/pci.h>
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/agp_backend.h>
1162306a36Sopenharmony_ci#include "agp.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic const struct pci_device_id agp_via_pci_table[];
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define VIA_GARTCTRL	0x80
1662306a36Sopenharmony_ci#define VIA_APSIZE	0x84
1762306a36Sopenharmony_ci#define VIA_ATTBASE	0x88
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define VIA_AGP3_GARTCTRL	0x90
2062306a36Sopenharmony_ci#define VIA_AGP3_APSIZE		0x94
2162306a36Sopenharmony_ci#define VIA_AGP3_ATTBASE	0x98
2262306a36Sopenharmony_ci#define VIA_AGPSEL		0xfd
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic int via_fetch_size(void)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	int i;
2762306a36Sopenharmony_ci	u8 temp;
2862306a36Sopenharmony_ci	struct aper_size_info_8 *values;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
3162306a36Sopenharmony_ci	pci_read_config_byte(agp_bridge->dev, VIA_APSIZE, &temp);
3262306a36Sopenharmony_ci	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
3362306a36Sopenharmony_ci		if (temp == values[i].size_value) {
3462306a36Sopenharmony_ci			agp_bridge->previous_size =
3562306a36Sopenharmony_ci			    agp_bridge->current_size = (void *) (values + i);
3662306a36Sopenharmony_ci			agp_bridge->aperture_size_idx = i;
3762306a36Sopenharmony_ci			return values[i].size;
3862306a36Sopenharmony_ci		}
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci	printk(KERN_ERR PFX "Unknown aperture size from AGP bridge (0x%x)\n", temp);
4162306a36Sopenharmony_ci	return 0;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int via_configure(void)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct aper_size_info_8 *current_size;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	current_size = A_SIZE_8(agp_bridge->current_size);
5062306a36Sopenharmony_ci	/* aperture size */
5162306a36Sopenharmony_ci	pci_write_config_byte(agp_bridge->dev, VIA_APSIZE,
5262306a36Sopenharmony_ci			      current_size->size_value);
5362306a36Sopenharmony_ci	/* address to map to */
5462306a36Sopenharmony_ci	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
5562306a36Sopenharmony_ci						    AGP_APERTURE_BAR);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* GART control register */
5862306a36Sopenharmony_ci	pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, 0x0000000f);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* attbase - aperture GATT base */
6162306a36Sopenharmony_ci	pci_write_config_dword(agp_bridge->dev, VIA_ATTBASE,
6262306a36Sopenharmony_ci			    (agp_bridge->gatt_bus_addr & 0xfffff000) | 3);
6362306a36Sopenharmony_ci	return 0;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void via_cleanup(void)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct aper_size_info_8 *previous_size;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	previous_size = A_SIZE_8(agp_bridge->previous_size);
7262306a36Sopenharmony_ci	pci_write_config_byte(agp_bridge->dev, VIA_APSIZE,
7362306a36Sopenharmony_ci			      previous_size->size_value);
7462306a36Sopenharmony_ci	/* Do not disable by writing 0 to VIA_ATTBASE, it screws things up
7562306a36Sopenharmony_ci	 * during reinitialization.
7662306a36Sopenharmony_ci	 */
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void via_tlbflush(struct agp_memory *mem)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	u32 temp;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	pci_read_config_dword(agp_bridge->dev, VIA_GARTCTRL, &temp);
8562306a36Sopenharmony_ci	temp |= (1<<7);
8662306a36Sopenharmony_ci	pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, temp);
8762306a36Sopenharmony_ci	temp &= ~(1<<7);
8862306a36Sopenharmony_ci	pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, temp);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic const struct aper_size_info_8 via_generic_sizes[9] =
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	{256, 65536, 6, 0},
9562306a36Sopenharmony_ci	{128, 32768, 5, 128},
9662306a36Sopenharmony_ci	{64, 16384, 4, 192},
9762306a36Sopenharmony_ci	{32, 8192, 3, 224},
9862306a36Sopenharmony_ci	{16, 4096, 2, 240},
9962306a36Sopenharmony_ci	{8, 2048, 1, 248},
10062306a36Sopenharmony_ci	{4, 1024, 0, 252},
10162306a36Sopenharmony_ci	{2, 512, 0, 254},
10262306a36Sopenharmony_ci	{1, 256, 0, 255}
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic int via_fetch_size_agp3(void)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	int i;
10962306a36Sopenharmony_ci	u16 temp;
11062306a36Sopenharmony_ci	struct aper_size_info_16 *values;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	values = A_SIZE_16(agp_bridge->driver->aperture_sizes);
11362306a36Sopenharmony_ci	pci_read_config_word(agp_bridge->dev, VIA_AGP3_APSIZE, &temp);
11462306a36Sopenharmony_ci	temp &= 0xfff;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
11762306a36Sopenharmony_ci		if (temp == values[i].size_value) {
11862306a36Sopenharmony_ci			agp_bridge->previous_size =
11962306a36Sopenharmony_ci				agp_bridge->current_size = (void *) (values + i);
12062306a36Sopenharmony_ci			agp_bridge->aperture_size_idx = i;
12162306a36Sopenharmony_ci			return values[i].size;
12262306a36Sopenharmony_ci		}
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int via_configure_agp3(void)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	u32 temp;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* address to map to */
13362306a36Sopenharmony_ci	agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
13462306a36Sopenharmony_ci						    AGP_APERTURE_BAR);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* attbase - aperture GATT base */
13762306a36Sopenharmony_ci	pci_write_config_dword(agp_bridge->dev, VIA_AGP3_ATTBASE,
13862306a36Sopenharmony_ci		agp_bridge->gatt_bus_addr & 0xfffff000);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* 1. Enable GTLB in RX90<7>, all AGP aperture access needs to fetch
14162306a36Sopenharmony_ci	 *    translation table first.
14262306a36Sopenharmony_ci	 * 2. Enable AGP aperture in RX91<0>. This bit controls the enabling of the
14362306a36Sopenharmony_ci	 *    graphics AGP aperture for the AGP3.0 port.
14462306a36Sopenharmony_ci	 */
14562306a36Sopenharmony_ci	pci_read_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, &temp);
14662306a36Sopenharmony_ci	pci_write_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, temp | (3<<7));
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void via_cleanup_agp3(void)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct aper_size_info_16 *previous_size;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	previous_size = A_SIZE_16(agp_bridge->previous_size);
15662306a36Sopenharmony_ci	pci_write_config_byte(agp_bridge->dev, VIA_APSIZE, previous_size->size_value);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic void via_tlbflush_agp3(struct agp_memory *mem)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	u32 temp;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	pci_read_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, &temp);
16562306a36Sopenharmony_ci	pci_write_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, temp & ~(1<<7));
16662306a36Sopenharmony_ci	pci_write_config_dword(agp_bridge->dev, VIA_AGP3_GARTCTRL, temp);
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic const struct agp_bridge_driver via_agp3_driver = {
17162306a36Sopenharmony_ci	.owner			= THIS_MODULE,
17262306a36Sopenharmony_ci	.aperture_sizes		= agp3_generic_sizes,
17362306a36Sopenharmony_ci	.size_type		= U8_APER_SIZE,
17462306a36Sopenharmony_ci	.num_aperture_sizes	= 10,
17562306a36Sopenharmony_ci	.needs_scratch_page	= true,
17662306a36Sopenharmony_ci	.configure		= via_configure_agp3,
17762306a36Sopenharmony_ci	.fetch_size		= via_fetch_size_agp3,
17862306a36Sopenharmony_ci	.cleanup		= via_cleanup_agp3,
17962306a36Sopenharmony_ci	.tlb_flush		= via_tlbflush_agp3,
18062306a36Sopenharmony_ci	.mask_memory		= agp_generic_mask_memory,
18162306a36Sopenharmony_ci	.masks			= NULL,
18262306a36Sopenharmony_ci	.agp_enable		= agp_generic_enable,
18362306a36Sopenharmony_ci	.cache_flush		= global_cache_flush,
18462306a36Sopenharmony_ci	.create_gatt_table	= agp_generic_create_gatt_table,
18562306a36Sopenharmony_ci	.free_gatt_table	= agp_generic_free_gatt_table,
18662306a36Sopenharmony_ci	.insert_memory		= agp_generic_insert_memory,
18762306a36Sopenharmony_ci	.remove_memory		= agp_generic_remove_memory,
18862306a36Sopenharmony_ci	.alloc_by_type		= agp_generic_alloc_by_type,
18962306a36Sopenharmony_ci	.free_by_type		= agp_generic_free_by_type,
19062306a36Sopenharmony_ci	.agp_alloc_page		= agp_generic_alloc_page,
19162306a36Sopenharmony_ci	.agp_alloc_pages	= agp_generic_alloc_pages,
19262306a36Sopenharmony_ci	.agp_destroy_page	= agp_generic_destroy_page,
19362306a36Sopenharmony_ci	.agp_destroy_pages	= agp_generic_destroy_pages,
19462306a36Sopenharmony_ci	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
19562306a36Sopenharmony_ci};
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic const struct agp_bridge_driver via_driver = {
19862306a36Sopenharmony_ci	.owner			= THIS_MODULE,
19962306a36Sopenharmony_ci	.aperture_sizes		= via_generic_sizes,
20062306a36Sopenharmony_ci	.size_type		= U8_APER_SIZE,
20162306a36Sopenharmony_ci	.num_aperture_sizes	= 9,
20262306a36Sopenharmony_ci	.needs_scratch_page	= true,
20362306a36Sopenharmony_ci	.configure		= via_configure,
20462306a36Sopenharmony_ci	.fetch_size		= via_fetch_size,
20562306a36Sopenharmony_ci	.cleanup		= via_cleanup,
20662306a36Sopenharmony_ci	.tlb_flush		= via_tlbflush,
20762306a36Sopenharmony_ci	.mask_memory		= agp_generic_mask_memory,
20862306a36Sopenharmony_ci	.masks			= NULL,
20962306a36Sopenharmony_ci	.agp_enable		= agp_generic_enable,
21062306a36Sopenharmony_ci	.cache_flush		= global_cache_flush,
21162306a36Sopenharmony_ci	.create_gatt_table	= agp_generic_create_gatt_table,
21262306a36Sopenharmony_ci	.free_gatt_table	= agp_generic_free_gatt_table,
21362306a36Sopenharmony_ci	.insert_memory		= agp_generic_insert_memory,
21462306a36Sopenharmony_ci	.remove_memory		= agp_generic_remove_memory,
21562306a36Sopenharmony_ci	.alloc_by_type		= agp_generic_alloc_by_type,
21662306a36Sopenharmony_ci	.free_by_type		= agp_generic_free_by_type,
21762306a36Sopenharmony_ci	.agp_alloc_page		= agp_generic_alloc_page,
21862306a36Sopenharmony_ci	.agp_alloc_pages	= agp_generic_alloc_pages,
21962306a36Sopenharmony_ci	.agp_destroy_page	= agp_generic_destroy_page,
22062306a36Sopenharmony_ci	.agp_destroy_pages	= agp_generic_destroy_pages,
22162306a36Sopenharmony_ci	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic struct agp_device_ids via_agp_device_ids[] =
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	{
22762306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_82C597_0,
22862306a36Sopenharmony_ci		.chipset_name	= "Apollo VP3",
22962306a36Sopenharmony_ci	},
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	{
23262306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_82C598_0,
23362306a36Sopenharmony_ci		.chipset_name	= "Apollo MVP3",
23462306a36Sopenharmony_ci	},
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	{
23762306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8501_0,
23862306a36Sopenharmony_ci		.chipset_name	= "Apollo MVP4",
23962306a36Sopenharmony_ci	},
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/* VT8601 */
24262306a36Sopenharmony_ci	{
24362306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8601_0,
24462306a36Sopenharmony_ci		.chipset_name	= "Apollo ProMedia/PLE133Ta",
24562306a36Sopenharmony_ci	},
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* VT82C693A / VT28C694T */
24862306a36Sopenharmony_ci	{
24962306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_82C691_0,
25062306a36Sopenharmony_ci		.chipset_name	= "Apollo Pro 133",
25162306a36Sopenharmony_ci	},
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	{
25462306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8371_0,
25562306a36Sopenharmony_ci		.chipset_name	= "KX133",
25662306a36Sopenharmony_ci	},
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/* VT8633 */
25962306a36Sopenharmony_ci	{
26062306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8633_0,
26162306a36Sopenharmony_ci		.chipset_name	= "Pro 266",
26262306a36Sopenharmony_ci	},
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	{
26562306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_XN266,
26662306a36Sopenharmony_ci		.chipset_name	= "Apollo Pro266",
26762306a36Sopenharmony_ci	},
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* VT8361 */
27062306a36Sopenharmony_ci	{
27162306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8361,
27262306a36Sopenharmony_ci		.chipset_name	= "KLE133",
27362306a36Sopenharmony_ci	},
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* VT8365 / VT8362 */
27662306a36Sopenharmony_ci	{
27762306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8363_0,
27862306a36Sopenharmony_ci		.chipset_name	= "Twister-K/KT133x/KM133",
27962306a36Sopenharmony_ci	},
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/* VT8753A */
28262306a36Sopenharmony_ci	{
28362306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8753_0,
28462306a36Sopenharmony_ci		.chipset_name	= "P4X266",
28562306a36Sopenharmony_ci	},
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* VT8366 */
28862306a36Sopenharmony_ci	{
28962306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8367_0,
29062306a36Sopenharmony_ci		.chipset_name	= "KT266/KY266x/KT333",
29162306a36Sopenharmony_ci	},
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/* VT8633 (for CuMine/ Celeron) */
29462306a36Sopenharmony_ci	{
29562306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8653_0,
29662306a36Sopenharmony_ci		.chipset_name	= "Pro266T",
29762306a36Sopenharmony_ci	},
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* KM266 / PM266 */
30062306a36Sopenharmony_ci	{
30162306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_XM266,
30262306a36Sopenharmony_ci		.chipset_name	= "PM266/KM266",
30362306a36Sopenharmony_ci	},
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* CLE266 */
30662306a36Sopenharmony_ci	{
30762306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_862X_0,
30862306a36Sopenharmony_ci		.chipset_name	= "CLE266",
30962306a36Sopenharmony_ci	},
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	{
31262306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8377_0,
31362306a36Sopenharmony_ci		.chipset_name	= "KT400/KT400A/KT600",
31462306a36Sopenharmony_ci	},
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* VT8604 / VT8605 / VT8603
31762306a36Sopenharmony_ci	 * (Apollo Pro133A chipset with S3 Savage4) */
31862306a36Sopenharmony_ci	{
31962306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8605_0,
32062306a36Sopenharmony_ci		.chipset_name	= "ProSavage PM133/PL133/PN133"
32162306a36Sopenharmony_ci	},
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* P4M266x/P4N266 */
32462306a36Sopenharmony_ci	{
32562306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8703_51_0,
32662306a36Sopenharmony_ci		.chipset_name	= "P4M266x/P4N266",
32762306a36Sopenharmony_ci	},
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	/* VT8754 */
33062306a36Sopenharmony_ci	{
33162306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8754C_0,
33262306a36Sopenharmony_ci		.chipset_name	= "PT800",
33362306a36Sopenharmony_ci	},
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* P4X600 */
33662306a36Sopenharmony_ci	{
33762306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8763_0,
33862306a36Sopenharmony_ci		.chipset_name	= "P4X600"
33962306a36Sopenharmony_ci	},
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* KM400 */
34262306a36Sopenharmony_ci	{
34362306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8378_0,
34462306a36Sopenharmony_ci		.chipset_name	= "KM400/KM400A",
34562306a36Sopenharmony_ci	},
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	/* PT880 */
34862306a36Sopenharmony_ci	{
34962306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_PT880,
35062306a36Sopenharmony_ci		.chipset_name	= "PT880",
35162306a36Sopenharmony_ci	},
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* PT880 Ultra */
35462306a36Sopenharmony_ci	{
35562306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_PT880ULTRA,
35662306a36Sopenharmony_ci		.chipset_name	= "PT880 Ultra",
35762306a36Sopenharmony_ci	},
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/* PT890 */
36062306a36Sopenharmony_ci	{
36162306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_8783_0,
36262306a36Sopenharmony_ci		.chipset_name	= "PT890",
36362306a36Sopenharmony_ci	},
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* PM800/PN800/PM880/PN880 */
36662306a36Sopenharmony_ci	{
36762306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_PX8X0_0,
36862306a36Sopenharmony_ci		.chipset_name	= "PM800/PN800/PM880/PN880",
36962306a36Sopenharmony_ci	},
37062306a36Sopenharmony_ci	/* KT880 */
37162306a36Sopenharmony_ci	{
37262306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_3269_0,
37362306a36Sopenharmony_ci		.chipset_name	= "KT880",
37462306a36Sopenharmony_ci	},
37562306a36Sopenharmony_ci	/* KTxxx/Px8xx */
37662306a36Sopenharmony_ci	{
37762306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_83_87XX_1,
37862306a36Sopenharmony_ci		.chipset_name	= "VT83xx/VT87xx/KTxxx/Px8xx",
37962306a36Sopenharmony_ci	},
38062306a36Sopenharmony_ci	/* P4M800 */
38162306a36Sopenharmony_ci	{
38262306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_3296_0,
38362306a36Sopenharmony_ci		.chipset_name	= "P4M800",
38462306a36Sopenharmony_ci	},
38562306a36Sopenharmony_ci	/* P4M800CE */
38662306a36Sopenharmony_ci	{
38762306a36Sopenharmony_ci		.device_id	= PCI_DEVICE_ID_VIA_P4M800CE,
38862306a36Sopenharmony_ci		.chipset_name	= "VT3314",
38962306a36Sopenharmony_ci	},
39062306a36Sopenharmony_ci	/* VT3324 / CX700 */
39162306a36Sopenharmony_ci	{
39262306a36Sopenharmony_ci		.device_id  = PCI_DEVICE_ID_VIA_VT3324,
39362306a36Sopenharmony_ci		.chipset_name   = "CX700",
39462306a36Sopenharmony_ci	},
39562306a36Sopenharmony_ci	/* VT3336 - this is a chipset for AMD Athlon/K8 CPU. Due to K8's unique
39662306a36Sopenharmony_ci	 * architecture, the AGP resource and behavior are different from
39762306a36Sopenharmony_ci	 * the traditional AGP which resides only in chipset. AGP is used
39862306a36Sopenharmony_ci	 * by 3D driver which wasn't available for the VT3336 and VT3364
39962306a36Sopenharmony_ci	 * generation until now.  Unfortunately, by testing, VT3364 works
40062306a36Sopenharmony_ci	 * but VT3336 doesn't. - explanation from via, just leave this as
40162306a36Sopenharmony_ci	 * as a placeholder to avoid future patches adding it back in.
40262306a36Sopenharmony_ci	 */
40362306a36Sopenharmony_ci#if 0
40462306a36Sopenharmony_ci	{
40562306a36Sopenharmony_ci		.device_id  = PCI_DEVICE_ID_VIA_VT3336,
40662306a36Sopenharmony_ci		.chipset_name   = "VT3336",
40762306a36Sopenharmony_ci	},
40862306a36Sopenharmony_ci#endif
40962306a36Sopenharmony_ci	/* P4M890 */
41062306a36Sopenharmony_ci	{
41162306a36Sopenharmony_ci		.device_id  = PCI_DEVICE_ID_VIA_P4M890,
41262306a36Sopenharmony_ci		.chipset_name   = "P4M890",
41362306a36Sopenharmony_ci	},
41462306a36Sopenharmony_ci	/* P4M900 */
41562306a36Sopenharmony_ci	{
41662306a36Sopenharmony_ci		.device_id  = PCI_DEVICE_ID_VIA_VT3364,
41762306a36Sopenharmony_ci		.chipset_name   = "P4M900",
41862306a36Sopenharmony_ci	},
41962306a36Sopenharmony_ci	{ }, /* dummy final entry, always present */
42062306a36Sopenharmony_ci};
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci/*
42462306a36Sopenharmony_ci * VIA's AGP3 chipsets do magick to put the AGP bridge compliant
42562306a36Sopenharmony_ci * with the same standards version as the graphics card.
42662306a36Sopenharmony_ci */
42762306a36Sopenharmony_cistatic void check_via_agp3 (struct agp_bridge_data *bridge)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	u8 reg;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	pci_read_config_byte(bridge->dev, VIA_AGPSEL, &reg);
43262306a36Sopenharmony_ci	/* Check AGP 2.0 compatibility mode. */
43362306a36Sopenharmony_ci	if ((reg & (1<<1))==0)
43462306a36Sopenharmony_ci		bridge->driver = &via_agp3_driver;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic int agp_via_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct agp_device_ids *devs = via_agp_device_ids;
44162306a36Sopenharmony_ci	struct agp_bridge_data *bridge;
44262306a36Sopenharmony_ci	int j = 0;
44362306a36Sopenharmony_ci	u8 cap_ptr;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
44662306a36Sopenharmony_ci	if (!cap_ptr)
44762306a36Sopenharmony_ci		return -ENODEV;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	j = ent - agp_via_pci_table;
45062306a36Sopenharmony_ci	printk (KERN_INFO PFX "Detected VIA %s chipset\n", devs[j].chipset_name);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	bridge = agp_alloc_bridge();
45362306a36Sopenharmony_ci	if (!bridge)
45462306a36Sopenharmony_ci		return -ENOMEM;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	bridge->dev = pdev;
45762306a36Sopenharmony_ci	bridge->capndx = cap_ptr;
45862306a36Sopenharmony_ci	bridge->driver = &via_driver;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/*
46162306a36Sopenharmony_ci	 * Garg, there are KT400s with KT266 IDs.
46262306a36Sopenharmony_ci	 */
46362306a36Sopenharmony_ci	if (pdev->device == PCI_DEVICE_ID_VIA_8367_0) {
46462306a36Sopenharmony_ci		/* Is there a KT400 subsystem ? */
46562306a36Sopenharmony_ci		if (pdev->subsystem_device == PCI_DEVICE_ID_VIA_8377_0) {
46662306a36Sopenharmony_ci			printk(KERN_INFO PFX "Found KT400 in disguise as a KT266.\n");
46762306a36Sopenharmony_ci			check_via_agp3(bridge);
46862306a36Sopenharmony_ci		}
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* If this is an AGP3 bridge, check which mode its in and adjust. */
47262306a36Sopenharmony_ci	get_agp_version(bridge);
47362306a36Sopenharmony_ci	if (bridge->major_version >= 3)
47462306a36Sopenharmony_ci		check_via_agp3(bridge);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/* Fill in the mode register */
47762306a36Sopenharmony_ci	pci_read_config_dword(pdev,
47862306a36Sopenharmony_ci			bridge->capndx+PCI_AGP_STATUS, &bridge->mode);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	pci_set_drvdata(pdev, bridge);
48162306a36Sopenharmony_ci	return agp_add_bridge(bridge);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic void agp_via_remove(struct pci_dev *pdev)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	agp_remove_bridge(bridge);
48962306a36Sopenharmony_ci	agp_put_bridge(bridge);
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic int agp_via_resume(struct device *dev)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	struct agp_bridge_data *bridge = dev_get_drvdata(dev);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (bridge->driver == &via_agp3_driver)
49762306a36Sopenharmony_ci		return via_configure_agp3();
49862306a36Sopenharmony_ci	else if (bridge->driver == &via_driver)
49962306a36Sopenharmony_ci		return via_configure();
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return 0;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/* must be the same order as name table above */
50562306a36Sopenharmony_cistatic const struct pci_device_id agp_via_pci_table[] = {
50662306a36Sopenharmony_ci#define ID(x) \
50762306a36Sopenharmony_ci	{						\
50862306a36Sopenharmony_ci	.class		= (PCI_CLASS_BRIDGE_HOST << 8),	\
50962306a36Sopenharmony_ci	.class_mask	= ~0,				\
51062306a36Sopenharmony_ci	.vendor		= PCI_VENDOR_ID_VIA,		\
51162306a36Sopenharmony_ci	.device		= x,				\
51262306a36Sopenharmony_ci	.subvendor	= PCI_ANY_ID,			\
51362306a36Sopenharmony_ci	.subdevice	= PCI_ANY_ID,			\
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_82C597_0),
51662306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_82C598_0),
51762306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8501_0),
51862306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8601_0),
51962306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_82C691_0),
52062306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8371_0),
52162306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8633_0),
52262306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_XN266),
52362306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8361),
52462306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8363_0),
52562306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8753_0),
52662306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8367_0),
52762306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8653_0),
52862306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_XM266),
52962306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_862X_0),
53062306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8377_0),
53162306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8605_0),
53262306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8703_51_0),
53362306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8754C_0),
53462306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8763_0),
53562306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8378_0),
53662306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_PT880),
53762306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_PT880ULTRA),
53862306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_8783_0),
53962306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_PX8X0_0),
54062306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_3269_0),
54162306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_83_87XX_1),
54262306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_3296_0),
54362306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_P4M800CE),
54462306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_VT3324),
54562306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_P4M890),
54662306a36Sopenharmony_ci	ID(PCI_DEVICE_ID_VIA_VT3364),
54762306a36Sopenharmony_ci	{ }
54862306a36Sopenharmony_ci};
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, agp_via_pci_table);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(agp_via_pm_ops, NULL, agp_via_resume);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic struct pci_driver agp_via_pci_driver = {
55562306a36Sopenharmony_ci	.name		= "agpgart-via",
55662306a36Sopenharmony_ci	.id_table	= agp_via_pci_table,
55762306a36Sopenharmony_ci	.probe		= agp_via_probe,
55862306a36Sopenharmony_ci	.remove		= agp_via_remove,
55962306a36Sopenharmony_ci	.driver.pm      = &agp_via_pm_ops,
56062306a36Sopenharmony_ci};
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic int __init agp_via_init(void)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	if (agp_off)
56662306a36Sopenharmony_ci		return -EINVAL;
56762306a36Sopenharmony_ci	return pci_register_driver(&agp_via_pci_driver);
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic void __exit agp_via_cleanup(void)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	pci_unregister_driver(&agp_via_pci_driver);
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cimodule_init(agp_via_init);
57662306a36Sopenharmony_cimodule_exit(agp_via_cleanup);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
57962306a36Sopenharmony_ciMODULE_AUTHOR("Dave Jones");
580