ati-agp.c revision 0ea27d9f2fb5b998063323bff47ab87891ced9e2
1/*
2 * ATi 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/agp.h>
11#include "agp.h"
12
13#define ATI_GART_MMBASE_ADDR	0x14
14#define ATI_RS100_APSIZE	0xac
15#define ATI_RS100_IG_AGPMODE	0xb0
16#define ATI_RS300_APSIZE	0xf8
17#define ATI_RS300_IG_AGPMODE	0xfc
18#define ATI_GART_FEATURE_ID		0x00
19#define ATI_GART_BASE			0x04
20#define ATI_GART_CACHE_SZBASE		0x08
21#define ATI_GART_CACHE_CNTRL		0x0c
22#define ATI_GART_CACHE_ENTRY_CNTRL	0x10
23
24
25static struct aper_size_info_lvl2 ati_generic_sizes[7] =
26{
27	{2048, 524288, 0x0000000c},
28	{1024, 262144, 0x0000000a},
29	{512, 131072, 0x00000008},
30	{256, 65536, 0x00000006},
31	{128, 32768, 0x00000004},
32	{64, 16384, 0x00000002},
33	{32, 8192, 0x00000000}
34};
35
36static struct gatt_mask ati_generic_masks[] =
37{
38	{ .mask = 1, .type = 0}
39};
40
41
42
43typedef struct _ati_page_map {
44	unsigned long *real;
45	unsigned long __iomem *remapped;
46} ati_page_map;
47
48static struct _ati_generic_private {
49	volatile u8 __iomem *registers;
50	ati_page_map **gatt_pages;
51	int num_tables;
52} ati_generic_private;
53
54static int ati_create_page_map(ati_page_map *page_map)
55{
56	int i, err = 0;
57
58	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
59	if (page_map->real == NULL)
60		return -ENOMEM;
61
62	SetPageReserved(virt_to_page(page_map->real));
63	err = map_page_into_agp(virt_to_page(page_map->real));
64	page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
65					    PAGE_SIZE);
66	if (page_map->remapped == NULL || err) {
67		ClearPageReserved(virt_to_page(page_map->real));
68		free_page((unsigned long) page_map->real);
69		page_map->real = NULL;
70		return -ENOMEM;
71	}
72	/*CACHE_FLUSH();*/
73	global_cache_flush();
74
75	for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
76		writel(agp_bridge->scratch_page, page_map->remapped+i);
77		readl(page_map->remapped+i);	/* PCI Posting. */
78	}
79
80	return 0;
81}
82
83
84static void ati_free_page_map(ati_page_map *page_map)
85{
86	unmap_page_from_agp(virt_to_page(page_map->real));
87	iounmap(page_map->remapped);
88	ClearPageReserved(virt_to_page(page_map->real));
89	free_page((unsigned long) page_map->real);
90}
91
92
93static void ati_free_gatt_pages(void)
94{
95	int i;
96	ati_page_map **tables;
97	ati_page_map *entry;
98
99	tables = ati_generic_private.gatt_pages;
100	for(i = 0; i < ati_generic_private.num_tables; i++) {
101		entry = tables[i];
102		if (entry != NULL) {
103			if (entry->real != NULL)
104				ati_free_page_map(entry);
105			kfree(entry);
106		}
107	}
108	kfree(tables);
109}
110
111
112static int ati_create_gatt_pages(int nr_tables)
113{
114	ati_page_map **tables;
115	ati_page_map *entry;
116	int retval = 0;
117	int i;
118
119	tables = kzalloc((nr_tables + 1) * sizeof(ati_page_map *),GFP_KERNEL);
120	if (tables == NULL)
121		return -ENOMEM;
122
123	for (i = 0; i < nr_tables; i++) {
124		entry = kzalloc(sizeof(ati_page_map), GFP_KERNEL);
125		if (entry == NULL) {
126			while (i>0) {
127				kfree (tables[i-1]);
128				i--;
129			}
130			kfree (tables);
131			tables = NULL;
132			retval = -ENOMEM;
133			break;
134		}
135		tables[i] = entry;
136		retval = ati_create_page_map(entry);
137		if (retval != 0) break;
138	}
139	ati_generic_private.num_tables = nr_tables;
140	ati_generic_private.gatt_pages = tables;
141
142	if (retval != 0) ati_free_gatt_pages();
143
144	return retval;
145}
146
147static int is_r200(void)
148{
149	if ((agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS100) ||
150	    (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200) ||
151	    (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200_B) ||
152	    (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS250))
153		return 1;
154	return 0;
155}
156
157static int ati_fetch_size(void)
158{
159	int i;
160	u32 temp;
161	struct aper_size_info_lvl2 *values;
162
163	if (is_r200())
164		pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
165	else
166		pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
167
168	temp = (temp & 0x0000000e);
169	values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes);
170	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
171		if (temp == values[i].size_value) {
172			agp_bridge->previous_size =
173			    agp_bridge->current_size = (void *) (values + i);
174
175			agp_bridge->aperture_size_idx = i;
176			return values[i].size;
177		}
178	}
179
180	return 0;
181}
182
183static void ati_tlbflush(struct agp_memory * mem)
184{
185	writel(1, ati_generic_private.registers+ATI_GART_CACHE_CNTRL);
186	readl(ati_generic_private.registers+ATI_GART_CACHE_CNTRL);	/* PCI Posting. */
187}
188
189static void ati_cleanup(void)
190{
191	struct aper_size_info_lvl2 *previous_size;
192	u32 temp;
193
194	previous_size = A_SIZE_LVL2(agp_bridge->previous_size);
195
196	/* Write back the previous size and disable gart translation */
197	if (is_r200()) {
198		pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
199		temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
200		pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp);
201	} else {
202		pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
203		temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
204		pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp);
205	}
206	iounmap((volatile u8 __iomem *)ati_generic_private.registers);
207}
208
209
210static int ati_configure(void)
211{
212	u32 temp;
213
214	/* Get the memory mapped registers */
215	pci_read_config_dword(agp_bridge->dev, ATI_GART_MMBASE_ADDR, &temp);
216	temp = (temp & 0xfffff000);
217	ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
218
219	if (is_r200())
220       	pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
221	else
222		pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000);
223
224	/* address to map too */
225        /*
226	pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp);
227	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
228	printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr);
229        */
230	writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID);
231	readl(ati_generic_private.registers+ATI_GART_FEATURE_ID);	/* PCI Posting.*/
232
233	/* SIGNALED_SYSTEM_ERROR @ NB_STATUS */
234	pci_read_config_dword(agp_bridge->dev, 4, &temp);
235	pci_write_config_dword(agp_bridge->dev, 4, temp | (1<<14));
236
237	/* Write out the address of the gatt table */
238	writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE);
239	readl(ati_generic_private.registers+ATI_GART_BASE);	/* PCI Posting. */
240
241	return 0;
242}
243
244
245/*
246 *Since we don't need contigious memory we just try
247 * to get the gatt table once
248 */
249
250#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
251#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
252	GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr))
253#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
254#undef  GET_GATT
255#define GET_GATT(addr) (ati_generic_private.gatt_pages[\
256	GET_PAGE_DIR_IDX(addr)]->remapped)
257
258static int ati_insert_memory(struct agp_memory * mem,
259			     off_t pg_start, int type)
260{
261	int i, j, num_entries;
262	unsigned long __iomem *cur_gatt;
263	unsigned long addr;
264
265	num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
266
267	if (type != 0 || mem->type != 0)
268		return -EINVAL;
269
270	if ((pg_start + mem->page_count) > num_entries)
271		return -EINVAL;
272
273	j = pg_start;
274	while (j < (pg_start + mem->page_count)) {
275		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
276		cur_gatt = GET_GATT(addr);
277		if (!PGE_EMPTY(agp_bridge,readl(cur_gatt+GET_GATT_OFF(addr))))
278			return -EBUSY;
279		j++;
280	}
281
282	if (mem->is_flushed == FALSE) {
283		/*CACHE_FLUSH(); */
284		global_cache_flush();
285		mem->is_flushed = TRUE;
286	}
287
288	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
289		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
290		cur_gatt = GET_GATT(addr);
291		writel(agp_bridge->driver->mask_memory(agp_bridge,
292			mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
293		readl(cur_gatt+GET_GATT_OFF(addr));	/* PCI Posting. */
294	}
295	agp_bridge->driver->tlb_flush(mem);
296	return 0;
297}
298
299static int ati_remove_memory(struct agp_memory * mem, off_t pg_start,
300			     int type)
301{
302	int i;
303	unsigned long __iomem *cur_gatt;
304	unsigned long addr;
305
306	if (type != 0 || mem->type != 0) {
307		return -EINVAL;
308	}
309	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
310		addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
311		cur_gatt = GET_GATT(addr);
312		writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
313		readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */
314	}
315
316	agp_bridge->driver->tlb_flush(mem);
317	return 0;
318}
319
320static int ati_create_gatt_table(struct agp_bridge_data *bridge)
321{
322	struct aper_size_info_lvl2 *value;
323	ati_page_map page_dir;
324	unsigned long addr;
325	int retval;
326	u32 temp;
327	int i;
328	struct aper_size_info_lvl2 *current_size;
329
330	value = A_SIZE_LVL2(agp_bridge->current_size);
331	retval = ati_create_page_map(&page_dir);
332	if (retval != 0)
333		return retval;
334
335	retval = ati_create_gatt_pages(value->num_entries / 1024);
336	if (retval != 0) {
337		ati_free_page_map(&page_dir);
338		return retval;
339	}
340
341	agp_bridge->gatt_table_real = (u32 *)page_dir.real;
342	agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped;
343	agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
344
345	/* Write out the size register */
346	current_size = A_SIZE_LVL2(agp_bridge->current_size);
347
348	if (is_r200()) {
349		pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
350		temp = (((temp & ~(0x0000000e)) | current_size->size_value)
351			| 0x00000001);
352		pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp);
353		pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
354	} else {
355		pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
356		temp = (((temp & ~(0x0000000e)) | current_size->size_value)
357			| 0x00000001);
358		pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp);
359		pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
360	}
361
362	/*
363	 * Get the address for the gart region.
364	 * This is a bus address even on the alpha, b/c its
365	 * used to program the agp master not the cpu
366	 */
367	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
368	addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
369	agp_bridge->gart_bus_addr = addr;
370
371	/* Calculate the agp offset */
372	for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
373		writel(virt_to_gart(ati_generic_private.gatt_pages[i]->real) | 1,
374			page_dir.remapped+GET_PAGE_DIR_OFF(addr));
375		readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));	/* PCI Posting. */
376	}
377
378	return 0;
379}
380
381static int ati_free_gatt_table(struct agp_bridge_data *bridge)
382{
383	ati_page_map page_dir;
384
385	page_dir.real = (unsigned long *)agp_bridge->gatt_table_real;
386	page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table;
387
388	ati_free_gatt_pages();
389	ati_free_page_map(&page_dir);
390	return 0;
391}
392
393static struct agp_bridge_driver ati_generic_bridge = {
394	.owner			= THIS_MODULE,
395	.aperture_sizes		= ati_generic_sizes,
396	.size_type		= LVL2_APER_SIZE,
397	.num_aperture_sizes	= 7,
398	.configure		= ati_configure,
399	.fetch_size		= ati_fetch_size,
400	.cleanup		= ati_cleanup,
401	.tlb_flush		= ati_tlbflush,
402	.mask_memory		= agp_generic_mask_memory,
403	.masks			= ati_generic_masks,
404	.agp_enable		= agp_generic_enable,
405	.cache_flush		= global_cache_flush,
406	.create_gatt_table	= ati_create_gatt_table,
407	.free_gatt_table	= ati_free_gatt_table,
408	.insert_memory		= ati_insert_memory,
409	.remove_memory		= ati_remove_memory,
410	.alloc_by_type		= agp_generic_alloc_by_type,
411	.free_by_type		= agp_generic_free_by_type,
412	.agp_alloc_page		= agp_generic_alloc_page,
413	.agp_destroy_page	= agp_generic_destroy_page,
414};
415
416
417static struct agp_device_ids ati_agp_device_ids[] __devinitdata =
418{
419	{
420		.device_id	= PCI_DEVICE_ID_ATI_RS100,
421		.chipset_name	= "IGP320/M",
422	},
423	{
424		.device_id	= PCI_DEVICE_ID_ATI_RS200,
425		.chipset_name	= "IGP330/340/345/350/M",
426	},
427	{
428		.device_id	= PCI_DEVICE_ID_ATI_RS200_B,
429		.chipset_name	= "IGP345M",
430	},
431	{
432		.device_id	= PCI_DEVICE_ID_ATI_RS250,
433		.chipset_name	= "IGP7000/M",
434	},
435	{
436		.device_id	= PCI_DEVICE_ID_ATI_RS300_100,
437		.chipset_name	= "IGP9100/M",
438	},
439	{
440		.device_id	= PCI_DEVICE_ID_ATI_RS300_133,
441		.chipset_name	= "IGP9100/M",
442	},
443	{
444		.device_id	= PCI_DEVICE_ID_ATI_RS300_166,
445		.chipset_name	= "IGP9100/M",
446	},
447	{
448		.device_id	= PCI_DEVICE_ID_ATI_RS300_200,
449		.chipset_name	= "IGP9100/M",
450	},
451	{ }, /* dummy final entry, always present */
452};
453
454static int __devinit agp_ati_probe(struct pci_dev *pdev,
455				   const struct pci_device_id *ent)
456{
457	struct agp_device_ids *devs = ati_agp_device_ids;
458	struct agp_bridge_data *bridge;
459	u8 cap_ptr;
460	int j;
461
462	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
463	if (!cap_ptr)
464		return -ENODEV;
465
466	/* probe for known chipsets */
467	for (j = 0; devs[j].chipset_name; j++) {
468		if (pdev->device == devs[j].device_id)
469			goto found;
470	}
471
472	printk(KERN_ERR PFX
473	     "Unsupported Ati chipset (device id: %04x)\n", pdev->device);
474	return -ENODEV;
475
476found:
477	bridge = agp_alloc_bridge();
478	if (!bridge)
479		return -ENOMEM;
480
481	bridge->dev = pdev;
482	bridge->capndx = cap_ptr;
483
484	bridge->driver = &ati_generic_bridge;
485
486
487	printk(KERN_INFO PFX "Detected Ati %s chipset\n",
488			devs[j].chipset_name);
489
490	/* Fill in the mode register */
491	pci_read_config_dword(pdev,
492			bridge->capndx+PCI_AGP_STATUS,
493			&bridge->mode);
494
495	pci_set_drvdata(pdev, bridge);
496	return agp_add_bridge(bridge);
497}
498
499static void __devexit agp_ati_remove(struct pci_dev *pdev)
500{
501	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
502
503	agp_remove_bridge(bridge);
504	agp_put_bridge(bridge);
505}
506
507static struct pci_device_id agp_ati_pci_table[] = {
508	{
509	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
510	.class_mask	= ~0,
511	.vendor		= PCI_VENDOR_ID_ATI,
512	.device		= PCI_ANY_ID,
513	.subvendor	= PCI_ANY_ID,
514	.subdevice	= PCI_ANY_ID,
515	},
516	{ }
517};
518
519MODULE_DEVICE_TABLE(pci, agp_ati_pci_table);
520
521static struct pci_driver agp_ati_pci_driver = {
522	.name		= "agpgart-ati",
523	.id_table	= agp_ati_pci_table,
524	.probe		= agp_ati_probe,
525	.remove		= agp_ati_remove,
526};
527
528static int __init agp_ati_init(void)
529{
530	if (agp_off)
531		return -EINVAL;
532	return pci_register_driver(&agp_ati_pci_driver);
533}
534
535static void __exit agp_ati_cleanup(void)
536{
537	pci_unregister_driver(&agp_ati_pci_driver);
538}
539
540module_init(agp_ati_init);
541module_exit(agp_ati_cleanup);
542
543MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
544MODULE_LICENSE("GPL and additional rights");
545
546