iop310-pci.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 517 行

C
517
字号
/* * arch/arm/mach-iop310/iop310-pci.c * * PCI support for the Intel IOP310 chipset * * Matt Porter <mporter@mvista.com> * * Copyright (C) 2001 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/sched.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/ioport.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/hardware.h>#include <asm/mach/pci.h>#include <asm/arch/iop310.h>/* *    *** Special note - why the IOP310 should NOT be used *** * * The PCI ATU is a brain dead implementation, only allowing 32-bit * accesses to PCI configuration space.  This is especially brain * dead for writes to this space.  A simple for-instance: * *  You want to modify the command register *without* corrupting the *  status register. * *  To perform this, you need to read *32* bits of data from offset 4, *  mask off the low 16, replace them with the new data, and write *32* *  bits back. * *  Writing the status register at offset 6 with status bits set *clears* *  the status. * * Hello?  Could we have a *SANE* implementation of a PCI ATU some day * *PLEASE*? */#undef DEBUG#ifdef DEBUG#define  DBG(x...) printk(x)#else#define  DBG(x...) do { } while (0)#endifextern int (*external_fault)(unsigned long, struct pt_regs *);static u32 iop310_cfg_address(struct pci_dev *dev, int where){	struct pci_sys_data *sys = dev->sysdata;	u32 addr;	where &= ~3;	if (sys->busnr == dev->bus->number)		addr = 1 << (PCI_SLOT(dev->devfn) + 16);	else		addr = dev->bus->number << 16 |		       PCI_SLOT(dev->devfn) << 11 | 1;	addr |=	PCI_FUNC(dev->devfn) << 8 | where;	return addr;}/* * Primary PCI interface support. */static int iop310_pri_pci_status(void){	unsigned int status;	int ret = 0;	status = *IOP310_PATUSR;	if (status & 0xf900) {		*IOP310_PATUSR = status & 0xf900;		ret = 1;	}	status = *IOP310_PATUISR;	if (status & 0x0000018f) {		*IOP310_PATUISR = status & 0x0000018f;		ret = 1;	}	status = *IOP310_PSR;	if (status & 0xf900) {		*IOP310_PSR = status & 0xf900;		ret = 1;	}	status = *IOP310_PBISR;	if (status & 0x003f) {		*IOP310_PBISR = status & 0x003f;		ret = 1;	}	return ret;}static intiop310_pri_rd_cfg_byte(struct pci_dev *dev, int where, u8 *p){	int ret;	u8 val;	*IOP310_POCCAR = iop310_cfg_address(dev, where);	val = (*IOP310_POCCDR) >> ((where & 3) * 8);	__asm__ __volatile__("nop; nop; nop; nop");	ret = iop310_pri_pci_status();	if (ret)		val = 0xff;	*p = val;	return PCIBIOS_SUCCESSFUL;}static intiop310_pri_rd_cfg_word(struct pci_dev *dev, int where, u16 *p){	int ret;	u16 val;	*IOP310_POCCAR = iop310_cfg_address(dev, where);	val = (*IOP310_POCCDR) >> ((where & 2) * 8);	__asm__ __volatile__("nop; nop; nop; nop");	ret = iop310_pri_pci_status();	if (ret)		val = 0xffff;	*p = val;	return PCIBIOS_SUCCESSFUL;}static intiop310_pri_rd_cfg_dword(struct pci_dev *dev, int where, u32 *p){	int ret;	u32 val;	*IOP310_POCCAR = iop310_cfg_address(dev, where);	val = *IOP310_POCCDR;	__asm__ __volatile__("nop; nop; nop; nop");	ret = iop310_pri_pci_status();	if (ret)		val = 0xffffffff;	*p = val;	return PCIBIOS_SUCCESSFUL;}static intiop310_pri_wr_cfg_byte(struct pci_dev *dev, int where, u8 v){	int ret;	u32 val;	*IOP310_POCCAR = iop310_cfg_address(dev, where);	val = *IOP310_POCCDR;	__asm__ __volatile__("nop; nop; nop; nop");	ret = iop310_pri_pci_status();	if (ret == 0) {		where = (where & 3) * 8;		val &= ~(0xff << where);		val |= v << where;		*IOP310_POCCDR = val;	}	return PCIBIOS_SUCCESSFUL;}static intiop310_pri_wr_cfg_word(struct pci_dev *dev, int where, u16 v){	int ret;	u32 val;	*IOP310_POCCAR = iop310_cfg_address(dev, where);	val = *IOP310_POCCDR;	__asm__ __volatile__("nop; nop; nop; nop");	ret = iop310_pri_pci_status();	if (ret == 0) {		where = (where & 2) * 8;		val &= ~(0xffff << where);		val |= v << where;		*IOP310_POCCDR = val;	}	return PCIBIOS_SUCCESSFUL;}static intiop310_pri_wr_cfg_dword(struct pci_dev *dev, int where, u32 v){	*IOP310_POCCAR = iop310_cfg_address(dev, where);	*IOP310_POCCDR = v;	__asm__ __volatile__("nop; nop; nop; nop");	return PCIBIOS_SUCCESSFUL;}static struct pci_ops iop310_primary_ops = {	iop310_pri_rd_cfg_byte,	iop310_pri_rd_cfg_word,	iop310_pri_rd_cfg_dword,	iop310_pri_wr_cfg_byte,	iop310_pri_wr_cfg_word,	iop310_pri_wr_cfg_dword,};/* * Secondary PCI interface support. */static int iop310_sec_pci_status(void){	unsigned int usr, uisr;	int ret = 0;	usr = *IOP310_SATUSR;	uisr = *IOP310_SATUISR;	if (usr & 0xf900) {		*IOP310_SATUSR = usr & 0xf900;		ret = 1;	}	if (uisr & 0x0000069f) {		*IOP310_SATUISR = uisr & 0x0000069f;		ret = 1;	}	if (ret)		DBG("ERROR (%08lx %08lx)", usr, uisr);	return ret;}static intiop310_sec_rd_cfg_byte(struct pci_dev *dev, int where, u8 *p){	int ret;	u8 val;	DBG("rdb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),	    PCI_FUNC(dev->devfn), where);	*IOP310_SOCCAR = iop310_cfg_address(dev, where);	val = (*IOP310_SOCCDR) >> ((where & 3) * 8);	__asm__ __volatile__("nop; nop; nop; nop");	DBG(">= %08lx ", val);	ret = iop310_sec_pci_status();	if (ret)		val = 0xff;	DBG("\n");	*p = val;	return PCIBIOS_SUCCESSFUL;}static intiop310_sec_rd_cfg_word(struct pci_dev *dev, int where, u16 *p){	int ret;	u16 val;	DBG("rdw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),	    PCI_FUNC(dev->devfn), where);	*IOP310_SOCCAR = iop310_cfg_address(dev, where);	val = (*IOP310_SOCCDR) >> ((where & 3) * 8);	__asm__ __volatile__("nop; nop; nop; nop");	DBG(">= %08lx ", val);	ret = iop310_sec_pci_status();	if (ret)		val = 0xffff;	DBG("\n");	*p = val;	return PCIBIOS_SUCCESSFUL;}static intiop310_sec_rd_cfg_dword(struct pci_dev *dev, int where, u32 *p){	int ret;	u32 val;	DBG("rdl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),	    PCI_FUNC(dev->devfn), where);	*IOP310_SOCCAR = iop310_cfg_address(dev, where);	val = *IOP310_SOCCDR;	__asm__ __volatile__("nop; nop; nop; nop");	DBG(">= %08lx ", val);	ret = iop310_sec_pci_status();	if (ret)		val = 0xffffffff;	DBG("\n");	*p = val;	return PCIBIOS_SUCCESSFUL;}static intiop310_sec_wr_cfg_byte(struct pci_dev *dev, int where, u8 v){	int ret;	u32 val;	DBG("wrb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),	    PCI_FUNC(dev->devfn), where);	*IOP310_SOCCAR = iop310_cfg_address(dev, where);	val = *IOP310_SOCCDR;	__asm__ __volatile__("nop; nop; nop; nop");	DBG("<= %08lx", v);	ret = iop310_sec_pci_status();	if (ret == 0) {		where = (where & 3) * 8;		val &= ~(0xff << where);		val |= v << where;		*IOP310_SOCCDR = val;	}	DBG("\n");	return PCIBIOS_SUCCESSFUL;}static intiop310_sec_wr_cfg_word(struct pci_dev *dev, int where, u16 v){	int ret;	u32 val;	DBG("wrw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),	    PCI_FUNC(dev->devfn), where);	*IOP310_SOCCAR = iop310_cfg_address(dev, where);	val = *IOP310_SOCCDR;	__asm__ __volatile__("nop; nop; nop; nop");	DBG("<= %08lx", v);	ret = iop310_sec_pci_status();	if (ret == 0) {		where = (where & 2) * 8;		val &= ~(0xffff << where);		val |= v << where;		*IOP310_SOCCDR = val;	}	DBG("\n");	return PCIBIOS_SUCCESSFUL;}static intiop310_sec_wr_cfg_dword(struct pci_dev *dev, int where, u32 v){	DBG("wrl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),	    PCI_FUNC(dev->devfn), where);	*IOP310_SOCCAR = iop310_cfg_address(dev, where);	*IOP310_SOCCDR = v;	__asm__ __volatile__("nop; nop; nop; nop");	DBG("<= %08lx\n", v);	return PCIBIOS_SUCCESSFUL;}static struct pci_ops iop310_secondary_ops = {	iop310_sec_rd_cfg_byte,	iop310_sec_rd_cfg_word,	iop310_sec_rd_cfg_dword,	iop310_sec_wr_cfg_byte,	iop310_sec_wr_cfg_word,	iop310_sec_wr_cfg_dword,};/* * When a PCI device does not exist during config cycles, the 80200 gets a * bus error instead of returning 0xffffffff. This handler simply returns. */int iop310_pci_abort_handler(unsigned long addr, struct pt_regs *regs){	DBG("PCI abort: address = %08x PC = %08x LR = %08lx\n",		addr, regs->ARM_pc, regs->ARM_lr);	return 0;}/* * Scan an IOP310 PCI bus.  sys->bus defines which bus we scan. */struct pci_bus *iop310_scan_bus(int nr, struct pci_sys_data *sys){	struct pci_ops *ops;	if (nr)		ops = &iop310_secondary_ops;	else		ops = &iop310_primary_ops;	return pci_scan_bus(sys->busnr, ops, sys);}/* * Setup the system data for controller 'nr'.   Return 0 if none found, * 1 if found, or negative error. * * We can alter: *  io_offset   - offset between IO resources and PCI bus BARs *  mem_offset  - offset between mem resources and PCI bus BARs *  resource[0] - parent IO resource *  resource[1] - parent non-prefetchable memory resource *  resource[2] - parent prefetchable memory resource *  swizzle     - bridge swizzling function *  map_irq     - irq mapping function * * Note that 'io_offset' and 'mem_offset' are left as zero since * the IOP310 doesn't attempt to perform any address translation * on accesses from the host to the bus. */int iop310_setup(int nr, struct pci_sys_data *sys){	struct resource *res;	if (nr >= 2)		return 0;	res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);	if (!res)		panic("PCI: unable to alloc resources");	switch (nr) {	case 0:		res[0].start = IOP310_PCIPRI_LOWER_IO + 0x6e000000;		res[0].end   = IOP310_PCIPRI_LOWER_IO + 0x6e00ffff;		res[0].name  = "PCI IO Primary";		res[1].start = IOP310_PCIPRI_LOWER_MEM;		res[1].end   = IOP310_PCIPRI_LOWER_MEM + IOP310_PCI_WINDOW_SIZE;		res[1].name  = "PCI Memory Primary";		break;	case 1:		res[0].start = IOP310_PCISEC_LOWER_IO + 0x6e000000;		res[0].end   = IOP310_PCISEC_LOWER_IO + 0x6e00ffff;		res[0].name  = "PCI IO Secondary";		res[1].start = IOP310_PCISEC_LOWER_MEM;		res[1].end   = IOP310_PCISEC_LOWER_MEM + IOP310_PCI_WINDOW_SIZE;		res[1].name  = "PCI Memory Secondary";		break;	}	request_resource(&ioport_resource, &res[0]);	request_resource(&iomem_resource, &res[1]);	sys->resource[0] = &res[0];	sys->resource[1] = &res[1];	sys->resource[2] = NULL;	sys->io_offset   = 0x6e000000;	return 1;}void iop310_init(void){	DBG("PCI:  Intel 80312 PCI-to-PCI init code.\n");	DBG("  ATU secondary: ATUCR =0x%08x\n", *IOP310_ATUCR);	DBG("  ATU secondary: SOMWVR=0x%08x  SOIOWVR=0x%08x\n",		*IOP310_SOMWVR,	*IOP310_SOIOWVR);	DBG("  ATU secondary: SIABAR=0x%08x  SIALR  =0x%08x SIATVR=%08x\n",		*IOP310_SIABAR, *IOP310_SIALR, *IOP310_SIATVR);	DBG("  ATU primary:   POMWVR=0x%08x  POIOWVR=0x%08x\n",		*IOP310_POMWVR,	*IOP310_POIOWVR);	DBG("  ATU primary:   PIABAR=0x%08x  PIALR  =0x%08x PIATVR=%08x\n",		*IOP310_PIABAR, *IOP310_PIALR, *IOP310_PIATVR);	DBG("  P2P: PCR=0x%04x BCR=0x%04x EBCR=0x%04x\n",		*IOP310_PCR, *IOP310_BCR, *IOP310_EBCR);	/*	 * Windows have to be carefully opened via a nice set of calls	 * here or just some direct register fiddling in the board	 * specific init when we want transactions to occur between the	 * two PCI hoses.	 *	 * To do this, we will have manage RETRY assertion between the	 * firmware and the kernel.  This will ensure that the host	 * system's enumeration code is held off until we have tweaked	 * the interrupt routing and public/private IDSELs.	 *	 * For now we will simply default to disabling the integrated type	 * 81 P2P bridge.	 */	*IOP310_PCR &= 0xfff8;	external_fault = iop310_pci_abort_handler;}

⌨️ 快捷键说明

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