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 + -
显示快捷键?