📄 mot82xxpci.c
字号:
/* mot82xxPci.c - Motorola ads 82xx PCI Bridge functions *//* Copyright 1984-2003 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01c,01oct03,dee changed structure element names for all dma buffer descriptors01b,08jan03,dtr Added support for PCI DMA and Error Handling. Implemented workaround for PCI Bridge read errata.01a,04jul02,dtr File created.*//* PCI Host Bridge setup File */#include "vxWorks.h"#include "config.h"#include "sysLib.h"#include "drv/pci/pciConfigLib.h" #include "drv/pci/pciIntLib.h" #include "drv/pci/pciAutoConfigLib.h" #include "sysBusPci.h"#include "drv/mem/m8260Memc.h"#include "drv/intrCtl/m8260IntrCtl.h"#include "drv/mem/m8260Siu.h"#include "mot82xxPci.h"#ifdef PCI_BRIDGE_READ_ERRATA_WORKAROUND/* Anything above 0x3ffffff can be handled by IDMA */ #define PCI_ACCESS_MASK 0xfc000000 /* Global function called in sysLib.c */ void pciBridgeIdmaInit();IMPORT USHORT sysWord(int);IMPORT UCHAR sysByte(int);IMPORT ULONG sysLong(int);#endif /* PCI_BRIDGE_READ_ERRATA_WORKAROUND */#ifdef INCLUDE_PCI_DMASTATUS pciDmaTransfer(char*,char*,UINT32,UINT32 );LOCAL void pciDmaHandler();#endif/* These three arrays are for convenience and speed *//* Each interrupt line is wire OR'd to another on another slot * Hence for first 4 bits - 8 is slot 0 INT A * links second - 4 is slot 1 INT B * links third - 2 is slot 2 INT C * All are the same interrupt effectively linked but they all * need to be cleared/masked in the interrupt register. * Refer to the ADS8266 PCI Board Users Manual. */ LOCAL UINT32 pciSlotIntDisableMask[MAX_NUM_VECTORS] = {0x84200000, /* Slot 0 */ 0x18400000, /* Slot 1 */ 0x21800000}; /* Slot 2 */LOCAL UINT32 pciSlotIntEnableMask[MAX_NUM_VECTORS] = {0x7bd00000, 0xe7b00000, 0xde700000};LOCAL UINT32 pciSlotIntClearMask[MAX_NUM_VECTORS] = {0x7bdfffff, 0xe7bfffff, 0xde7fffff};LOCAL INTR_HANDLER pciDeviceIntTable[MAX_NUM_VECTORS] = { {NULL,0}, {NULL,0}, {NULL,0} };BOOL firstTime = TRUE;LOCAL void pciDeviceIntHandler(void);STATUS pciDeviceIntConnect(int vector,VOIDFUNCPTR *handler,int arg);STATUS pciDeviceIntDisconnect(int vector,VOIDFUNCPTR *handler);STATUS pciDeviceIntEnable(int);STATUS pciDeviceIntDisable(int);LOCAL void pciMultiInterruptHandler();LOCAL void pciErrorHandler();LOCAL UINT32 pciIntEnabled = 0;VOIDFUNCPTR _func_pciDmaUserHandler[] = {NULL,NULL,NULL,NULL};typedef struct { UINT32 nmi; /* 60x error original initiated for PCI */ UINT32 ira; /* Illegal register access */ UINT32 i2o_ipqo; /* I2O Error queue overflow inbound */ UINT32 i2o_ofqo; /* I2O Error queue overflow outbound*/ UINT32 perr_wr; /* PCI Error Parity Error on write */ UINT32 perr_rd; /* PCI Error Parity Error on read */ UINT32 serr; /* PCI Error System error */ UINT32 tar_abt; /* PCI Error configuration access device isn't available */ UINT32 no_rsp; /* PCI Error no response */ UINT32 datapar_rd; /* PCI Error data parity error on read */ UINT32 datapar_wr; /* PCI Error data parity error on write */ UINT32 addrpar; /* PCI Error address parity error */} PCI_ERROR_COUNT;LOCAL PCI_ERROR_COUNT pciErrorCount; IMPORT UINT32 vxImmrGet (void);IMPORT USHORT sysPciInWord(int);LOCAL UINT32 immrVal = INTERNAL_MEM_MAP_ADDR;#ifdef PCI_BRIDGE_READ_ERRATA_WORKAROUNDLOCAL BD_DMA *idmaBd;LOCAL IDMA_PARAM *pIdmaParam;#endif /* PCI_BRIDGE_READ_ERRATA_WORKAROUND *//************************************************************************* * * mot82xxBridgeInit - This function performs all the initialisation * required for the Bridge/Interrupts/PCI Bus to function. It does some * low level processor initialisation which might normally be done in * romInit as it is optional to do use this and shows what the core * changes required to bring up the bridge. * * RETURNS : NONE * */void mot82xxBridgeInit() { STATUS result; immrVal = (UINT32)vxImmrGet(); /* Set device to use IRQ6 (pci device interrupt number) */ *M8260_SIUMCR(INTERNAL_MEM_MAP_ADDR) = (UINT32)SIUMCR_PCI_SETTING; /* Make PCI lowest priority */ /* Each 4 bits is a device bus request and the MS 4bits is highest priority */ /* Bus 4bit value --- ---------- CPM high 0b0000 CPM middle 0b0001 CPM low 0b0010 PCI reguest 0b0011 Reserved 0b0100 Reserved 0b0101 Internal Core 0b0110 External Master 1 0b0111 External Master 2 0b1000 External Master 3 0b1001 The rest are reserved */ *M8260_PPC_ALRH (INTERNAL_MEM_MAP_ADDR) = 0x61207893; /* Park bus on core while modifying PCI Bus accesses */ *M8260_PPC_ACR (INTERNAL_MEM_MAP_ADDR) = PPC_ACR_BUS_PARK_CORE; /* Standard GPCM */ *(VUINT32*) M8260_OR3(INTERNAL_MEM_MAP_ADDR) = PCI_INT_MEM_OR8_SETTING; *(VUINT32*) M8260_BR3(INTERNAL_MEM_MAP_ADDR) = PCI_INT_MEM_BR8_SETTING; /* Set outbound translation window adresses */ sysPciOutLong((UINT32*)(PCI_OUTBOUND_BASE_ADRS_REG0(immrVal)), (CPU_PCI_MEM_ADRS>>12) & 0xfffff); sysPciOutLong((UINT32*)(PCI_OUTBOUND_TRANS_ADRS_REG0(immrVal)), (PCI_MEM_ADRS>>12) & 0xfffff); sysPciOutLong((UINT32*)(PCI_OUTBOUND_BASE_ADRS_REG1(immrVal)), (CPU_PCI_MEMIO_ADRS>>12) & 0xfffff); sysPciOutLong((UINT32*)(PCI_OUTBOUND_TRANS_ADRS_REG1(immrVal)), (PCI_MEMIO_ADRS>>12) & 0xfffff); sysPciOutLong((UINT32*)(PCI_OUTBOUND_BASE_ADRS_REG2(immrVal)), (CPU_PCI_IO_ADRS>>12) & 0xfffff); sysPciOutLong((UINT32*)(PCI_OUTBOUND_TRANS_ADRS_REG2(immrVal)), (PCI_IO_ADRS>>12) & 0xfffff); *(VUINT32*) PCIMSK_REG0 (INTERNAL_MEM_MAP_ADDR) = PCIMSK0_SETTING; /* set mask for 128KBytes */ *(VUINT32*) PCIMSK_REG1 (INTERNAL_MEM_MAP_ADDR) = PCIMSK1_SETTING; /* set start addresses and enable window*/ *(VUINT32*) PCIBR_REG0 (INTERNAL_MEM_MAP_ADDR) = PCIBR0_SETTING; *(VUINT32*) PCIBR_REG1 (INTERNAL_MEM_MAP_ADDR) = PCIBR1_SETTING; /* Switch on the outbound trnslation windows */ sysPciOutLong((UINT32*)(PCI_OUTBOUND_COMP_MASK_REG0(immrVal)), PCI_WINDOW_ENABLE_BIT | PCI_MEM_SIZE_MASK); sysPciOutLong((UINT32*)(PCI_OUTBOUND_COMP_MASK_REG1(immrVal)), PCI_WINDOW_ENABLE_BIT | PCI_MEMIO_SIZE_MASK); /* Set the PCI reset line high to switch on PCI bus */ sysPciOutLong((UINT32*)(immrVal| PCI_GCR_REG) , 0); sysPciOutLong((UINT32*)(immrVal| PCI_GCR_REG) , EXTERNAL_PCI_BUS_ENABLE); sysMsDelay(1); /* the bridge registers need to be accessed as little endian */ /* Set up inbound address translation registers */ /* Translation address is the locally mapped address */ sysPciOutLong((UINT32*)(immrVal| PCI_INBOUND_TRANS_ADRS_REG0), (PCI_LOCAL_MEM_BUS>>12) & 0xfffff); /* Base Address is the PCI address */ sysPciOutLong((UINT32*)(immrVal| PCI_INBOUND_BASE_ADRS_REG0), (PCI_MSTR_MEM_BUS>>12) & 0xfffff); /* This initialises the size of the window and enables it */ sysPciOutLong((UINT32*)(immrVal |PCI_INBOUND_COMP_MASK_REG0), PCI_MSTR_MEM_SIZE_MASK | PCI_WINDOW_ENABLE_BIT | PCI_SNOOP_ENABLE | PCI_PREFETCHABLE); /* See above for description - puts PCI request as highest priority */ *M8260_PPC_ALRH (INTERNAL_MEM_MAP_ADDR) = 0x30126745; /* Park the bus on the PCI */ *M8260_PPC_ACR (INTERNAL_MEM_MAP_ADDR) = PPC_ACR_BUS_PARK_PCI; /* Setup The PIMMR PCI Base address */ result = sysPciConfigWrite(0,0,0, PIMMR_BASE_ADRS_REGISTER_OFFSET, PIMMR_BASE_ADRS_REGISTER_WIDTH, PCI_BRIDGE_PIMMR_BASE_ADRS); result = sysPciConfigWrite(0,0,0, CLASS_OFFSET, CLASS_WIDTH, BRIDGE_CLASS_TYPE); /* configure the bridge as bus master */ result = sysPciConfigWrite(0,0,0, COMMAND_REGISTER_OFFSET, COMMAND_REGISTER_WIDTH, (BUS_MASTER_ENABLE_BIT|MEMORY_SPACE_ACCESS_ENABLE_BIT)); }/************************************************************************* * * pciDeviceIntConnect - This function connects a interrupt handler to * the pci interrupt and pci interrupt vector. It disables the interrupt * vector via the PCI interrupt mask register prior to initialisation * in order to get it to a known state assuming the interrupt should be * at this point. * * RETURNS : OK or ERROR * */STATUS pciDeviceIntConnect ( int vector, VOIDFUNCPTR *handler, int arg ) { if (vector>=MAX_NUM_VECTORS) return (ERROR); pciDeviceIntDisable(vector); if (firstTime==TRUE) { (void)_func_intConnectRtn((VOIDFUNCPTR *)INUM_IRQ2,(VOIDFUNCPTR)pciDeviceIntHandler,0); /* Initialise Interrupt Mask */ firstTime=FALSE; } pciDeviceIntTable[vector].vec = (VOIDFUNCPTR)handler; pciDeviceIntTable[vector].arg = arg; (void)m8260IntEnable(INUM_IRQ2); return OK; }/************************************************************************* * * pciDeviceIntDisconnect - This function disconnects the device * interrupt handler from the pci interrupt and disables the relevent * pci interrupt. * * RETURNS : OK or ERROR * */STATUS pciDeviceIntDisconnect ( int vector, VOIDFUNCPTR *handler ) { if (vector>=MAX_NUM_VECTORS) return (ERROR); (void)pciDeviceIntDisable(vector); pciDeviceIntTable[vector].vec = NULL; pciDeviceIntTable[vector].arg = 0;#ifdef PCI_DEBUG logMsg("PCI Interrupt disconnected %d\n",vector,0,0,0,0,0);#endif firstTime=TRUE; return OK; }/************************************************************************* * * pciDeviceIntEnable - This function enables the specific pci * interrupt related to the vector. * * RETURNS : OK or ERROR */ STATUS pciDeviceIntEnable ( int vector ) { if (vector>=MAX_NUM_VECTORS) return (ERROR);#ifdef PCI_DEBUG logMsg("PCI Interrupt Enable %x\n",(int)vector,0,0,0,0,0);#endif /* PCI_DEBUG */ (void)m8260IntDisable(INUM_IRQ2); *(UINT32*)PCI_INTERRUPT_MASK_REG &=pciSlotIntEnableMask[vector]; (void)m8260IntEnable(INUM_IRQ2); return (OK); }/************************************************************************* * * pciDeviceIntDisable - This function disables the specific pci * interrupt related to the vector. * * RETURNS : OK or ERROR * */STATUS pciDeviceIntDisable ( int vector ) { if (vector>=MAX_NUM_VECTORS) return (ERROR);#ifdef PCI_DEBUG logMsg("PCI Interrupt disable %x\n",(int)vector,0,0,0,0,0);#endif /* PCI_DEBUG */ (void)m8260IntDisable(INUM_IRQ2); *(UINT32*)PCI_INTERRUPT_MASK_REG |= pciSlotIntDisableMask[vector]; (void)m8260IntEnable(INUM_IRQ2); return (OK); }/************************************************************************* * * pciDeviceIntHandler - This is called from the 8260 interrupt * controller and is linked to IRQ6. * It finds which vectors have the corresponding interrupt set and * calls the relevent interrupt handler. The priority based on * slot and the slot<->vector are the effectively the same. The vector * is based upon device number which for ADS board is : * 0x16 -> slot 0 -> vector 0 * 0x17 -> slot 1 -> vector 1 * 0x18 -> slot 2 -> vector 2 * For a custom board this may need to be modified. * * RETURNS : N/A * */LOCAL void pciDeviceIntHandler(void) { volatile int vector; volatile UINT32 status; status = *(VUINT32*)PCI_INTERRUPT_STATUS_REG; for (vector=0;vector<MAX_NUM_VECTORS;vector++) { /* Check Interrupt routine available and interrupt vector is set */ if ( (pciDeviceIntTable[vector].vec!=NULL) &&(pciDeviceIntTable[vector].arg!=0) && ((status & pciSlotIntDisableMask[vector])!=0)) { /* Call Interrupt Handler for specific vector */ pciDeviceIntTable[vector].vec(pciDeviceIntTable[vector].arg); /* Clear the specific interrupt */ *(VUINT32*)PCI_INTERRUPT_STATUS_REG &=pciSlotIntClearMask[vector]; } }#ifdef PCI_DEBUG logMsg("PCI interrupt received %x\n",(int)status,0,0,0,0,0);#endif /* PCI_DEBUG */ }/**************************************************************** * * pciErrorHandlingInit - This function sets up the error * control and mask registers. It also connects the INUM_PCI to * the interrupt handler and activates the interrupt. * * RETURNS : NONE * */void pciErrorHandlingInit() { volatile int loop; /* Initialise ECR to include particular PCI Errors */ /* Not required as most useful errors already enabled on reset*/ /* Connect handler to INUM_PCI*/ (void)_func_intConnectRtn( (VOIDFUNCPTR *)INUM_PCI, (VOIDFUNCPTR)pciMultiInterruptHandler, 0); for (loop=0;loop<sizeof(pciErrorCount)/sizeof(UINT32);loop++) { *(UINT32*)((UINT32*)&pciErrorCount + loop) = 0; } /* Clear the Error Status register */ sysPciOutLong((UINT32*)PCI_ESR(INTERNAL_MEM_MAP_ADDR),0x0); /* Activate/Initialise Mask/Control Registers */ sysPciOutLong((UINT32*)PCI_EMR(INTERNAL_MEM_MAP_ADDR),0xeff); sysPciOutLong((UINT32*)PCI_ECR(INTERNAL_MEM_MAP_ADDR),0x0); /* Allow the interrupt handler to process the interrupt */ pciIntEnabled|=PCI_ERROR_INT_ENABLED; /* Enable Interrupts */ m8260IntEnable(INUM_PCI); #ifdef PCI_DEBUG logMsg("PCI Error Handling Initialised.\n",0,0,0,0,0,0); #endif /* PCI_DEBUG */ }#ifdef INCLUDE_PCI_DMA/**************************************************************** * * pciDmaInit - This function sets up the error * control and mask registers. It also connects the INUM_PCI to * the interrupt handler and activates the interrupt. * * RETURNS : NONE * */void pciDmaInit() { (void)_func_intConnectRtn( (VOIDFUNCPTR *)INUM_PCI, (VOIDFUNCPTR)pciMultiInterruptHandler, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -