PageRenderTime 52ms CodeModel.GetById 8ms app.highlight 38ms RepoModel.GetById 2ms app.codeStats 0ms

/drivers/char/agp/uninorth-agp.c

https://bitbucket.org/evzijst/gittest
C | 647 lines | 491 code | 97 blank | 59 comment | 76 complexity | 54b5fe835cc4f7da7010ddbcb05a8df1 MD5 | raw file
  1/*
  2 * UniNorth AGPGART routines.
  3 */
  4#include <linux/module.h>
  5#include <linux/pci.h>
  6#include <linux/init.h>
  7#include <linux/pagemap.h>
  8#include <linux/agp_backend.h>
  9#include <linux/delay.h>
 10#include <asm/uninorth.h>
 11#include <asm/pci-bridge.h>
 12#include <asm/prom.h>
 13#include "agp.h"
 14
 15/*
 16 * NOTES for uninorth3 (G5 AGP) supports :
 17 *
 18 * There maybe also possibility to have bigger cache line size for
 19 * agp (see pmac_pci.c and look for cache line). Need to be investigated
 20 * by someone.
 21 *
 22 * PAGE size are hardcoded but this may change, see asm/page.h.
 23 *
 24 * Jerome Glisse <j.glisse@gmail.com>
 25 */
 26static int uninorth_rev;
 27static int is_u3;
 28
 29static int uninorth_fetch_size(void)
 30{
 31	int i;
 32	u32 temp;
 33	struct aper_size_info_32 *values;
 34
 35	pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_BASE, &temp);
 36	temp &= ~(0xfffff000);
 37	values = A_SIZE_32(agp_bridge->driver->aperture_sizes);
 38
 39	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 40		if (temp == values[i].size_value) {
 41			agp_bridge->previous_size =
 42			    agp_bridge->current_size = (void *) (values + i);
 43			agp_bridge->aperture_size_idx = i;
 44			return values[i].size;
 45		}
 46	}
 47
 48	agp_bridge->previous_size =
 49	    agp_bridge->current_size = (void *) (values + 1);
 50	agp_bridge->aperture_size_idx = 1;
 51	return values[1].size;
 52
 53	return 0;
 54}
 55
 56static void uninorth_tlbflush(struct agp_memory *mem)
 57{
 58	u32 ctrl = UNI_N_CFG_GART_ENABLE;
 59
 60	if (is_u3)
 61		ctrl |= U3_N_CFG_GART_PERFRD;
 62	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
 63			       ctrl | UNI_N_CFG_GART_INVAL);
 64	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, ctrl);
 65
 66	if (uninorth_rev <= 0x30) {
 67		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
 68				       ctrl | UNI_N_CFG_GART_2xRESET);
 69		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
 70				       ctrl);
 71	}
 72}
 73
 74static void uninorth_cleanup(void)
 75{
 76	u32 tmp;
 77
 78	pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, &tmp);
 79	if (!(tmp & UNI_N_CFG_GART_ENABLE))
 80		return;
 81	tmp |= UNI_N_CFG_GART_INVAL;
 82	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, tmp);
 83	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, 0);
 84
 85	if (uninorth_rev <= 0x30) {
 86		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
 87				       UNI_N_CFG_GART_2xRESET);
 88		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
 89				       0);
 90	}
 91}
 92
 93static int uninorth_configure(void)
 94{
 95	struct aper_size_info_32 *current_size;
 96	
 97	current_size = A_SIZE_32(agp_bridge->current_size);
 98
 99	printk(KERN_INFO PFX "configuring for size idx: %d\n",
100	       current_size->size_value);
101	
102	/* aperture size and gatt addr */
103	pci_write_config_dword(agp_bridge->dev,
104		UNI_N_CFG_GART_BASE,
105		(agp_bridge->gatt_bus_addr & 0xfffff000)
106			| current_size->size_value);
107
108	/* HACK ALERT
109	 * UniNorth seem to be buggy enough not to handle properly when
110	 * the AGP aperture isn't mapped at bus physical address 0
111	 */
112	agp_bridge->gart_bus_addr = 0;
113#ifdef CONFIG_PPC64
114	/* Assume U3 or later on PPC64 systems */
115	/* high 4 bits of GART physical address go in UNI_N_CFG_AGP_BASE */
116	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_AGP_BASE,
117			       (agp_bridge->gatt_bus_addr >> 32) & 0xf);
118#else
119	pci_write_config_dword(agp_bridge->dev,
120		UNI_N_CFG_AGP_BASE, agp_bridge->gart_bus_addr);
121#endif
122
123	if (is_u3) {
124		pci_write_config_dword(agp_bridge->dev,
125				       UNI_N_CFG_GART_DUMMY_PAGE,
126				       agp_bridge->scratch_page_real >> 12);
127	}
128	
129	return 0;
130}
131
132static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start,
133				int type)
134{
135	int i, j, num_entries;
136	void *temp;
137
138	temp = agp_bridge->current_size;
139	num_entries = A_SIZE_32(temp)->num_entries;
140
141	if (type != 0 || mem->type != 0)
142		/* We know nothing of memory types */
143		return -EINVAL;
144	if ((pg_start + mem->page_count) > num_entries)
145		return -EINVAL;
146
147	j = pg_start;
148
149	while (j < (pg_start + mem->page_count)) {
150		if (agp_bridge->gatt_table[j])
151			return -EBUSY;
152		j++;
153	}
154
155	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
156		agp_bridge->gatt_table[j] =
157		    cpu_to_le32((mem->memory[i] & 0xFFFFF000UL) | 0x1UL);
158		flush_dcache_range((unsigned long)__va(mem->memory[i]),
159				   (unsigned long)__va(mem->memory[i])+0x1000);
160	}
161	(void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]);
162	mb();
163	flush_dcache_range((unsigned long)&agp_bridge->gatt_table[pg_start], 
164		(unsigned long)&agp_bridge->gatt_table[pg_start + mem->page_count]);
165
166	uninorth_tlbflush(mem);
167	return 0;
168}
169
170static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
171{
172	int i, num_entries;
173	void *temp;
174	u32 *gp;
175
176	temp = agp_bridge->current_size;
177	num_entries = A_SIZE_32(temp)->num_entries;
178
179	if (type != 0 || mem->type != 0)
180		/* We know nothing of memory types */
181		return -EINVAL;
182	if ((pg_start + mem->page_count) > num_entries)
183		return -EINVAL;
184
185	gp = (u32 *) &agp_bridge->gatt_table[pg_start];
186	for (i = 0; i < mem->page_count; ++i) {
187		if (gp[i]) {
188			printk("u3_insert_memory: entry 0x%x occupied (%x)\n",
189			       i, gp[i]);
190			return -EBUSY;
191		}
192	}
193
194	for (i = 0; i < mem->page_count; i++) {
195		gp[i] = (mem->memory[i] >> PAGE_SHIFT) | 0x80000000UL;
196		flush_dcache_range((unsigned long)__va(mem->memory[i]),
197				   (unsigned long)__va(mem->memory[i])+0x1000);
198	}
199	mb();
200	flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
201	uninorth_tlbflush(mem);
202
203	return 0;
204}
205
206int u3_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
207{
208	size_t i;
209	u32 *gp;
210
211	if (type != 0 || mem->type != 0)
212		/* We know nothing of memory types */
213		return -EINVAL;
214
215	gp = (u32 *) &agp_bridge->gatt_table[pg_start];
216	for (i = 0; i < mem->page_count; ++i)
217		gp[i] = 0;
218	mb();
219	flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
220	uninorth_tlbflush(mem);
221
222	return 0;
223}
224
225static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode)
226{
227	u32 command, scratch, status;
228	int timeout;
229
230	pci_read_config_dword(bridge->dev,
231			      bridge->capndx + PCI_AGP_STATUS,
232			      &status);
233
234	command = agp_collect_device_status(bridge, mode, status);
235	command |= PCI_AGP_COMMAND_AGP;
236	
237	if (uninorth_rev == 0x21) {
238		/*
239		 * Darwin disable AGP 4x on this revision, thus we
240		 * may assume it's broken. This is an AGP2 controller.
241		 */
242		command &= ~AGPSTAT2_4X;
243	}
244
245	if ((uninorth_rev >= 0x30) && (uninorth_rev <= 0x33)) {
246		/*
247		 * We need to to set REQ_DEPTH to 7 for U3 versions 1.0, 2.1,
248		 * 2.2 and 2.3, Darwin do so.
249		 */
250		if ((command >> AGPSTAT_RQ_DEPTH_SHIFT) > 7)
251			command = (command & ~AGPSTAT_RQ_DEPTH)
252				| (7 << AGPSTAT_RQ_DEPTH_SHIFT);
253	}
254
255	uninorth_tlbflush(NULL);
256
257	timeout = 0;
258	do {
259		pci_write_config_dword(bridge->dev,
260				       bridge->capndx + PCI_AGP_COMMAND,
261				       command);
262		pci_read_config_dword(bridge->dev,
263				      bridge->capndx + PCI_AGP_COMMAND,
264				       &scratch);
265	} while ((scratch & PCI_AGP_COMMAND_AGP) == 0 && ++timeout < 1000);
266	if ((scratch & PCI_AGP_COMMAND_AGP) == 0)
267		printk(KERN_ERR PFX "failed to write UniNorth AGP command reg\n");
268
269	if (uninorth_rev >= 0x30) {
270		/* This is an AGP V3 */
271		agp_device_command(command, (status & AGPSTAT_MODE_3_0));
272	} else {
273		/* AGP V2 */
274		agp_device_command(command, 0);
275	}
276
277	uninorth_tlbflush(NULL);
278}
279
280#ifdef CONFIG_PM
281static int agp_uninorth_suspend(struct pci_dev *pdev, pm_message_t state)
282{
283	u32 cmd;
284	u8 agp;
285	struct pci_dev *device = NULL;
286
287	if (state != PMSG_SUSPEND)
288		return 0;
289
290	/* turn off AGP on the video chip, if it was enabled */
291	for_each_pci_dev(device) {
292		/* Don't touch the bridge yet, device first */
293		if (device == pdev)
294			continue;
295		/* Only deal with devices on the same bus here, no Mac has a P2P
296		 * bridge on the AGP port, and mucking around the entire PCI
297		 * tree is source of problems on some machines because of a bug
298		 * in some versions of pci_find_capability() when hitting a dead
299		 * device
300		 */
301		if (device->bus != pdev->bus)
302			continue;
303		agp = pci_find_capability(device, PCI_CAP_ID_AGP);
304		if (!agp)
305			continue;
306		pci_read_config_dword(device, agp + PCI_AGP_COMMAND, &cmd);
307		if (!(cmd & PCI_AGP_COMMAND_AGP))
308			continue;
309		printk("uninorth-agp: disabling AGP on device %s\n",
310				pci_name(device));
311		cmd &= ~PCI_AGP_COMMAND_AGP;
312		pci_write_config_dword(device, agp + PCI_AGP_COMMAND, cmd);
313	}
314
315	/* turn off AGP on the bridge */
316	agp = pci_find_capability(pdev, PCI_CAP_ID_AGP);
317	pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd);
318	if (cmd & PCI_AGP_COMMAND_AGP) {
319		printk("uninorth-agp: disabling AGP on bridge %s\n",
320				pci_name(pdev));
321		cmd &= ~PCI_AGP_COMMAND_AGP;
322		pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND, cmd);
323	}
324	/* turn off the GART */
325	uninorth_cleanup();
326
327	return 0;
328}
329
330static int agp_uninorth_resume(struct pci_dev *pdev)
331{
332	return 0;
333}
334#endif
335
336static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
337{
338	char *table;
339	char *table_end;
340	int size;
341	int page_order;
342	int num_entries;
343	int i;
344	void *temp;
345	struct page *page;
346
347	/* We can't handle 2 level gatt's */
348	if (bridge->driver->size_type == LVL2_APER_SIZE)
349		return -EINVAL;
350
351	table = NULL;
352	i = bridge->aperture_size_idx;
353	temp = bridge->current_size;
354	size = page_order = num_entries = 0;
355
356	do {
357		size = A_SIZE_32(temp)->size;
358		page_order = A_SIZE_32(temp)->page_order;
359		num_entries = A_SIZE_32(temp)->num_entries;
360
361		table = (char *) __get_free_pages(GFP_KERNEL, page_order);
362
363		if (table == NULL) {
364			i++;
365			bridge->current_size = A_IDX32(bridge);
366		} else {
367			bridge->aperture_size_idx = i;
368		}
369	} while (!table && (i < bridge->driver->num_aperture_sizes));
370
371	if (table == NULL)
372		return -ENOMEM;
373
374	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
375
376	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
377		SetPageReserved(page);
378
379	bridge->gatt_table_real = (u32 *) table;
380	bridge->gatt_table = (u32 *)table;
381	bridge->gatt_bus_addr = virt_to_phys(table);
382
383	for (i = 0; i < num_entries; i++)
384		bridge->gatt_table[i] = 0;
385
386	flush_dcache_range((unsigned long)table, (unsigned long)table_end);
387
388	return 0;
389}
390
391static int uninorth_free_gatt_table(struct agp_bridge_data *bridge)
392{
393	int page_order;
394	char *table, *table_end;
395	void *temp;
396	struct page *page;
397
398	temp = bridge->current_size;
399	page_order = A_SIZE_32(temp)->page_order;
400
401	/* Do not worry about freeing memory, because if this is
402	 * called, then all agp memory is deallocated and removed
403	 * from the table.
404	 */
405
406	table = (char *) bridge->gatt_table_real;
407	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
408
409	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
410		ClearPageReserved(page);
411
412	free_pages((unsigned long) bridge->gatt_table_real, page_order);
413
414	return 0;
415}
416
417void null_cache_flush(void)
418{
419	mb();
420}
421
422/* Setup function */
423
424static struct aper_size_info_32 uninorth_sizes[7] =
425{
426#if 0 /* Not sure uninorth supports that high aperture sizes */
427	{256, 65536, 6, 64},
428	{128, 32768, 5, 32},
429	{64, 16384, 4, 16},
430#endif	
431	{32, 8192, 3, 8},
432	{16, 4096, 2, 4},
433	{8, 2048, 1, 2},
434	{4, 1024, 0, 1}
435};
436
437/*
438 * Not sure that u3 supports that high aperture sizes but it
439 * would strange if it did not :)
440 */
441static struct aper_size_info_32 u3_sizes[8] =
442{
443	{512, 131072, 7, 128},
444	{256, 65536, 6, 64},
445	{128, 32768, 5, 32},
446	{64, 16384, 4, 16},
447	{32, 8192, 3, 8},
448	{16, 4096, 2, 4},
449	{8, 2048, 1, 2},
450	{4, 1024, 0, 1}
451};
452
453struct agp_bridge_driver uninorth_agp_driver = {
454	.owner			= THIS_MODULE,
455	.aperture_sizes		= (void *)uninorth_sizes,
456	.size_type		= U32_APER_SIZE,
457	.num_aperture_sizes	= 4,
458	.configure		= uninorth_configure,
459	.fetch_size		= uninorth_fetch_size,
460	.cleanup		= uninorth_cleanup,
461	.tlb_flush		= uninorth_tlbflush,
462	.mask_memory		= agp_generic_mask_memory,
463	.masks			= NULL,
464	.cache_flush		= null_cache_flush,
465	.agp_enable		= uninorth_agp_enable,
466	.create_gatt_table	= uninorth_create_gatt_table,
467	.free_gatt_table	= uninorth_free_gatt_table,
468	.insert_memory		= uninorth_insert_memory,
469	.remove_memory		= agp_generic_remove_memory,
470	.alloc_by_type		= agp_generic_alloc_by_type,
471	.free_by_type		= agp_generic_free_by_type,
472	.agp_alloc_page		= agp_generic_alloc_page,
473	.agp_destroy_page	= agp_generic_destroy_page,
474	.cant_use_aperture	= 1,
475};
476
477struct agp_bridge_driver u3_agp_driver = {
478	.owner			= THIS_MODULE,
479	.aperture_sizes		= (void *)u3_sizes,
480	.size_type		= U32_APER_SIZE,
481	.num_aperture_sizes	= 8,
482	.configure		= uninorth_configure,
483	.fetch_size		= uninorth_fetch_size,
484	.cleanup		= uninorth_cleanup,
485	.tlb_flush		= uninorth_tlbflush,
486	.mask_memory		= agp_generic_mask_memory,
487	.masks			= NULL,
488	.cache_flush		= null_cache_flush,
489	.agp_enable		= uninorth_agp_enable,
490	.create_gatt_table	= uninorth_create_gatt_table,
491	.free_gatt_table	= uninorth_free_gatt_table,
492	.insert_memory		= u3_insert_memory,
493	.remove_memory		= u3_remove_memory,
494	.alloc_by_type		= agp_generic_alloc_by_type,
495	.free_by_type		= agp_generic_free_by_type,
496	.agp_alloc_page		= agp_generic_alloc_page,
497	.agp_destroy_page	= agp_generic_destroy_page,
498	.cant_use_aperture	= 1,
499	.needs_scratch_page	= 1,
500};
501
502static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = {
503	{
504		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP,
505		.chipset_name	= "UniNorth",
506	},
507	{
508		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP_P,
509		.chipset_name	= "UniNorth/Pangea",
510	},
511	{
512		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP15,
513		.chipset_name	= "UniNorth 1.5",
514	},
515	{
516		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP2,
517		.chipset_name	= "UniNorth 2",
518	},
519	{
520		.device_id	= PCI_DEVICE_ID_APPLE_U3_AGP,
521		.chipset_name	= "U3",
522	},
523	{
524		.device_id	= PCI_DEVICE_ID_APPLE_U3L_AGP,
525		.chipset_name	= "U3L",
526	},
527	{
528		.device_id	= PCI_DEVICE_ID_APPLE_U3H_AGP,
529		.chipset_name	= "U3H",
530	},
531};
532
533static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
534					const struct pci_device_id *ent)
535{
536	struct agp_device_ids *devs = uninorth_agp_device_ids;
537	struct agp_bridge_data *bridge;
538	struct device_node *uninorth_node;
539	u8 cap_ptr;
540	int j;
541
542	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
543	if (cap_ptr == 0)
544		return -ENODEV;
545
546	/* probe for known chipsets */
547	for (j = 0; devs[j].chipset_name != NULL; ++j) {
548		if (pdev->device == devs[j].device_id) {
549			printk(KERN_INFO PFX "Detected Apple %s chipset\n",
550			       devs[j].chipset_name);
551			goto found;
552		}
553	}
554
555	printk(KERN_ERR PFX "Unsupported Apple chipset (device id: %04x).\n",
556		pdev->device);
557	return -ENODEV;
558
559 found:
560	/* Set revision to 0 if we could not read it. */
561	uninorth_rev = 0;
562	is_u3 = 0;
563	/* Locate core99 Uni-N */
564	uninorth_node = of_find_node_by_name(NULL, "uni-n");
565	/* Locate G5 u3 */
566	if (uninorth_node == NULL) {
567		is_u3 = 1;
568		uninorth_node = of_find_node_by_name(NULL, "u3");
569	}
570	if (uninorth_node) {
571		int *revprop = (int *)
572			get_property(uninorth_node, "device-rev", NULL);
573		if (revprop != NULL)
574			uninorth_rev = *revprop & 0x3f;
575		of_node_put(uninorth_node);
576	}
577
578	bridge = agp_alloc_bridge();
579	if (!bridge)
580		return -ENOMEM;
581
582	if (is_u3)
583		bridge->driver = &u3_agp_driver;
584	else
585		bridge->driver = &uninorth_agp_driver;
586
587	bridge->dev = pdev;
588	bridge->capndx = cap_ptr;
589	bridge->flags = AGP_ERRATA_FASTWRITES;
590
591	/* Fill in the mode register */
592	pci_read_config_dword(pdev, cap_ptr+PCI_AGP_STATUS, &bridge->mode);
593
594	pci_set_drvdata(pdev, bridge);
595	return agp_add_bridge(bridge);
596}
597
598static void __devexit agp_uninorth_remove(struct pci_dev *pdev)
599{
600	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
601
602	agp_remove_bridge(bridge);
603	agp_put_bridge(bridge);
604}
605
606static struct pci_device_id agp_uninorth_pci_table[] = {
607	{
608	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
609	.class_mask	= ~0,
610	.vendor		= PCI_VENDOR_ID_APPLE,
611	.device		= PCI_ANY_ID,
612	.subvendor	= PCI_ANY_ID,
613	.subdevice	= PCI_ANY_ID,
614	},
615	{ }
616};
617
618MODULE_DEVICE_TABLE(pci, agp_uninorth_pci_table);
619
620static struct pci_driver agp_uninorth_pci_driver = {
621	.name		= "agpgart-uninorth",
622	.id_table	= agp_uninorth_pci_table,
623	.probe		= agp_uninorth_probe,
624	.remove		= agp_uninorth_remove,
625#ifdef CONFIG_PM
626	.suspend	= agp_uninorth_suspend,
627	.resume		= agp_uninorth_resume,
628#endif
629};
630
631static int __init agp_uninorth_init(void)
632{
633	if (agp_off)
634		return -EINVAL;
635	return pci_register_driver(&agp_uninorth_pci_driver);
636}
637
638static void __exit agp_uninorth_cleanup(void)
639{
640	pci_unregister_driver(&agp_uninorth_pci_driver);
641}
642
643module_init(agp_uninorth_init);
644module_exit(agp_uninorth_cleanup);
645
646MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras");
647MODULE_LICENSE("GPL");