📄 comempci.c
字号:
/*****************************************************************************//* * 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 + -