⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ixp425pci.c

📁 ixp425 bsp for vxworks
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ixp425Pci.c - PCI driver for the IXP425 *//* Copyright 2002 Wind River Systems, Inc. *//*modification history--------------------01d,14aug03,scm  remove warnings for diab01c,09jul03,m_h  tweek timing numbers01b,02jul03,m_h  little endian01a,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 INITIALIZATIONThe function sysPciInit() should be called fromsysHwInit() 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.hSEE 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           (50000)#define PCI_MIN_RESET_ASSERT_USEC (500000)/*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_MAPPINGLOCAL UINT32 nextPccMap = MAX_PCC_MAP+1;#elseLOCAL UINT32 nextPccMap = 0;#endifextern DL_LIST pciIntList[PCI_IRQ_LINES];  /* linked list of interrupt handlers */extern DL_LIST pciCallbackList;	           /* linked list of callback error handlers */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 sysMicroDelay(int microseconds);extern void   pciInternalIsr (UINT32 param);extern void   pciInt (UINT32 param); extern BOOL pciDeviceExists (UINT32 busNo, UINT32 deviceNo, UINT32 funcNo);#ifdef INCLUDE_PCI_DMAextern 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 BOOLsysPciIsHost (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 STATUSsysPciGpioClockConfig (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 voidsysPciIntConnect(){    /*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 voidsysPciIntEnable(){        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 voidsortBars (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 voidcalcBars (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 voidsysPciBarInfoGet (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

⌨️ 快捷键说明

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