• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/char/agp/
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	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
89	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
90
91
92	pci_read_config_dword(agp_bridge->dev, ALI_TLBCTRL, &temp);
93	temp &= 0xffffff7f;		//enable TLB
94	pci_write_config_dword(agp_bridge->dev, ALI_TLBCTRL, temp);
95
96	return 0;
97}
98
99
100static void m1541_cache_flush(void)
101{
102	int i, page_count;
103	u32 temp;
104
105	global_cache_flush();
106
107	page_count = 1 << A_SIZE_32(agp_bridge->current_size)->page_order;
108	for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) {
109		pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
110				&temp);
111		pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
112				(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
113				  (agp_bridge->gatt_bus_addr + i)) |
114				 ALI_CACHE_FLUSH_EN));
115	}
116}
117
118static struct page *m1541_alloc_page(struct agp_bridge_data *bridge)
119{
120	struct page *page = agp_generic_alloc_page(agp_bridge);
121	u32 temp;
122
123	if (!page)
124		return NULL;
125
126	pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
127	pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
128			(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
129			  page_to_phys(page)) | ALI_CACHE_FLUSH_EN ));
130	return page;
131}
132
133static void ali_destroy_page(struct page *page, int flags)
134{
135	if (page) {
136		if (flags & AGP_PAGE_DESTROY_UNMAP) {
137			global_cache_flush();	/* is this really needed?  --hch */
138			agp_generic_destroy_page(page, flags);
139		} else
140			agp_generic_destroy_page(page, flags);
141	}
142}
143
144static void m1541_destroy_page(struct page *page, int flags)
145{
146	u32 temp;
147
148	if (page == NULL)
149		return;
150
151	if (flags & AGP_PAGE_DESTROY_UNMAP) {
152		global_cache_flush();
153
154		pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
155		pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
156				       (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
157					 page_to_phys(page)) | ALI_CACHE_FLUSH_EN));
158	}
159	agp_generic_destroy_page(page, flags);
160}
161
162
163/* Setup function */
164
165static const struct aper_size_info_32 ali_generic_sizes[7] =
166{
167	{256, 65536, 6, 10},
168	{128, 32768, 5, 9},
169	{64, 16384, 4, 8},
170	{32, 8192, 3, 7},
171	{16, 4096, 2, 6},
172	{8, 2048, 1, 4},
173	{4, 1024, 0, 3}
174};
175
176static const struct agp_bridge_driver ali_generic_bridge = {
177	.owner			= THIS_MODULE,
178	.aperture_sizes		= ali_generic_sizes,
179	.size_type		= U32_APER_SIZE,
180	.num_aperture_sizes	= 7,
181	.needs_scratch_page	= true,
182	.configure		= ali_configure,
183	.fetch_size		= ali_fetch_size,
184	.cleanup		= ali_cleanup,
185	.tlb_flush		= ali_tlbflush,
186	.mask_memory		= agp_generic_mask_memory,
187	.masks			= NULL,
188	.agp_enable		= agp_generic_enable,
189	.cache_flush		= global_cache_flush,
190	.create_gatt_table	= agp_generic_create_gatt_table,
191	.free_gatt_table	= agp_generic_free_gatt_table,
192	.insert_memory		= agp_generic_insert_memory,
193	.remove_memory		= agp_generic_remove_memory,
194	.alloc_by_type		= agp_generic_alloc_by_type,
195	.free_by_type		= agp_generic_free_by_type,
196	.agp_alloc_page		= agp_generic_alloc_page,
197	.agp_destroy_page	= ali_destroy_page,
198	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
199};
200
201static const struct agp_bridge_driver ali_m1541_bridge = {
202	.owner			= THIS_MODULE,
203	.aperture_sizes		= ali_generic_sizes,
204	.size_type		= U32_APER_SIZE,
205	.num_aperture_sizes	= 7,
206	.configure		= ali_configure,
207	.fetch_size		= ali_fetch_size,
208	.cleanup		= ali_cleanup,
209	.tlb_flush		= ali_tlbflush,
210	.mask_memory		= agp_generic_mask_memory,
211	.masks			= NULL,
212	.agp_enable		= agp_generic_enable,
213	.cache_flush		= m1541_cache_flush,
214	.create_gatt_table	= agp_generic_create_gatt_table,
215	.free_gatt_table	= agp_generic_free_gatt_table,
216	.insert_memory		= agp_generic_insert_memory,
217	.remove_memory		= agp_generic_remove_memory,
218	.alloc_by_type		= agp_generic_alloc_by_type,
219	.free_by_type		= agp_generic_free_by_type,
220	.agp_alloc_page		= m1541_alloc_page,
221	.agp_destroy_page	= m1541_destroy_page,
222	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
223};
224
225
226static struct agp_device_ids ali_agp_device_ids[] __devinitdata =
227{
228	{
229		.device_id	= PCI_DEVICE_ID_AL_M1541,
230		.chipset_name	= "M1541",
231	},
232	{
233		.device_id	= PCI_DEVICE_ID_AL_M1621,
234		.chipset_name	= "M1621",
235	},
236	{
237		.device_id	= PCI_DEVICE_ID_AL_M1631,
238		.chipset_name	= "M1631",
239	},
240	{
241		.device_id	= PCI_DEVICE_ID_AL_M1632,
242		.chipset_name	= "M1632",
243	},
244	{
245		.device_id	= PCI_DEVICE_ID_AL_M1641,
246		.chipset_name	= "M1641",
247	},
248	{
249		.device_id	= PCI_DEVICE_ID_AL_M1644,
250		.chipset_name	= "M1644",
251	},
252	{
253		.device_id	= PCI_DEVICE_ID_AL_M1647,
254		.chipset_name	= "M1647",
255	},
256	{
257		.device_id	= PCI_DEVICE_ID_AL_M1651,
258		.chipset_name	= "M1651",
259	},
260	{
261		.device_id	= PCI_DEVICE_ID_AL_M1671,
262		.chipset_name	= "M1671",
263	},
264	{
265		.device_id	= PCI_DEVICE_ID_AL_M1681,
266		.chipset_name	= "M1681",
267	},
268	{
269		.device_id	= PCI_DEVICE_ID_AL_M1683,
270		.chipset_name	= "M1683",
271	},
272
273	{ }, /* dummy final entry, always present */
274};
275
276static int __devinit agp_ali_probe(struct pci_dev *pdev,
277				const struct pci_device_id *ent)
278{
279	struct agp_device_ids *devs = ali_agp_device_ids;
280	struct agp_bridge_data *bridge;
281	u8 hidden_1621_id, cap_ptr;
282	int j;
283
284	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
285	if (!cap_ptr)
286		return -ENODEV;
287
288	/* probe for known chipsets */
289	for (j = 0; devs[j].chipset_name; j++) {
290		if (pdev->device == devs[j].device_id)
291			goto found;
292	}
293
294	dev_err(&pdev->dev, "unsupported ALi chipset [%04x/%04x])\n",
295		pdev->vendor, pdev->device);
296	return -ENODEV;
297
298
299found:
300	bridge = agp_alloc_bridge();
301	if (!bridge)
302		return -ENOMEM;
303
304	bridge->dev = pdev;
305	bridge->capndx = cap_ptr;
306
307	switch (pdev->device) {
308	case PCI_DEVICE_ID_AL_M1541:
309		bridge->driver = &ali_m1541_bridge;
310		break;
311	case PCI_DEVICE_ID_AL_M1621:
312		pci_read_config_byte(pdev, 0xFB, &hidden_1621_id);
313		switch (hidden_1621_id) {
314		case 0x31:
315			devs[j].chipset_name = "M1631";
316			break;
317		case 0x32:
318			devs[j].chipset_name = "M1632";
319			break;
320		case 0x41:
321			devs[j].chipset_name = "M1641";
322			break;
323		case 0x43:
324			devs[j].chipset_name = "M1621";
325			break;
326		case 0x47:
327			devs[j].chipset_name = "M1647";
328			break;
329		case 0x51:
330			devs[j].chipset_name = "M1651";
331			break;
332		default:
333			break;
334		}
335		/*FALLTHROUGH*/
336	default:
337		bridge->driver = &ali_generic_bridge;
338	}
339
340	dev_info(&pdev->dev, "ALi %s chipset\n", devs[j].chipset_name);
341
342	/* Fill in the mode register */
343	pci_read_config_dword(pdev,
344			bridge->capndx+PCI_AGP_STATUS,
345			&bridge->mode);
346
347	pci_set_drvdata(pdev, bridge);
348	return agp_add_bridge(bridge);
349}
350
351static void __devexit agp_ali_remove(struct pci_dev *pdev)
352{
353	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
354
355	agp_remove_bridge(bridge);
356	agp_put_bridge(bridge);
357}
358
359static struct pci_device_id agp_ali_pci_table[] = {
360	{
361	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
362	.class_mask	= ~0,
363	.vendor		= PCI_VENDOR_ID_AL,
364	.device		= PCI_ANY_ID,
365	.subvendor	= PCI_ANY_ID,
366	.subdevice	= PCI_ANY_ID,
367	},
368	{ }
369};
370
371MODULE_DEVICE_TABLE(pci, agp_ali_pci_table);
372
373static struct pci_driver agp_ali_pci_driver = {
374	.name		= "agpgart-ali",
375	.id_table	= agp_ali_pci_table,
376	.probe		= agp_ali_probe,
377	.remove		= agp_ali_remove,
378};
379
380static int __init agp_ali_init(void)
381{
382	if (agp_off)
383		return -EINVAL;
384	return pci_register_driver(&agp_ali_pci_driver);
385}
386
387static void __exit agp_ali_cleanup(void)
388{
389	pci_unregister_driver(&agp_ali_pci_driver);
390}
391
392module_init(agp_ali_init);
393module_exit(agp_ali_cleanup);
394
395MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
396MODULE_LICENSE("GPL and additional rights");
397