⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uninorth-agp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * UniNorth AGPGART routines. */#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/pagemap.h>#include <linux/agp_backend.h>#include <linux/delay.h>#include <asm/uninorth.h>#include <asm/pci-bridge.h>#include <asm/prom.h>#include <asm/pmac_feature.h>#include "agp.h"/* * NOTES for uninorth3 (G5 AGP) supports : * * There maybe also possibility to have bigger cache line size for * agp (see pmac_pci.c and look for cache line). Need to be investigated * by someone. * * PAGE size are hardcoded but this may change, see asm/page.h. * * Jerome Glisse <j.glisse@gmail.com> */static int uninorth_rev;static int is_u3;static int uninorth_fetch_size(void){	int i;	u32 temp;	struct aper_size_info_32 *values;	pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_BASE, &temp);	temp &= ~(0xfffff000);	values = A_SIZE_32(agp_bridge->driver->aperture_sizes);	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {		if (temp == values[i].size_value) {			agp_bridge->previous_size =			    agp_bridge->current_size = (void *) (values + i);			agp_bridge->aperture_size_idx = i;			return values[i].size;		}	}	agp_bridge->previous_size =	    agp_bridge->current_size = (void *) (values + 1);	agp_bridge->aperture_size_idx = 1;	return values[1].size;	return 0;}static void uninorth_tlbflush(struct agp_memory *mem){	u32 ctrl = UNI_N_CFG_GART_ENABLE;	if (is_u3)		ctrl |= U3_N_CFG_GART_PERFRD;	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,			       ctrl | UNI_N_CFG_GART_INVAL);	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, ctrl);	if (uninorth_rev <= 0x30) {		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,				       ctrl | UNI_N_CFG_GART_2xRESET);		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,				       ctrl);	}}static void uninorth_cleanup(void){	u32 tmp;	pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, &tmp);	if (!(tmp & UNI_N_CFG_GART_ENABLE))		return;	tmp |= UNI_N_CFG_GART_INVAL;	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, tmp);	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, 0);	if (uninorth_rev <= 0x30) {		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,				       UNI_N_CFG_GART_2xRESET);		pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,				       0);	}}static int uninorth_configure(void){	struct aper_size_info_32 *current_size;		current_size = A_SIZE_32(agp_bridge->current_size);	printk(KERN_INFO PFX "configuring for size idx: %d\n",	       current_size->size_value);		/* aperture size and gatt addr */	pci_write_config_dword(agp_bridge->dev,		UNI_N_CFG_GART_BASE,		(agp_bridge->gatt_bus_addr & 0xfffff000)			| current_size->size_value);	/* HACK ALERT	 * UniNorth seem to be buggy enough not to handle properly when	 * the AGP aperture isn't mapped at bus physical address 0	 */	agp_bridge->gart_bus_addr = 0;#ifdef CONFIG_PPC64	/* Assume U3 or later on PPC64 systems */	/* high 4 bits of GART physical address go in UNI_N_CFG_AGP_BASE */	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_AGP_BASE,			       (agp_bridge->gatt_bus_addr >> 32) & 0xf);#else	pci_write_config_dword(agp_bridge->dev,		UNI_N_CFG_AGP_BASE, agp_bridge->gart_bus_addr);#endif	if (is_u3) {		pci_write_config_dword(agp_bridge->dev,				       UNI_N_CFG_GART_DUMMY_PAGE,				       agp_bridge->scratch_page_real >> 12);	}		return 0;}static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start,				int type){	int i, j, num_entries;	void *temp;	temp = agp_bridge->current_size;	num_entries = A_SIZE_32(temp)->num_entries;	if (type != 0 || mem->type != 0)		/* We know nothing of memory types */		return -EINVAL;	if ((pg_start + mem->page_count) > num_entries)		return -EINVAL;	j = pg_start;	while (j < (pg_start + mem->page_count)) {		if (agp_bridge->gatt_table[j])			return -EBUSY;		j++;	}	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {		agp_bridge->gatt_table[j] =		    cpu_to_le32((mem->memory[i] & 0xFFFFF000UL) | 0x1UL);		flush_dcache_range((unsigned long)__va(mem->memory[i]),				   (unsigned long)__va(mem->memory[i])+0x1000);	}	(void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]);	mb();	flush_dcache_range((unsigned long)&agp_bridge->gatt_table[pg_start], 		(unsigned long)&agp_bridge->gatt_table[pg_start + mem->page_count]);	uninorth_tlbflush(mem);	return 0;}static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type){	int i, num_entries;	void *temp;	u32 *gp;	temp = agp_bridge->current_size;	num_entries = A_SIZE_32(temp)->num_entries;	if (type != 0 || mem->type != 0)		/* We know nothing of memory types */		return -EINVAL;	if ((pg_start + mem->page_count) > num_entries)		return -EINVAL;	gp = (u32 *) &agp_bridge->gatt_table[pg_start];	for (i = 0; i < mem->page_count; ++i) {		if (gp[i]) {			printk("u3_insert_memory: entry 0x%x occupied (%x)\n",			       i, gp[i]);			return -EBUSY;		}	}	for (i = 0; i < mem->page_count; i++) {		gp[i] = (mem->memory[i] >> PAGE_SHIFT) | 0x80000000UL;		flush_dcache_range((unsigned long)__va(mem->memory[i]),				   (unsigned long)__va(mem->memory[i])+0x1000);	}	mb();	flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);	uninorth_tlbflush(mem);	return 0;}int u3_remove_memory(struct agp_memory *mem, off_t pg_start, int type){	size_t i;	u32 *gp;	if (type != 0 || mem->type != 0)		/* We know nothing of memory types */		return -EINVAL;	gp = (u32 *) &agp_bridge->gatt_table[pg_start];	for (i = 0; i < mem->page_count; ++i)		gp[i] = 0;	mb();	flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);	uninorth_tlbflush(mem);	return 0;}static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode){	u32 command, scratch, status;	int timeout;	pci_read_config_dword(bridge->dev,			      bridge->capndx + PCI_AGP_STATUS,			      &status);	command = agp_collect_device_status(bridge, mode, status);	command |= PCI_AGP_COMMAND_AGP;		if (uninorth_rev == 0x21) {		/*		 * Darwin disable AGP 4x on this revision, thus we		 * may assume it's broken. This is an AGP2 controller.		 */		command &= ~AGPSTAT2_4X;	}	if ((uninorth_rev >= 0x30) && (uninorth_rev <= 0x33)) {		/*		 * We need to to set REQ_DEPTH to 7 for U3 versions 1.0, 2.1,		 * 2.2 and 2.3, Darwin do so.		 */		if ((command >> AGPSTAT_RQ_DEPTH_SHIFT) > 7)			command = (command & ~AGPSTAT_RQ_DEPTH)				| (7 << AGPSTAT_RQ_DEPTH_SHIFT);	}	uninorth_tlbflush(NULL);	timeout = 0;	do {		pci_write_config_dword(bridge->dev,				       bridge->capndx + PCI_AGP_COMMAND,				       command);		pci_read_config_dword(bridge->dev,				      bridge->capndx + PCI_AGP_COMMAND,				       &scratch);	} while ((scratch & PCI_AGP_COMMAND_AGP) == 0 && ++timeout < 1000);	if ((scratch & PCI_AGP_COMMAND_AGP) == 0)		printk(KERN_ERR PFX "failed to write UniNorth AGP"		       " command register\n");	if (uninorth_rev >= 0x30) {		/* This is an AGP V3 */		agp_device_command(command, (status & AGPSTAT_MODE_3_0));	} else {		/* AGP V2 */		agp_device_command(command, 0);	}	uninorth_tlbflush(NULL);}#ifdef CONFIG_PM/* * These Power Management routines are _not_ called by the normal PCI PM layer, * but directly by the video driver through function pointers in the device * tree. */static int agp_uninorth_suspend(struct pci_dev *pdev){	struct agp_bridge_data *bridge;	u32 cmd;	u8 agp;	struct pci_dev *device = NULL;	bridge = agp_find_bridge(pdev);	if (bridge == NULL)		return -ENODEV;	/* Only one suspend supported */	if (bridge->dev_private_data)		return 0;	/* turn off AGP on the video chip, if it was enabled */	for_each_pci_dev(device) {		/* Don't touch the bridge yet, device first */		if (device == pdev)			continue;		/* Only deal with devices on the same bus here, no Mac has a P2P		 * bridge on the AGP port, and mucking around the entire PCI		 * tree is source of problems on some machines because of a bug		 * in some versions of pci_find_capability() when hitting a dead		 * device		 */		if (device->bus != pdev->bus)			continue;		agp = pci_find_capability(device, PCI_CAP_ID_AGP);		if (!agp)			continue;		pci_read_config_dword(device, agp + PCI_AGP_COMMAND, &cmd);		if (!(cmd & PCI_AGP_COMMAND_AGP))			continue;		printk("uninorth-agp: disabling AGP on device %s\n",				pci_name(device));		cmd &= ~PCI_AGP_COMMAND_AGP;		pci_write_config_dword(device, agp + PCI_AGP_COMMAND, cmd);	}	/* turn off AGP on the bridge */	agp = pci_find_capability(pdev, PCI_CAP_ID_AGP);	pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd);	bridge->dev_private_data = (void *)cmd;	if (cmd & PCI_AGP_COMMAND_AGP) {		printk("uninorth-agp: disabling AGP on bridge %s\n",				pci_name(pdev));		cmd &= ~PCI_AGP_COMMAND_AGP;		pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND, cmd);	}	/* turn off the GART */	uninorth_cleanup();	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -