pci_sh5.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 648 行 · 第 1/2 页

C
648
字号
/*  * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) * * May be copied or modified under the terms of the GNU General Public * License.  See linux/COPYING for more information.                             * * Support functions for the SH5 PCI hardware. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/types.h>#include <asm/pci.h>#include <linux/irq.h>#include <asm/io.h>#include <asm/hardware.h>#include "pci_sh5.h"#undef DEBUG#ifdef DEBUG#  define dprintk(x...)  printk(KERN_DEBUG x)#else#  define dprintk(x...)  do { } while (0)#endif /* DEBUG */static unsigned long pcicr_virt;unsigned long pciio_virt;static void __init pci_fixup_ide_bases(struct pci_dev *d){	int i;	/*	 * PCI IDE controllers use non-standard I/O port decoding, respect it.	 */	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)		return;	printk("PCI: IDE base address fixup for %s\n", d->slot_name);	for(i=0; i<4; i++) {		struct resource *r = &d->resource[i];		if ((r->start & ~0x80) == 0x374) {			r->start |= 2;			r->end = r->start;		}	}}/* Add future fixups here... */struct pci_fixup pcibios_fixups[] = {	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,	PCI_ANY_ID,	pci_fixup_ide_bases },	{ 0 }};char * __init pcibios_setup(char *str){	return str;}/* Rounds a number UP to the nearest power of two. Used for * sizing the PCI window. */static u32 __init r2p2(u32 num){	int i = 31;	u32 tmp = num;	if (num == 0)		return 0;	do {		if (tmp & (1 << 31))			break;		i--;		tmp <<= 1;	} while (i >= 0);	tmp = 1 << i;	/* If the original number isn't a power of 2, round it up */	if (tmp != num)		tmp <<= 1;	return tmp;}extern unsigned long long memory_start, memory_end;int __init sh5pci_init(unsigned memStart, unsigned memSize){	u32 lsr0;	u32 uval;	pcicr_virt = onchip_remap(SH5PCI_ICR_BASE, 1024, "PCICR");	if (!pcicr_virt) {		panic("Unable to remap PCICR\n");	}	pciio_virt = onchip_remap(SH5PCI_IO_BASE, 0x10000, "PCIIO");	if (!pciio_virt) {		panic("Unable to remap PCIIO\n");	}	dprintk("Register base addres is 0x%08lx\n", pcicr_virt);	/* Clear snoop registers */        SH5PCI_WRITE(CSCR0, 0);        SH5PCI_WRITE(CSCR1, 0);	dprintk("Wrote to reg\n");        /* Switch off interrupts */        SH5PCI_WRITE(INTM,  0);        SH5PCI_WRITE(AINTM, 0);        SH5PCI_WRITE(PINTM, 0);        /* Set bus active, take it out of reset */        uval = SH5PCI_READ(CR);	/* Set command Register */        SH5PCI_WRITE(CR, uval | CR_LOCK_MASK | CR_CFINT| CR_FTO | CR_PFE | CR_PFCS | CR_BMAM );	uval=SH5PCI_READ(CR);        dprintk("CR is actually 0x%08x\n",uval);        /* Allow it to be a master */	/* NB - WE DISABLE I/O ACCESS to stop overlap */        /* set WAIT bit to enable stepping, an attempt to improve stability */	SH5PCI_WRITE_SHORT(CSR_CMD,			    PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_WAIT);        /*         ** Set translation mapping memory in order to convert the address        ** used for the main bus, to the PCI internal address.        */        SH5PCI_WRITE(MBR,0x40000000);        /* Always set the max size 512M */        SH5PCI_WRITE(MBMR, PCISH5_MEM_SIZCONV(512*1024*1024));        /*         ** I/O addresses are mapped at internal PCI specific address        ** as is described into the configuration bridge table.        ** These are changed to 0, to allow cards that have legacy         ** io such as vga to function correctly. We set the SH5 IOBAR to        ** 256K, which is a bit big as we can only have 64K of address space        */        SH5PCI_WRITE(IOBR,0x0);      		dprintk("PCI:Writing 0x%08x to IOBR\n",0);        /* Set up a 256K window. Totally pointless waste  of address space */        SH5PCI_WRITE(IOBMR,0);	dprintk("PCI:Writing 0x%08x to IOBMR\n",0);	/* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec. Ideally,          * we would want to map the I/O region somewhere, but it is so big this is not         * that easy!         */	SH5PCI_WRITE(CSR_IBAR0,~0);	/* Set memory size value */        memSize = memory_end - memory_start;        /* Now we set up the mbars so the PCI bus can see the memory of the machine */        if (memSize < (1024 * 1024)) {                printk(KERN_ERR "PCISH5: Ridiculous memory size of 0x%x?\n", memSize);                return(-1);        }        /* Set LSR 0 */        lsr0 = (memSize > (512 * 1024 * 1024)) ? 0x1ff00001 : ((r2p2(memSize) - 0x100000) | 0x1);        SH5PCI_WRITE(LSR0, lsr0);	dprintk("PCI:Writing 0x%08x to LSR0\n",lsr0);        /* Set MBAR 0 */        SH5PCI_WRITE(CSR_MBAR0, memory_start);        SH5PCI_WRITE(LAR0, memory_start);        SH5PCI_WRITE(CSR_MBAR1,0);        SH5PCI_WRITE(LAR1,0);        SH5PCI_WRITE(LSR1,0);	dprintk("PCI:Writing 0x%08llx to CSR_MBAR0\n",memory_start);         	dprintk("PCI:Writing 0x%08llx to LAR0\n",memory_start);                 /* Enable the PCI interrupts on the device */#if 1        SH5PCI_WRITE(INTM,  ~0);        SH5PCI_WRITE(AINTM, ~0);        SH5PCI_WRITE(PINTM, ~0);#endif	dprintk("Switching on all error interrupts\n");        return(0);}/* Write to config register */static int sh5pci_read_config_byte(struct pci_dev *dev, int where,				    u8 * val){	SH5PCI_WRITE(PAR, CONFIG_CMD(dev, where));	*val = SH5PCI_READ_BYTE(PDR + (where & 3));	return PCIBIOS_SUCCESSFUL;}static int sh5pci_read_config_word(struct pci_dev *dev, int where,				    u16 * val){	SH5PCI_WRITE(PAR, CONFIG_CMD(dev, where));	*val = SH5PCI_READ_SHORT(PDR + (where & 2));	return PCIBIOS_SUCCESSFUL;}static int sh5pci_read_config_dword(struct pci_dev *dev, int where,				     u32 * val){	SH5PCI_WRITE(PAR, CONFIG_CMD(dev, where));	*val = SH5PCI_READ(PDR);	return PCIBIOS_SUCCESSFUL;}static int sh5pci_write_config_byte(struct pci_dev *dev, int where,				     u8 val){	SH5PCI_WRITE(PAR, CONFIG_CMD(dev, where));	SH5PCI_WRITE_BYTE(PDR + (where & 3), val);	return PCIBIOS_SUCCESSFUL;}static int sh5pci_write_config_word(struct pci_dev *dev, int where,				     u16 val){	SH5PCI_WRITE(PAR, CONFIG_CMD(dev, where));	SH5PCI_WRITE_SHORT(PDR + (where & 2), val);	return PCIBIOS_SUCCESSFUL;}static int sh5pci_write_config_dword(struct pci_dev *dev, int where,				      u32 val){	SH5PCI_WRITE(PAR, CONFIG_CMD(dev, where));	SH5PCI_WRITE(PDR, val);	return PCIBIOS_SUCCESSFUL;}static struct pci_ops pci_config_ops = {	sh5pci_read_config_byte,	sh5pci_read_config_word,	sh5pci_read_config_dword,	sh5pci_write_config_byte,	sh5pci_write_config_word,	sh5pci_write_config_dword};/* Everything hangs off this */static struct pci_bus *pci_root_bus;static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin){	dprintk("swizzle for dev %d on bus %d slot %d pin is %d\n",	       dev->devfn,dev->bus->number, PCI_SLOT(dev->devfn),*pin);	return PCI_SLOT(dev->devfn);}static inline u8 bridge_swizzle(u8 pin, u8 slot) {	return (((pin-1) + slot) % 4) + 1;}u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp){	if (dev->bus->number != 0) {		u8 pin = *pinp;		do {			pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));			/* Move up the chain of bridges. */			dev = dev->bus->self;		} while (dev->bus->self);		*pinp = pin;		/* The slot is the slot of the last bridge. */	}	return PCI_SLOT(dev->devfn);}/* This needs to be shunted out of here into the board specific bit */static int __init map_cayman_irq(struct pci_dev *dev, u8 slot, u8 pin){	int result = -1;	/* The complication here is that the PCI IRQ lines from the Cayman's 2	   5V slots get into the CPU via a different path from the IRQ lines

⌨️ 快捷键说明

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