📄 ixp425pci.c
字号:
* devices' BAR registers** RETURNS - N/A*/ LOCAL voidsysPciDeviceBarsWrite (){ UINT32 i,j; for (i=1; i<nDevices; i++) { if (devices[i].error) { continue; } /*Write the BARs in PCI device i*/ for (j=0; devices[i].bar[j].size; j++) { pciConfigOutLong (devices[i].bus, devices[i].device, devices[i].func, PCI_CFG_BASE_ADDRESS_0 + (4*j), devices[i].bar[j].address); } pciConfigOutLong (devices[i].bus, devices[i].device, devices[i].func, PCI_CFG_DEV_INT_LINE, devices[i].irq); pciConfigOutWord (devices[i].bus, devices[i].device, devices[i].func, PCI_CFG_COMMAND, INITIAL_PCI_CMD); }}/* * PCI controller config registers are accessed through these functions * i.e. these allow us to set up our own BARs etc. */LOCAL void crpRead (UINT32 offset, UINT32* data){ UINT32 key; key = intLock (); REG_WRITE (PCI_CSR_BASE, PCI_CRP_OFFSET, offset); REG_READ (PCI_CSR_BASE, PCI_CRP_RDATA_OFFSET, *data); intUnlock (key);}LOCAL void crpWrite (UINT32 offset, UINT32 data){ UINT32 key; key = intLock (); /*The CRP address register bit 16 indicates that we want to do a write */ REG_WRITE (PCI_CSR_BASE, PCI_CRP_OFFSET, PCI_CRP_WRITE | offset); REG_WRITE (PCI_CSR_BASE, PCI_CRP_WDATA_OFFSET, data); intUnlock (key);}/******************************************************************************** sysPciInit - initialise PCI bridge controller** This function initialises the PCI controller block.** RETURNS: N/A*/void sysPciInit (void){ volatile UINT32 i; UINT32 regval; /* Check to see if we are host, if we are PCI host we assert reset signals and provide the clock */ if (sysPciIsHost ()) { sysPciGpioClockDisable(); /*Configure reset and clock gpio signals*/ sysPciGpioConfig (); /* assert PCI reset */ sysPciResetAssert (); /* PCI spec says that we must assert reset for a minimum of 1 ms * we don't have any usable timers at this stage in the * system boot, so we busy loop for * approximately twice the required minimum delay time. */ sysMicroDelay(PCI_MIN_RESET_ASSERT_USEC);#ifdef IXP425_PCI_GPIO_CLOCK_ON /*configure PCI clock output from GPIO pin*/ sysPciGpioClockConfig (PciClock33); /*enable the PCI clock output from GPIO pin*/ sysPciGpioClockEnable ();#endif /* Disable all PCI Controller interrupts*/ REG_WRITE (PCI_CSR_BASE, PCI_INTEN_OFFSET, 0); /*Wait at least 100us to satisfy "minimum reset assertion time from clock stable"*/ sysMicroDelay(PCI_SETTLE_USEC); /* Negate PCI reset, i.e. take the bus out of reset*/ sysPciResetDeassert (); /* wait a few usecs to settle the device and PCI bus */ sysMicroDelay(PCI_SETTLE_USEC); /*Initialise interrupt callback list*/ for (i = 0; i < PCI_IRQ_LINES; i++) { dllInit (&pciIntList[i]); } /*Initialise callback list*/ dllInit (&pciCallbackList); /*setup BARs in controller */ crpWrite (PCI_CFG_BASE_ADDRESS_0, IXP425_PCI_BAR_0_DEFAULT); crpWrite (PCI_CFG_BASE_ADDRESS_1, IXP425_PCI_BAR_1_DEFAULT); crpWrite (PCI_CFG_BASE_ADDRESS_2, IXP425_PCI_BAR_2_DEFAULT); crpWrite (PCI_CFG_BASE_ADDRESS_3, IXP425_PCI_BAR_3_DEFAULT); crpWrite (PCI_CFG_BASE_ADDRESS_4, IXP425_PCI_BAR_4_DEFAULT); crpWrite (PCI_CFG_BASE_ADDRESS_5, IXP425_PCI_BAR_5_DEFAULT); /*Setup PCI-AHB and AHB-PCI address mappings*/ REG_WRITE (PCI_CSR_BASE, PCI_AHBMEMBASE_OFFSET, IXP425_PCI_AHBMEMBASE_DEFAULT); REG_WRITE (PCI_CSR_BASE,PCI_AHBIOBASE_OFFSET, IXP425_PCI_AHBIOBASE_DEFAULT); REG_WRITE (PCI_CSR_BASE,PCI_PCIMEMBASE_OFFSET, IXP425_PCI_PCIMEMBASE_DEFAULT); } else { /*if we are not the PCI bus host, we must not assert reset or drive the clock, and the GPIO's used for INTA#..INTD# when in host mode must not be claimed/configured as they may be used by another driver.*/ /* We must allow ourselves to be configured by a bus * master out on the PCI bus, to do this we must set * BAR4 to permit access to the CSRs and set the * Subsystem ID register * Set CSR BAR4: i.e. set base address of CSRs from PCI, * CSR Base Address Mask Register will setup 128 byte window. */ crpWrite (PCI_CFG_BASE_ADDRESS_4, IXP425_PCI_BAR_4_DEFAULT); } /*Clear error bits in ISR, write 1 to clear*/ REG_WRITE (PCI_CSR_BASE, PCI_ISR_OFFSET , PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE ); /*reset the AHB doorbell*/ sysAhbDoorbellReset (); /*Enable interrupts in the controller*/ REG_WRITE (PCI_CSR_BASE, PCI_INTEN_OFFSET, PCI_INTEN_PSE | PCI_INTEN_PFE | PCI_INTEN_PPE | PCI_INTEN_AHBE | PCI_INTEN_ADB | PCI_INTEN_PDB); /*set the subsystem vendor and device ids*/ crpWrite (PCI_CFG_SUB_VENDOR_ID, IXP425_PCI_SUB_VENDOR_SYSTEM); /* * Set Initialise Complete in PCI Control Register: allow IXP425 to * respond to PCI configuration cycles. */ REG_READ (PCI_CSR_BASE, PCI_CSR_OFFSET, regval); /*This line sets up byte lane swapping between little-endian PCI and the big-endian AHB bus, specifies that initialisation is complete and therefore enables the controller to respond to transactions and also specifies that the AHB bus is operating in big endian mode.*/ regval |= PCI_CSR_IC | PCI_CSR_ABE;#if (defined(IXP425_PCI_ENABLE_BYTE_ROUTING) || defined(VXWORKS_DATA_COHERENT)) /* Causes data byte swapping between PCI & AHB */ regval |= PCI_CSR_PDS | PCI_CSR_ADS;#else regval &= ~PCI_CSR_PDS ; /* Force off PDS */ regval &= ~PCI_CSR_ADS ; /* Force off ADS */#endif REG_WRITE (PCI_CSR_BASE, PCI_CSR_OFFSET, regval); /*Set up PCI Bus interface in our PCI configuration registers * i.e. not the PCI controller configuration registers*/ /*enable memory access and bus mastering*/ crpWrite (PCI_CFG_COMMAND, PCI_CFG_CMD_MAE | PCI_CFG_CMD_BME); pciLibInitStatus=OK;#ifdef INCLUDE_PCI_DMA pciDmaInit();#endif return;}/******************************************************************************** sysPciAssignAddrs - Scan PCI bus and automatically assign PCI addresses** This function scans the PCI bus to see what other devices are there. It then* sorts the BARs that it finds and assigns them addresses. It enables PCI transactions* as defined by INITIAL_PCI_CMD.** This function only has an effect if this processor is the PCI central function.** RETURNS: N/A*/voidsysPciAssignAddrs (void){ UINT32 bus, dev, func; UINT16 data16; UINT32 data32; UINT8 intPin; if (!sysPciIsHost ()) { return; } /* Assign first device to ourselves */ devices[0].bus = 0; devices[0].device = 0; devices[0].func = 0; crpRead (PCI_CFG_VENDOR_ID, &data32); devices[0].vendor_id = data32 & IXP425_PCI_BOTTOM_WORD_OF_LONG_MASK; devices[0].device_id = data32 >> 16; devices[0].error = FALSE; devices[0].bar[NO_BAR].size = 0; /*dummy - required*/ nDevices = 1; nMBars = 0; nIOBars = 0; for (bus = 0; bus < IXP425_PCI_MAX_BUS; bus++ ) { for (dev = 0; dev < IXP425_PCI_MAX_DEV; dev++ ) { for(func = 0; func < IXP425_PCI_MAX_FUNC; func++) { /*Check whether a device is present*/ if (pciDeviceExists (bus, dev, func)!=TRUE) { /*Clear error bits in ISR, write 1 to clear*/ REG_WRITE (PCI_CSR_BASE, PCI_ISR_OFFSET , PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE ); continue; } /*A device is present, add an entry to the array*/ devices[nDevices].bus = bus; devices[nDevices].device = dev; devices[nDevices].func = func; pciConfigInWord (bus, dev, func, PCI_CFG_VENDOR_ID, &data16); devices[nDevices].vendor_id = data16; pciConfigInWord (bus, dev, func, PCI_CFG_DEVICE_ID, &data16); devices[nDevices].device_id = data16; /*The device is functioning correctly, set error to FALSE*/ devices[nDevices].error = FALSE; /*Figure out what BARs are on this device*/ sysPciBarInfoGet (nDevices, bus, dev, func); /*Figure out what INTX# line the card uses*/ pciConfigInByte(bus, dev, func, PCI_CFG_DEV_INT_PIN, &intPin); /*assign the appropriate irq line*/ if (intPin > PCI_IRQ_LINES) { devices[nDevices].error = TRUE; } else if (intPin != 0) { /*This device uses an interrupt line*/ devices[nDevices].irq = ixp425PciIntTranslate[dev][intPin-1]; } nDevices++; } /* end for func*/ } /* end for dev */ } /* end for bus */ /* Sort BARs and set devices[].bar[].address variables to appropriate values.*/ sortBars (memBars, nMBars); calcBars (memBars, nMBars, IXP425_PCI_BAR_MEM_BASE); sortBars (ioBars, nIOBars); calcBars (ioBars, nIOBars, IXP425_PCI_BAR_IO_BASE); /*write the BARs to the PCI devices*/ sysPciDeviceBarsWrite(); /*Clear error bits in ISR, write 1 to clear*/ REG_WRITE (PCI_CSR_BASE, PCI_ISR_OFFSET , PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE );}#ifndef IXP425_PCI_SIMPLE_MAPPING/******************************************************************************** sysPciMappingAdd - configure the AHB membase register ** This function configures the next available slot in the PCI controller's AHBMEMBASE* to permit a device on the PCI bus to access the specified SDRAM address. * This function is only available when IXP425_PCI_SIMPLE_MAPPING* is not defined, as it is the mechanism for creating dynamic (non-simple) mappings.** RETURNS: OK or ERROR if all mappings have already been used*/STATUSsysPciMappingAdd(UINT32 sdramAddress, UINT32 size){ UINT32 ahbMemBaseReg; UINT32 topEight; UINT32 i; if(size > MAPPING_SIZE) { return ERROR; } REG_READ (PCI_CSR_BASE, PCI_AHBMEMBASE_OFFSET, ahbMemBaseReg); /* check whether a mapping already exists that covers the address * and size: * foreach mapping * if (base <= address) and (base+Mapping size >= address+size) then this is the mapping * that covers the address */ for(i=0;i<nextPccMap;i++) { topEight = (ahbMemBaseReg << (i*8)) & IXP425_PCI_TOP_BYTE_OF_LONG_MASK; if ((topEight <= sdramAddress) && ((topEight + MAPPING_SIZE) >= (sdramAddress + size))) { break; } } if(i<nextPccMap) { /*mapping exists, no need to do anything*/ return OK; } /*create new mapping*/ if(nextPccMap > MAX_PCC_MAP) { return ERROR; } /*get the top 8 bits of the sdram address*/ sdramAddress = sdramAddress & IXP425_PCI_TOP_BYTE_OF_LONG_MASK; /*blank the byte we are about to write*/ ahbMemBaseReg = ahbMemBaseReg & (~ ( IXP425_PCI_TOP_BYTE_OF_LONG_MASK >> (nextPccMap*8))); ahbMemBaseReg = ahbMemBaseReg | (sdramAddress >> (nextPccMap*8)); REG_WRITE (PCI_CSR_BASE, PCI_AHBMEMBASE_OFFSET, ahbMemBaseReg); nextPccMap++; return OK;}#endif/******************************************************************************** sysPhysToPci - translate a physical address to a PCI address** This function converts a physical address to a PCI address.* It tells a PCI device what PCI address it needs to read/write* in order to access the physical address specified*** RETURNS: the PCI adddress*/void * sysPhysToPci (void *physAddr){ UINT32 topEight; UINT32 ahbBase=0; UINT32 ahbMemBaseReg; void *pciAddr; UINT32 pciBarValue=0; UINT32 i; /*figure out which of the regions defined by AHBMEMBASE covers physAddr*/ REG_READ (PCI_CSR_BASE, PCI_AHBMEMBASE_OFFSET, ahbMemBaseReg); /* * foreach mapping * if base <= address and base+Mapping size => address+size then this mapping * covers the address */ for(i=0;i<nextPccMap;i++) { topEight = (ahbMemBaseReg << (i*8)) & IXP425_PCI_TOP_BYTE_OF_LONG_MASK; if ((topEight <= (UINT32)physAddr) && ((topEight + MAPPING_SIZE) >= (UINT32)physAddr)) { ahbBase = topEight; break; } } if (i == nextPccMap) { /*no AHB base covering the specified physical address was found*/ return NULL; } /*the PCC bar corresponding to this AHB membase is specified by minindex*/ crpRead (PCI_CFG_BASE_ADDRESS_0 + 4*i, &pciBarValue); /*we're only interested in the top eight bits of the BAR - these specify the address, the rest is status info*/ pciBarValue = pciBarValue & IXP425_PCI_TOP_BYTE_OF_LONG_MASK; /*therefore the PCI address needed to access this AHB address is the PCI BAR plus (the physical addres minus the AHB base)*/ pciAddr = (void*) (pciBarValue + ((UINT32)physAddr - ahbBase)); return pciAddr;}/******************************************************************************** sysPciToPhys - translate a PCI address to a physical address** This function tells the caller what Physical address they need to generate* on the AHB bus in order to access the specified PCI address on the PCI bus* There is the facility for more complex mappings of PCI space using the* pci_pcimembasereg, but we do not use them as we can access 128MB of the PCI* address space which is sufficient, so this function assumes that the* pcimembasereg is set to zero. ** RETURNS: the physical adddress*/void * sysPciToPhys (void *pciAddr){ UINT32 pciMemBaseReg; REG_READ (PCI_CSR_BASE, PCI_PCIMEMBASE_OFFSET, pciMemBaseReg); if( pciMemBaseReg != 0) { return NULL; } return (void*)((UINT32)pciAddr + CPU_PCI_MEM_ADRS); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -