ixp425Pci.c
资源名称:ixp425BSP.rar [点击查看]
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:27k
源码类别:
VxWorks
开发平台:
C/C++
- /* ixp425Pci.c - PCI driver for the IXP425 */
- /* Copyright 2002 Wind River Systems, Inc. */
- /*
- modification history
- --------------------
- 01a,05jun02,jb initial version...
- */
- /*
- DESCRIPTION
- This is device driver code for the Intel IXP425 PCI unit. This code provides
- a set of initialization routines which automatically discover and initialize
- any PCI devices on the PCI bus at startup time. Configuration routines are
- provided to be used by PCI device drivers in order to configure PCI devices.
- In order for the functionality defined herein to be available, INCLUDE_PCI
- must be defined in config.h
- .SH INITIALIZATION
- The function sysPciInit() should be called from
- sysHwInit() to initialize the PCI unit on the IXP425.
- The function sysPciAssignAddrs() should be called from
- sysHwInit() after the call to sysPciInit to initialise
- devices on the PCI bus.
- INCLUDE FILES:
- ixp425Pci.h ixp425Pci_p.h
- SEE ALSO:
- .I "PCI Local Bus Specification, Revision 2.2, December 18, 1998"
- */
- #include "vxWorks.h"
- #include "config.h"
- #include "dllLib.h"
- #include "sysLib.h"
- #include "stdio.h"
- #include "stdlib.h"
- #include "intLib.h"
- #include "ixp425Pci.h"
- #include "ixp425Pci_p.h"
- #ifndef IX_PCI_UNIT_TEST
- #include "ixp425Gpio.h"
- #include "ixp425IntrCtl.h"
- #endif
- /* local defines */
- /*The following defines are used by busy-loop waits. Busy loops are necessary because
- in the early stages of PCI initialisation we do not have proper OS services.
- The delay values here are chosen to be pessimistic, ensuring that we always
- wait for at least the required period.
- */
- #define PCI_DELAY 500
- #define USEC_LOOP_COUNT 533
- #define PCI_SETTLE_USEC 200
- #define PCI_MIN_RESET_ASSERT_USEC 2000
- /*Specify the initial command we send to PCI devices*/
- #define INITIAL_PCI_CMD (PCI_CMD_IO_ENABLE
- | PCI_CMD_MEM_ENABLE
- | PCI_CMD_MASTER_ENABLE
- | PCI_CMD_WI_ENABLE)
- #define MAX_PCC_MAP (3)
- /*Each mapping permits access to exactly 16MB of AHB space*/
- #define MAPPING_SIZE (0x1000000)
- /*
- * Variable declarations global to this file only. Externs are followed by
- * static variables.
- */
- #ifdef IXP425_PCI_SIMPLE_MAPPING
- LOCAL UINT32 nextPccMap = MAX_PCC_MAP+1;
- #else
- LOCAL UINT32 nextPccMap = 0;
- #endif
- extern DL_LIST pciIntList[PCI_IRQ_LINES]; /* linked list of interrupt handlers */
- extern DL_LIST pciCallbackList; /* linked list of callback error handlers */
- LOCAL STATUS pciLibInitStatus = NONE;
- LOCAL PciStatus lastError = PCI_OK;
- LOCAL UINT32 nMBars;
- LOCAL UINT32 nIOBars;
- LOCAL PciBar *memBars[IXP425_PCI_MAX_BAR];
- LOCAL PciBar *ioBars[IXP425_PCI_MAX_BAR];
- /*
- * The devices array contains an entry for each individually configurable
- * entity on the PCI bus. In PCI nomenclature, such entities are
- * referred to as "functions", and it is possible for a PCI card to contain
- * more than one function (e.g. combined NIC + Modem), however the convention in PCI
- * controller drivers is to refer to such individually configurable entities
- * as devices. This is primarily due to the fact that multi function
- * cards are rare, so function and device are for the most part synonymous.
- *
- * This is potentially confusing since the drivers also typically
- * implicity refer to slots/cards on the PCI bus as devices,
- * since the constant PCI_MAX_DEV (in our case IXP425_PCI_MAX_DEV)
- * is set to be the maximum number of slots/cards.
- * We have chosen to follow the normal PCI driver convention here,
- * so the devices array contains an entry for each function,
- * and the constant IXP425_PCI_MAX_DEV is set to the maximum
- * number of PCI cards that can be present on the bus.
- * We include the PCI controller itself in this array, hence the +1
- */
- LOCAL PciDevice devices[IXP425_PCI_MAX_FUNC_ON_BUS];
- LOCAL UINT32 nDevices;
- LOCAL UINT32 ixp425PciIntTranslate[IXP425_PCI_MAX_DEV][PCI_IRQ_LINES] = {
- {IXP425_PCI_INTA_INTERRUPT_NUM, IXP425_PCI_INTB_INTERRUPT_NUM,
- IXP425_PCI_INTC_INTERRUPT_NUM, IXP425_PCI_INTD_INTERRUPT_NUM},
- {IXP425_PCI_INTB_INTERRUPT_NUM, IXP425_PCI_INTC_INTERRUPT_NUM,
- IXP425_PCI_INTD_INTERRUPT_NUM, IXP425_PCI_INTA_INTERRUPT_NUM},
- {IXP425_PCI_INTC_INTERRUPT_NUM, IXP425_PCI_INTD_INTERRUPT_NUM,
- IXP425_PCI_INTA_INTERRUPT_NUM, IXP425_PCI_INTB_INTERRUPT_NUM},
- {IXP425_PCI_INTD_INTERRUPT_NUM, IXP425_PCI_INTA_INTERRUPT_NUM,
- IXP425_PCI_INTB_INTERRUPT_NUM, IXP425_PCI_INTC_INTERRUPT_NUM}
- };
- /* extern prototypes*/
- extern void pciInternalIsr (UINT32 param);
- extern void pciInt (UINT32 param);
- extern BOOL pciDeviceExists (UINT32 busNo, UINT32 deviceNo, UINT32 funcNo);
- #ifdef INCLUDE_PCI_DMA
- extern STATUS pciDmaInit (void);
- #endif
- /* static function prototypes */
- LOCAL void crpRead (UINT32 offset, UINT32 *data);
- LOCAL void crpWrite (UINT32 offset, UINT32 data);
- /* driver functions */
- /******************************************************************************
- *
- * sysPciIsHost - returns a boolean indicating whether we are the Bus host
- *
- * This function returns a boolean indicating whether we are the PCI Bus host or not
- *
- * RETURNS: TRUE if we are PCI bus host, otherwise FALSE
- */
- LOCAL BOOL
- sysPciIsHost (void)
- {
- UINT32 regval;
- REG_READ (PCI_CSR_BASE, PCI_CSR_OFFSET, regval);
- if(regval & PCI_CSR_HOST)
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- /******************************************************************************
- *
- * sysPciGpioConfig - Configure the PCI gpio lines as outputs
- *
- * Configures the Clock and Reset GPIO lines as outputs,
- * and configures the PCI INTA#..INTD# as interrupts, active low.
- * Clears the interrupt status indicators for PCI interrupts.
- * If IXP425_PCI_GPIO_CLOCK_ON is not defined, then the clock GPIO
- * is not driven as an output by this code.
- *
- * RETURNS: void
- */
- LOCAL void
- sysPciGpioConfig (void)
- {
- #ifdef IXP425_PCI_GPIO_CLOCK_ON
- ixp425GPIOLineConfig (IXP425_PCI_CLK_PIN, IXP425_GPIO_OUT);
- #endif
- ixp425GPIOLineConfig (IXP425_PCI_RESET_GPIO, IXP425_GPIO_OUT);
- ixp425GPIOLineConfig (IXP425_PCI_INTA_PIN,
- IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW);
- /* ixp425GPIOLineConfig (IXP425_PCI_INTB_PIN,
- IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW);
- ixp425GPIOLineConfig (IXP425_PCI_INTC_PIN,
- IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW);
- ixp425GPIOLineConfig (IXP425_PCI_INTD_PIN,
- IXP425_GPIO_IN | IXP425_GPIO_ACTIVE_LOW);*/
- /*Set the interrupt status in the GPIO block to a known starting state*/
- ixp425GPIOIntStatusClear(IXP425_PCI_INTA_PIN);
- /* ixp425GPIOIntStatusClear(IXP425_PCI_INTB_PIN);
- ixp425GPIOIntStatusClear(IXP425_PCI_INTC_PIN);
- ixp425GPIOIntStatusClear(IXP425_PCI_INTD_PIN);*/
- }
- /******************************************************************************
- *
- * sysPciResetAssert - Asserts PCI reset to the PCI bus via IXP425_PCI_RESET_GPIO
- *
- * RETURNS: void
- */
- LOCAL void
- sysPciResetAssert (void)
- {
- ixp425GPIOLineSet (IXP425_PCI_RESET_GPIO, IXP425_GPIO_LOW);
- }
- /******************************************************************************
- *
- * sysPciResetDeassert - Deasserts PCI reset to the PCI bus via IXP425_PCI_RESET_GPIO
- *
- * RETURNS: void
- */
- LOCAL void
- sysPciResetDeassert (void)
- {
- ixp425GPIOLineSet (IXP425_PCI_RESET_GPIO, IXP425_GPIO_HIGH);
- }
- /******************************************************************************
- *
- * sysAhbDoorbellReset - reset the AHB doorbell register
- *
- * RETURNS: void
- */
- LOCAL void
- sysAhbDoorbellReset (void)
- {
- UINT32 regval;
- REG_READ (PCI_CSR_BASE, PCI_AHBDOORBELL_OFFSET, regval);
- /*The bits in this register are write 1 to clear*/
- REG_WRITE (PCI_CSR_BASE, PCI_AHBDOORBELL_OFFSET, regval);
- }
- /******************************************************************************
- *
- * sysPciGpioClockConfig - Configures the PCI clock output on IXP425_PCI_CLK_PIN
- *
- * This function configures the GPIO clock pin specified by IXP425_PCI_CLK_PIN.
- * RETURNS: void
- */
- LOCAL STATUS
- sysPciGpioClockConfig (PciClockRate rate)
- {
- if (rate==PciClock33)
- {
- ixp425GPIOClockSet (IXP425_PCI_CLK_PIN,IXP425_GPIO_33_MHZ);
- return OK;
- }
- else
- {
- return ERROR;
- }
- }
- /******************************************************************************
- *
- * sysPciGpioClockEnable - Enables the clock output
- *
- * RETURNS: void
- */
- LOCAL void
- sysPciGpioClockEnable ()
- {
- ixp425GPIOClockEnable (IXP425_PCI_CLK_PIN, TRUE);
- }
- /******************************************************************************
- *
- * sysPciGpioClockDisable - Disables the clock output
- *
- * RETURNS: void
- */
- LOCAL void
- sysPciGpioClockDisable ()
- {
- ixp425GPIOClockEnable (IXP425_PCI_CLK_PIN, FALSE);
- }
- /******************************************************************************
- *
- * sysPciIntConnect - Bind PCI interrupts
- *
- * This function binds the four PCI bus interrupts (INTA..INTD) to the
- * appropriate vectors, and also binds the internal PCI controller interrupt
- * to a vector.
- *
- * RETURNS: N/A
- */
- LOCAL void
- sysPciIntConnect()
- {
- /*bind INTA# through INTD# to the PCI interrupt handler*/
- intConnect (INUM_TO_IVEC (IXP425_PCI_INTA_INTERRUPT_NUM), pciInt,
- IXP425_PCI_INTA_INDEX);
- /*
- intConnect (INUM_TO_IVEC (IXP425_PCI_INTB_INTERRUPT_NUM), pciInt,
- IXP425_PCI_INTB_INDEX);
- intConnect (INUM_TO_IVEC (IXP425_PCI_INTC_INTERRUPT_NUM), pciInt,
- IXP425_PCI_INTC_INDEX);
- intConnect (INUM_TO_IVEC (IXP425_PCI_INTD_INTERRUPT_NUM), pciInt,
- IXP425_PCI_INTD_INDEX);*/
- /*Bind the internal interrupt handler to the PCI interrupt*/
- intConnect (INUM_TO_IVEC (IXP425_PCI_INTERNAL_INT_VEC), pciInternalIsr, 0);
- }
- /******************************************************************************
- *
- * sysPciIntEnable - enable PCI interrupts
- *
- * This function enables the internal PCI controller interrupt
- * Interrupts INTA..INTD are enabled by the drivers associated with
- * the devices using them, and so are not enabled here.
- *
- * RETURNS: N/A
- */
- LOCAL void
- sysPciIntEnable()
- {
- intEnable(IXP425_PCI_INTERNAL_INT_VEC);
- }
- /******************************************************************************
- *
- * sortBars - Sort Bars largest to smallest
- *
- * This function takes in an array of pointers to BARs,
- * it will sort the BARS from largest to smallest.
- *
- * RETURNS: N/A
- */
- LOCAL void
- sortBars (PciBar *Bars[], /* Array of pointers to BARs */
- UINT32 nBars) /* Number of BARs in array */
- {
- UINT32 i, j;
- PciBar *tmp;
- if(nBars == 0)
- {
- return;
- }
- /* Sort biggest to smallest */
- for (i = 0; i < nBars-1; i++)
- {
- for (j = i+1; j < nBars; j++)
- {
- if (Bars[j]->size > Bars[i]->size)
- {
- /* swap them */
- tmp = Bars[i];
- Bars[i] = Bars[j];
- Bars[j] = tmp;
- }
- }
- }
- }
- /******************************************************************************
- *
- * calcBars - calculate BAR values
- *
- * This function takes in an array of pointers to BARs and a starting
- * PCI address, then it will then align the address appropriately for the first
- * (largest) BAR, and then assign increasing addresses with no gaps.
- *
- * RETURNS: N/A
- */
- LOCAL void
- calcBars (PciBar *Bars[], /* Array of pointers to BARs */
- UINT32 nBars, /* Number of BARs in array */
- UINT32 startAddr) /* PCI address at which to start */
- {
- UINT32 i;
- if (nBars == 0)
- {
- return;
- }
- /* Assign Addresses; first align startAddr */
- startAddr = (startAddr + Bars[0]->size - 1) & ~(Bars[0]->size - 1);
- for (i=0; i < nBars; i++)
- {
- Bars[i]->address |= startAddr;
- startAddr += Bars[i]->size;
- }
- }
- /******************************************************************************
- *
- * sysPciBarInfoGet - retrieve BAR info from a device
- *
- * This function ascertains the size requirement of each BAR in the
- * specified device, and determines whether the BAR is for IO or
- * Memory space. Retreived data is stored in the global devices array
- */
- LOCAL void
- sysPciBarInfoGet (UINT32 devnum,
- UINT32 bus,
- UINT32 dev,
- UINT32 func)
- {
- UINT32 data32;
- UINT32 tmp;
- UINT32 size;
- UINT32 i;
- for (i=0; i < IXP425_PCI_MAX_BAR_PER_FUNC; i++)
- {
- pciConfigOutLong (bus, dev, func,
- PCI_CFG_BASE_ADDRESS_0 + (4*i),
- IXP425_PCI_BAR_QUERY);
- pciConfigInLong (bus, dev, func,
- PCI_CFG_BASE_ADDRESS_0 + (4*i),
- &data32);
- if (data32 == 0)
- {
- /*If the BAR reads back as zero, we know that we have
- already configured all BARs that are supported in the device*/
- break;
- }
- /*set the bottom bit of the BAR address, according
- to whether this is memory (bit 0 = 0) or IO (bit 0 = 1) space
- the actual address is calculated in the function calcBars*/
- devices[devnum].bar[i].address = (data32 & 1);
- if (data32 & 1)
- {
- /* IO space */
- tmp = data32 & ~0x3;
- size = ~(tmp-1);
- devices[devnum].bar[i].size = size;
- if (nIOBars < IXP425_PCI_MAX_BAR)
- {
- ioBars[nIOBars++] = &devices[devnum].bar[i];
- }
- }
- else
- {
- /* Mem space */
- tmp = data32 & ~IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
- size = ~(tmp-1);
- devices[devnum].bar[i].size = size;
- if (nMBars < IXP425_PCI_MAX_BAR)
- {
- memBars[nMBars++] = &devices[devnum].bar[i];
- }
- else
- {
- devices[devnum].error = TRUE;
- }
- }
- }
- devices[devnum].bar[i].size = 0;
- }
- /******************************************************************************
- *
- * sysPciDeviceBarsWrite - write BARs in PCI devices
- *
- * Write the bars calculated in the devices array to the actual
- * devices' BAR registers
- *
- * RETURNS - N/A
- */
- LOCAL void
- sysPciDeviceBarsWrite ()
- {
- 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, j;
- 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.
- */
- for (i = 0; i < PCI_MIN_RESET_ASSERT_USEC*USEC_LOOP_COUNT; i++)
- {
- j = i + 1;
- }
- #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"*/
- for (i = 0; i < PCI_SETTLE_USEC*USEC_LOOP_COUNT; i++)
- {
- j = i + 1;
- }
- /* Negate PCI reset, i.e. take the bus out of reset*/
- sysPciResetDeassert ();
- /* wait a few usecs to settle the device and PCI bus */
- for (i = 0; i < PCI_SETTLE_USEC*USEC_LOOP_COUNT ; i++)
- {
- j = i + 1;
- }
- /*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.*/
- #ifdef IXP425_PCI_ENABLE_BYTE_ROUTING
- regval |= PCI_CSR_IC | PCI_CSR_ABE | PCI_CSR_PDS | PCI_CSR_ADS;
- #else
- regval |= PCI_CSR_IC | PCI_CSR_ABE | PCI_CSR_PDS;
- #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
- */
- void
- sysPciAssignAddrs (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
- */
- STATUS
- sysPciMappingAdd(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);
- }