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

📄 comempci.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************//* *	comemlite.c -- PCI access code for embedded CO-MEM Lite PCI controller. * *	(C) Copyright 1999-2003, Greg Ungerer (gerg@snapgear.com). *	(C) Copyright 2000, Lineo (www.lineo.com) *//*****************************************************************************/#include <linux/config.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/ptrace.h>#include <linux/spinlock.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <asm/coldfire.h>#include <asm/mcfsim.h>#include <asm/irq.h>#include <asm/anchor.h>#ifdef CONFIG_eLIA#include <asm/elia.h>#endif/*****************************************************************************//* *	Debug configuration defines. DEBUGRES sets debugging output for *	the resource allocation phase. DEBUGPCI traces on pcibios_ function *	calls, and DEBUGIO traces all accesses to devices on the PCI bus. *//*#define	DEBUGRES	1*//*#define	DEBUGPCI	1*//*#define	DEBUGIO		1*//*****************************************************************************//* *	PCI markers for bus present and active slots. */int		pci_bus_is_present = 0;unsigned long	pci_slotmask = 0;/* *	We may or may not need to swap the bytes of PCI bus tranfers. *	The endianess is re-roder automatically by the CO-MEM, but it *	will get the wrong byte order for a pure data stream. */#define	pci_byteswap	0/* *	Resource tracking. The CO-MEM part creates a virtual address *	space that all the PCI devices live in - it is not in any way *	directly mapped into the ColdFire address space. So we can *	really assign any resources we like to devices, as long as *	they do not clash with other PCI devices. */unsigned int	pci_iobase = PCIBIOS_MIN_IO;	/* Arbitrary start address */unsigned int	pci_membase = PCIBIOS_MIN_MEM;	/* Arbitrary start address */#define	PCI_MINIO	0x100			/* 256 byte minimum I/O */#define	PCI_MINMEM	0x00010000		/* 64k minimum chunk *//* *	The CO-MEM's shared memory segment is visible inside the PCI *	memory address space. We need to keep track of the address that *	this is mapped at, to setup the bus masters pointers. */unsigned int	pci_shmemaddr;/*****************************************************************************/void	pci_interrupt(int irq, void *id, struct pt_regs *fp);/*****************************************************************************//* *	Some platforms have custom ways of reseting the PCI bus. */void pci_resetbus(void){#ifdef CONFIG_eLIA	int	i;#ifdef DEBUGPCI	printk(KERN_DEBUG "pci_resetbus()\n");#endif	*((volatile unsigned short *) (MCF_MBAR+MCFSIM_PADDR)) |= eLIA_PCIRESET;	for (i = 0; (i < 1000); i++) {		*((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = 			(ppdata | eLIA_PCIRESET);	}	*((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = ppdata;#endif}/*****************************************************************************/int pcibios_assign_resource_slot(int slot){	volatile unsigned long	*rp;	volatile unsigned char	*ip;	unsigned int		idsel, addr, val, align, i;	int			bar;#ifdef DEBUGPCI	printk(KERN_INFO "pcibios_assign_resource_slot(slot=%x)\n", slot);#endif	rp = (volatile unsigned long *) COMEM_BASE;	idsel = COMEM_DA_ADDR(0x1 << (slot + 16));	/* Try to assign resource to each BAR */	for (bar = 0; (bar < 6); bar++) {		addr = COMEM_PCIBUS + PCI_BASE_ADDRESS_0 + (bar * 4);		rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;		val = rp[LREG(addr)];#ifdef DEBUGRES		printk(KERN_DEBUG "-----------------------------------"			"-------------------------------------\n");		printk(KERN_DEBUG "BAR[%d]: read=%08x ", bar, val);#endif		rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;		rp[LREG(addr)] = 0xffffffff;		rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;		val = rp[LREG(addr)];#ifdef DEBUGRES		printk(KERN_DEBUG "write=%08x ", val);#endif		if (val == 0) {#ifdef DEBUGRES			printk(KERN_DEBUG "\n");#endif			continue;		}		/* Determine space required by BAR */		/* FIXME: this should go backwords from 0x80000000... */		for (i = 0; (i < 32); i++) {			if ((0x1 << i) & (val & 0xfffffffc))				break;		}#ifdef DEBUGRES		printk(KERN_DEBUG "size=%08x(%d)\n", (0x1 << i), i);#endif		i = 0x1 << i;		/* Assign a resource */		if (val & PCI_BASE_ADDRESS_SPACE_IO) {			if (i < PCI_MINIO)				i = PCI_MINIO;#ifdef DEBUGRES			printk(KERN_DEBUG "BAR[%d]: IO size=%08x iobase=%08x\n",				bar, i, pci_iobase);#endif			if (i > 0xffff) {				/* Invalid size?? */				val = 0 | PCI_BASE_ADDRESS_SPACE_IO;#ifdef DEBUGRES				printk(KERN_DEBUG "BAR[%d]: too big for IO??\n", bar);#endif			} else {				/* Check for un-alignment */				if ((align = pci_iobase % i))					pci_iobase += (i - align);				val = pci_iobase | PCI_BASE_ADDRESS_SPACE_IO;				pci_iobase += i;			}		} else {			if (i < PCI_MINMEM)				i = PCI_MINMEM;#ifdef DEBUGRES			printk(KERN_DEBUG "BAR[%d]: MEMORY size=%08x membase=%08x\n",				bar, i, pci_membase);#endif			/* Check for un-alignment */			if ((align = pci_membase % i))				pci_membase += (i - align);			val = pci_membase | PCI_BASE_ADDRESS_SPACE_MEMORY;			pci_membase += i;		}		/* Write resource back into BAR register */		rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;		rp[LREG(addr)] = val;#ifdef DEBUGRES		printk(KERN_DEBUG "BAR[%d]: assigned bar=%08x\n", bar, val);#endif	}#ifdef DEBUGRES	printk(KERN_DEBUG "-----------------------------------"			"-------------------------------------\n");#endif	/* Assign IRQ if one is wanted... */	ip = (volatile unsigned char *) (COMEM_BASE + COMEM_PCIBUS);	rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;	addr = (PCI_INTERRUPT_PIN & 0xfc) + (~PCI_INTERRUPT_PIN & 0x03);	if (ip[addr]) {		rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;		addr = (PCI_INTERRUPT_LINE & 0xfc)+(~PCI_INTERRUPT_LINE & 0x03);		ip[addr] = 25;#ifdef DEBUGRES		printk(KERN_DEBUG "IRQ LINE=25\n");#endif	}	return(0);}/*****************************************************************************/int pcibios_enable_slot(int slot){	volatile unsigned long	*rp;	volatile unsigned short	*wp;	unsigned int		idsel, addr;	unsigned short		cmd;#ifdef DEBUGPCI	printk(KERN_DEBUG "pcibios_enbale_slot(slot=%x)\n", slot);#endif	rp = (volatile unsigned long *) COMEM_BASE;	wp = (volatile unsigned short *) COMEM_BASE;	idsel = COMEM_DA_ADDR(0x1 << (slot + 16));	/* Get current command settings */	addr = COMEM_PCIBUS + PCI_COMMAND;	addr = (addr & ~0x3) + (~addr & 0x02);	rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;	cmd = wp[WREG(addr)];	/*val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);*/	/* Enable I/O and memory accesses to this device */	rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;	cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;	wp[WREG(addr)] = cmd;	return(0);}/*****************************************************************************/void pcibios_assign_resources(void){	volatile unsigned long	*rp;	unsigned long		sel, id;	int			slot;	rp = (volatile unsigned long *) COMEM_BASE;	/*	 *	Do a quick scan of the PCI bus and see what is here.	 */	for (slot = COMEM_MINDEV; (slot <= COMEM_MAXDEV); slot++) {		sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16));		rp[LREG(COMEM_DAHBASE)] = sel;		rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */		id = rp[LREG(COMEM_PCIBUS)];		if ((id != 0) && ((id & 0xffff0000) != (sel & 0xffff0000))) {			printk(KERN_INFO "PCI: slot=%d id=%08x\n", slot, (int) id);			pci_slotmask |= 0x1 << slot;			pcibios_assign_resource_slot(slot);			pcibios_enable_slot(slot);		}	}}/*****************************************************************************/int pcibios_init(void){	volatile unsigned long	*rp;	unsigned long		sel, id;	int			slot;#ifdef DEBUGPCI	printk(KERN_DEBUG "pcibios_init()\n");#endif	pci_resetbus();	/*	 *	Do some sort of basic check to see if the CO-MEM part	 *	is present... This works ok, but I think we really need	 *	something better...	 */	rp = (volatile unsigned long *) COMEM_BASE;	if ((rp[LREG(COMEM_LBUSCFG)] & 0xff) != 0x50) {		printk(KERN_INFO "PCI: no PCI bus present\n");		return(0);	}#ifdef COMEM_BRIDGEDEV	/*	 *	Setup the PCI bridge device first. It needs resources too,	 *	so that bus masters can get to its shared memory.	 */	slot = COMEM_BRIDGEDEV;	sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16));	rp[LREG(COMEM_DAHBASE)] = sel;	rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */	id = rp[LREG(COMEM_PCIBUS)];	if ((id == 0) || ((id & 0xffff0000) == (sel & 0xffff0000))) {		printk(KERN_INFO "PCI: no PCI bus bridge present\n");		return(0);	}	printk(KERN_INFO "PCI: bridge device at slot=%d id=%08x\n", slot, (int) id);	pci_slotmask |= 0x1 << slot;	pci_shmemaddr = pci_membase;	pcibios_assign_resource_slot(slot);	pcibios_enable_slot(slot);#endif	pci_bus_is_present = 1;	/* Get PCI irq for local vectoring */	if (request_irq(COMEM_IRQ, pci_interrupt, 0, "PCI bridge", NULL)) {		printk(KERN_WARNING "PCI: failed to acquire interrupt %d\n", COMEM_IRQ);	} else {		mcf_autovector(COMEM_IRQ);	}	pcibios_assign_resources();	return(0);}/*****************************************************************************/char *pcibios_setup(char *option){	/* Nothing for us to handle. */	return(option);}/*****************************************************************************/void pcibios_fixup_bus(struct pci_bus *b){}/*****************************************************************************/void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align){}/*****************************************************************************/int pcibios_enable_device(struct pci_dev *dev, int mask){	int slot;	slot = PCI_SLOT(dev->devfn);	if ((dev->bus == 0) && (pci_slotmask & (1 << slot)))		pcibios_enable_slot(slot);	return(0);}/*****************************************************************************/void pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *r, int resource){	printk(KERN_WARNING "%s(%d): no support for changing PCI resources...\n",		__FILE__, __LINE__);}/*****************************************************************************//* *	Local routines to interrcept the standard I/O and vector handling *	code. Don't include this 'till now - initialization code above needs *	access to the real code too. */#include <asm/mcfpci.h>/*****************************************************************************/void pci_outb(unsigned char val, unsigned int addr){	volatile unsigned long	*rp;	volatile unsigned char	*bp;#ifdef DEBUGIO	printk(KERN_DEBUG "pci_outb(val=%02x,addr=%x)\n", val, addr);#endif	rp = (volatile unsigned long *) COMEM_BASE;	bp = (volatile unsigned char *) COMEM_BASE;	rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr);	addr = (addr & ~0x3) + (~addr & 0x03);	bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val;}/*****************************************************************************/void pci_outw(unsigned short val, unsigned int addr){	volatile unsigned long	*rp;	volatile unsigned short	*sp;#ifdef DEBUGIO	printk(KERN_DEBUG "pci_outw(val=%04x,addr=%x)\n", val, addr);#endif	rp = (volatile unsigned long *) COMEM_BASE;	sp = (volatile unsigned short *) COMEM_BASE;	rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr);	addr = (addr & ~0x3) + (~addr & 0x02);	if (pci_byteswap)		val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);	sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val;}/*****************************************************************************/void pci_outl(unsigned int val, unsigned int addr){	volatile unsigned long	*rp;	volatile unsigned int	*lp;#ifdef DEBUGIO	printk(KERN_DEBUG "pci_outl(val=%08x,addr=%x)\n", val, addr);#endif	rp = (volatile unsigned long *) COMEM_BASE;	lp = (volatile unsigned int *) COMEM_BASE;	rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr);	if (pci_byteswap)		val = (val << 24) | ((val & 0x0000ff00) << 8) |			((val & 0x00ff0000) >> 8) | (val >> 24);	lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val;}/*****************************************************************************/unsigned long	pci_blmask[] = {	0x000000e0,	0x000000d0,	0x000000b0,	0x00000070};unsigned char pci_inb(unsigned int addr){	volatile unsigned long	*rp;	volatile unsigned char	*bp;	unsigned long		r;	unsigned char		val;#ifdef DEBUGIO	printk(KERN_DEBUG "pci_inb(addr=%x)\n", addr);#endif	rp = (volatile unsigned long *) COMEM_BASE;	bp = (volatile unsigned char *) COMEM_BASE;	r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_blmask[(addr & 0x3)];	rp[LREG(COMEM_DAHBASE)] = r;	addr = (addr & ~0x3) + (~addr & 0x3);	val = bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))];	return(val);}/*****************************************************************************/unsigned long	pci_bwmask[] = {	0x000000c0,	0x000000c0,	0x00000030,	0x00000030};unsigned short pci_inw(unsigned int addr){

⌨️ 快捷键说明

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