You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1424 lines
35 KiB
1424 lines
35 KiB
/*VxbFtPcie.c - FT PCI bus controller VxBus driver */
|
|
|
|
/*
|
|
*
|
|
* This program is OPEN SOURCE software: you can redistribute it and/or modify it;
|
|
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
*/
|
|
|
|
#include <vxWorks.h>
|
|
#include <vsbConfig.h>
|
|
#include <intLib.h>
|
|
#include <iv.h>
|
|
#include <taskLib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <vxBusLib.h>
|
|
#include <hwif/util/hwMemLib.h>
|
|
#include <hwif/vxbus/hwConf.h>
|
|
#include <hwif/vxbus/vxBus.h>
|
|
#include <hwif/vxbus/vxbPlbLib.h>
|
|
#include <hwif/vxbus/vxbPciLib.h>
|
|
#include <drv/pci/pciIntLib.h>
|
|
#include <drv/pci/pciConfigLib.h>
|
|
#include <drv/pci/pciAutoConfigLib.h>
|
|
#include "../h/vxbus/vxbPciBus.h"
|
|
#include "../h/vxbus/vxbAccess.h"
|
|
#include <../src/hwif/intCtlr/vxbIntCtlrLib.h>
|
|
#include <../src/hwif/intCtlr/vxbIntDynaCtlrLib.h>
|
|
#include <spinLockLib.h>
|
|
|
|
#if defined(DRV_PCIBUS_FT)
|
|
/* debug */
|
|
|
|
#ifdef FT_DEBUG_ENABLE
|
|
|
|
UINT32 ftPciDebugLevel = 0;
|
|
|
|
#ifndef FT_DEBUG_MSG
|
|
#define FT_DEBUG_MSG(level,fmt,a,b,c,d,e,f) \
|
|
{ \
|
|
if ( ftPciDebugLevel >= level ) \
|
|
{ \
|
|
uartf(fmt,a,b,c,d,e,f); \
|
|
} \
|
|
};
|
|
|
|
#endif /* FT_DEBUG_MSG */
|
|
|
|
#else /* FT_DEBUG_ENABLE */
|
|
|
|
#define FT_DEBUG_MSG(level,fmt,a,b,c,d,e,f)
|
|
|
|
#endif /* FT_DEBUG_ENABLE */
|
|
|
|
/* typedefs */
|
|
|
|
LOCAL void ftPciInstInit(VXB_DEVICE_ID pInst);
|
|
LOCAL void ftPciInstInit2(VXB_DEVICE_ID pInst);
|
|
LOCAL void ftPciInstConnect(VXB_DEVICE_ID pInst);
|
|
void (*funcPirqEnable)(BOOL enable);
|
|
|
|
LOCAL STATUS ftPciMethodDevCfgRead
|
|
(
|
|
VXB_DEVICE_ID pInst, /* device info */
|
|
PCI_HARDWARE * pPciDev, /* PCI device info */
|
|
UINT32 offset, /* offset into the configuration space */
|
|
UINT32 width, /* width to be read */
|
|
void * pData /* data buffer read from the offset */
|
|
);
|
|
|
|
LOCAL STATUS ftPciMethodDevCfgWrite
|
|
(
|
|
VXB_DEVICE_ID pInst, /* device info */
|
|
PCI_HARDWARE * pPciDev, /* PCI device info */
|
|
UINT32 offset, /* offset into the configuration space */
|
|
UINT32 width, /* width to be read */
|
|
UINT32 data /* data write to the offset */
|
|
);
|
|
|
|
LOCAL STATUS ftPciDevControl
|
|
(
|
|
VXB_DEVICE_ID devID,
|
|
pVXB_DEVCTL_HDR pBusDevControl
|
|
);
|
|
|
|
LOCAL STATUS ftPciConfigInfo
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
char * pArgs
|
|
);
|
|
|
|
LOCAL STATUS ftPciInterruptInfo
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
char * pArgs
|
|
);
|
|
|
|
LOCAL STATUS ftPciMSIProgram
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
struct vxbIntDynaVecInfo *dynaVec
|
|
);
|
|
|
|
LOCAL STATUS ftPciMethodConvertBaseAddress
|
|
(
|
|
VXB_DEVICE_ID devID,
|
|
UINT32 * pBaseAddr
|
|
);
|
|
|
|
IMPORT STATUS vxbPciMSIProgram
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
struct vxbIntDynaVecInfo *dynaVec
|
|
);
|
|
|
|
IMPORT STATUS vxbPciMSIEnable
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
struct vxbIntDynaVecInfo *dynaVec
|
|
);
|
|
|
|
IMPORT STATUS vxbPciMSIDisable
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
struct vxbIntDynaVecInfo *dynaVec
|
|
);
|
|
|
|
IMPORT BOOL vxbPciMSIIsCap
|
|
(
|
|
VXB_DEVICE_ID pInst
|
|
);
|
|
|
|
#ifdef MSI_READ_ENABLE
|
|
LOCAL STATUS ftPciMSIRead
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
struct vxbIntDynaVecInfo *dynaVec
|
|
)
|
|
#endif
|
|
|
|
|
|
IMPORT VXB_DEVICE_ID globalBusCtrlID;
|
|
|
|
|
|
/*
|
|
* The driver publishes driver methods. The following driver
|
|
* methods are for serial devices. Change these as appropriate
|
|
* for your device.
|
|
*/
|
|
|
|
LOCAL device_method_t ftPci_methods[] =
|
|
{
|
|
DEVMETHOD(busCtlrDevCfgRead, ftPciMethodDevCfgRead),
|
|
DEVMETHOD(busCtlrDevCfgWrite, ftPciMethodDevCfgWrite),
|
|
DEVMETHOD(busCtlrDevCtlr, ftPciDevControl),
|
|
DEVMETHOD(busCtlrCfgInfo, ftPciConfigInfo),
|
|
DEVMETHOD(busCtlrInterruptInfo, ftPciInterruptInfo),
|
|
|
|
DEVMETHOD(vxbIntDynaVecProgram, ftPciMSIProgram),
|
|
DEVMETHOD(vxbIntDynaVecEnable, vxbPciMSIEnable),
|
|
DEVMETHOD(vxbIntDynaVecDisable, vxbPciMSIDisable),
|
|
|
|
DEVMETHOD(busCtlrBaseAddrCvt, ftPciMethodConvertBaseAddress),
|
|
{ 0, 0}
|
|
};
|
|
|
|
|
|
LOCAL struct drvBusFuncs ftPciFuncs =
|
|
{
|
|
ftPciInstInit, /* devInstanceInit */
|
|
ftPciInstInit2, /* devInstanceInit2 */
|
|
ftPciInstConnect /* devConnect */
|
|
};
|
|
|
|
LOCAL struct vxbDevRegInfo ftPciDevRegistration =
|
|
{
|
|
(struct vxbDevRegInfo *)NULL, /* pNext */
|
|
VXB_DEVID_DEVICE, /* devID */
|
|
VXB_BUSID_PLB, /* busID = PLB */
|
|
VXB_VER_4_0_0, /* busVer */
|
|
"ftPcie", /* drvName */
|
|
&ftPciFuncs, /* pDrvBusFuncs */
|
|
&ftPci_methods[0], /* pMethods */
|
|
NULL /* devProbe */
|
|
};
|
|
|
|
|
|
typedef struct ftPciDrvCtrl
|
|
{
|
|
VXB_DEVICE_ID pInst;
|
|
void * regBase;
|
|
void * handle;
|
|
UINT32 magicNumber1;
|
|
UINT32 magicNumber2;
|
|
int pciMaxBus; /* Max number of sub-busses */
|
|
|
|
void * mem32Addr;
|
|
UINT32 mem32Size;
|
|
void * memIo32Addr;
|
|
UINT32 memIo32Size;
|
|
void * io32Addr;
|
|
UINT32 io32Size;
|
|
|
|
void * pimmrBase;
|
|
void * mstrMemBus;
|
|
void * lclMemAddr;
|
|
UINT32 lclMemMapSize;
|
|
|
|
UINT32 owAttrMem;
|
|
UINT32 owAttrMemIo;
|
|
UINT32 owAttrIo;
|
|
UINT32 iwAttr;
|
|
UINT32 singleLawBar;
|
|
UINT32 singleLawBarSize;
|
|
UINT32 pciExpressHost;
|
|
UINT32 msiEnable;
|
|
UINT32 dynamicInterrupts;
|
|
UINT32 msiAddress;
|
|
UINT32 msiData;
|
|
UINT32 msiDataWorkaround;
|
|
UINT32 msiDataWorkaroundAddr;
|
|
UINT32 autoConfig;
|
|
|
|
BOOL initDone;
|
|
BOOL bridgeInitFailed;
|
|
struct vxbPciConfig *pPciConfig;
|
|
struct vxbPciInt *pIntInfo;
|
|
struct hcfDevice * pHcf;
|
|
spinlockIsr_t spinlockIsr; /* ISR-callable spinlock */
|
|
|
|
/* external bridge interrupt map */
|
|
int * extIntMap;
|
|
int extIntMapSize;
|
|
|
|
/* a flag to invoke PCI EXT2 errata workaround */
|
|
void (*funcPirqEnable)(BOOL enable);
|
|
BOOL pciEx2ErrataFlag;
|
|
|
|
} FT_PCI_DRV_CTRL;
|
|
|
|
/* defines */
|
|
|
|
#define FT_PCI_CFG_READ(pInst, offset, width, data) \
|
|
ftPciMethodDevCfgRead(pInst, pPciDev, offset, width, (void *) &data)
|
|
|
|
#define FT_PCI_CFG_WRITE(pInst, offset, width, data) \
|
|
ftPciMethodDevCfgWrite(pInst, pPciDev, offset, width, (UINT32) data)
|
|
|
|
|
|
LOCAL VIRT_ADDR ft_pcicfg_va_base;
|
|
|
|
typedef enum pci_cfg_trans_width_t
|
|
{
|
|
PCI_CFG_TRANS_8BIT = 1,
|
|
PCI_CFG_TRANS_16BIT = 2,
|
|
PCI_CFG_TRANS_32BIT = 4,
|
|
PCI_CFG_TRANS_INVALID
|
|
} pci_cfg_trans_width_t;
|
|
|
|
typedef struct pci_dev_addr_t
|
|
{
|
|
UINT8 busno;
|
|
UINT8 devno;
|
|
UINT8 fnno;
|
|
} pci_dev_addr_t;
|
|
|
|
/* locals */
|
|
|
|
LOCAL FT_PCI_DRV_CTRL * pFtPciDrvCtrl0 = NULL;
|
|
|
|
LOCAL int ftPciIntNumGet
|
|
(
|
|
VXB_DEVICE_ID devID,
|
|
pVXB_DEVCTL_HDR pBusDevControl,
|
|
int devNo
|
|
);
|
|
|
|
/* extern */
|
|
IMPORT void vxbMsDelay(int);
|
|
|
|
/*
|
|
DESCRIPTION
|
|
|
|
This is the VxBus driver for the PCI bus controller on the
|
|
m85xx CPUs.
|
|
|
|
This driver work on PLB bus, and gets configuration information
|
|
from the hwconf.c file entry. This driver supports only 1-1
|
|
address mappings, so it uses the PCI addresses and sizes specified
|
|
in hwconf as the local addresses.
|
|
|
|
*/
|
|
|
|
IMPORT int ftPciCfgRead
|
|
(
|
|
UINT8 b,
|
|
UINT8 d,
|
|
UINT8 f,
|
|
unsigned int offset,
|
|
unsigned int size,
|
|
void *data
|
|
);
|
|
|
|
IMPORT int ftPciCfgWrite
|
|
(
|
|
UINT8 b,
|
|
UINT8 d,
|
|
UINT8 f,
|
|
unsigned int offset,
|
|
unsigned int size,
|
|
UINT32 data
|
|
);
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftPciMethodDevCfgRead - read from the PCI configuration space
|
|
*
|
|
* This routine reads either a byte, word or a long word specified by
|
|
* the argument <width>, from the PCI configuration space
|
|
* This routine works around a problem in the hardware which hangs
|
|
* PCI bus if device no 12 is accessed from the PCI configuration space.
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK, or ERROR if this library is not initialized
|
|
*
|
|
* ERRNO
|
|
*/
|
|
|
|
LOCAL STATUS ftPciMethodDevCfgRead
|
|
(
|
|
VXB_DEVICE_ID pInst, /* device info */
|
|
PCI_HARDWARE * pPciDev, /* PCI device info */
|
|
UINT32 offset, /* offset into the configuration space */
|
|
UINT32 width, /* width to be read */
|
|
void * pData /* data buffer read from the offset */
|
|
)
|
|
{
|
|
FT_PCI_DRV_CTRL * pDrvCtrl;
|
|
|
|
UINT8 busNo = pPciDev->pciBus;
|
|
UINT8 deviceNo = pPciDev->pciDev;
|
|
UINT8 funcNo = pPciDev->pciFunc;
|
|
|
|
|
|
pDrvCtrl = pInst->pDrvCtrl;
|
|
|
|
return ftPciCfgRead(busNo, deviceNo, funcNo, offset, width, pData);
|
|
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftPciMethodDevCfgWrite - write to the PCI configuration space
|
|
*
|
|
* This routine writes either a byte, word or a long word specified by
|
|
* the argument <width>, to the PCI configuration space
|
|
* This routine works around a problem in the hardware which hangs
|
|
* PCI bus if device no 12 is accessed from the PCI configuration space.
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK, or ERROR if this library is not initialized
|
|
*
|
|
* ERRNO
|
|
*/
|
|
|
|
LOCAL STATUS ftPciMethodDevCfgWrite
|
|
(
|
|
VXB_DEVICE_ID pInst, /* device info */
|
|
PCI_HARDWARE * pPciDev, /* PCI device info */
|
|
UINT32 offset, /* offset into the configuration space */
|
|
UINT32 width, /* width to write */
|
|
UINT32 data /* data to write */
|
|
)
|
|
{
|
|
|
|
UINT8 busNo = pPciDev->pciBus;
|
|
UINT8 deviceNo = pPciDev->pciDev;
|
|
UINT8 funcNo = pPciDev->pciFunc;
|
|
|
|
|
|
return ftPciCfgWrite(busNo, deviceNo, funcNo, offset, width, data);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftPciConfigInfo - Returns the PCI config info ptr from bus controller.
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK, or ERROR if this library is not initialized
|
|
*
|
|
* ERRNO
|
|
*/
|
|
LOCAL STATUS ftPciConfigInfo
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
char * pArgs
|
|
)
|
|
{
|
|
FT_PCI_DRV_CTRL *pDrvCtrl = pInst->pDrvCtrl;
|
|
*(UINT32*)pArgs = (UINT32)pDrvCtrl->pPciConfig;
|
|
|
|
return(OK);
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* ftPciMSIProgram - Returns the converted vector address for MSI
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK
|
|
*
|
|
* ERRNO
|
|
*/
|
|
LOCAL STATUS ftPciMSIProgram
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
struct vxbIntDynaVecInfo *dynaVec
|
|
)
|
|
{
|
|
/* routine expect reg offset from internal memory map base addr
|
|
* we can then just or in the pci internal memory map offset
|
|
*/
|
|
|
|
FT_DEBUG_MSG(0, "\nConvert PIMMR data 0x%x conerted 0x%x\n",
|
|
(int)dynaVec->vecAddr,dynaVec->vecAddr | (UINT64)pDrvCtrl->pimmrBase,
|
|
3,4,5,6);
|
|
|
|
|
|
/* TODO: */
|
|
/* dynaVec->vecAddr |= (UINT64)((UINT32)pDrvCtrl->pimmrBase); */
|
|
|
|
/* uartf("%s,%d: Addr of MSI: .\r\n",__FILE__,__LINE__); */
|
|
|
|
|
|
|
|
return (vxbPciMSIProgram (pDev,dynaVec));
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftPciInterruptInfo - Returns the PCI interrupt info ptr from the bus
|
|
* controller.
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK, or ERROR if this library is not initialized
|
|
*
|
|
* ERRNO
|
|
*/
|
|
LOCAL STATUS ftPciInterruptInfo
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
char * pArgs
|
|
)
|
|
{
|
|
FT_PCI_DRV_CTRL *pDrvCtrl = (FT_PCI_DRV_CTRL *)pInst->pDrvCtrl;
|
|
*(UINT32*)pArgs = (UINT32)pDrvCtrl->pIntInfo;
|
|
|
|
return(OK);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* ftPciRegister - register ftPci driver
|
|
*
|
|
* We use a two-function method here, to delay registration of the driver
|
|
* during debug. This should be left in place when the driver is released.
|
|
*
|
|
*/
|
|
|
|
void ftPciRegister(void)
|
|
{
|
|
vxbDevRegister((struct vxbDevRegInfo *)&ftPciDevRegistration);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* ftPciInstInit - initialize ftPci device
|
|
*
|
|
* This is the ftPci initialization routine.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* This routine is called early during system initialization, and
|
|
* *MUST NOT* make calls to OS facilities such as memory allocation
|
|
* and I/O.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO
|
|
*/
|
|
|
|
LOCAL void ftPciInstInit
|
|
(
|
|
VXB_DEVICE_ID pInst
|
|
)
|
|
{
|
|
STATUS stat;
|
|
FT_PCI_DRV_CTRL * pDrvCtrl;
|
|
struct hcfDevice * pHcf;
|
|
|
|
/* allocate pDrvCtrl */
|
|
|
|
pDrvCtrl = (FT_PCI_DRV_CTRL *)hwMemAlloc(sizeof(*pDrvCtrl));
|
|
|
|
if (pDrvCtrl == NULL)
|
|
return;
|
|
|
|
vxbRegMap (pInst, 0, &pDrvCtrl->handle);
|
|
pDrvCtrl->regBase = pInst->pRegBase[0];
|
|
ft_pcicfg_va_base =(VIRT_ADDR) pDrvCtrl->regBase ;
|
|
|
|
pDrvCtrl->initDone = FALSE;
|
|
pDrvCtrl->pInst = pInst;
|
|
|
|
/* magic number = "ftPci" */
|
|
|
|
pDrvCtrl->magicNumber1 = 0x6D383578;
|
|
pDrvCtrl->magicNumber2 = 0x78506369;
|
|
|
|
|
|
/* extract BSP information */
|
|
|
|
pHcf = (struct hcfDevice *)hcfDeviceGet(pInst);
|
|
pDrvCtrl->pHcf = pHcf;
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The mem32Addr resource specifies the
|
|
* 32-bit prefetchable memory address pool base address. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "mem32Addr", HCF_RES_ADDR, &pDrvCtrl->mem32Addr);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The mem32Size resource specifies the
|
|
* 32-bit prefetchable memory address pool size. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "mem32Size", HCF_RES_INT, (void *)&pDrvCtrl->mem32Size);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The memIo32Addr resource specifies the
|
|
* 32-bit non-prefetchable memory address pool base address. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "memIo32Addr", HCF_RES_ADDR, &pDrvCtrl->memIo32Addr);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The memIo32Size resource specifies the
|
|
* 32-bit non-prefetchable memory address pool size. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "memIo32Size", HCF_RES_INT, (void *)&pDrvCtrl->memIo32Size);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The io32Addr resource specifies the
|
|
* 32-bit I/O address pool base address. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "io32Addr", HCF_RES_ADDR, &pDrvCtrl->io32Addr);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The io32Size resource specifies the
|
|
* 32-bit I/O address pool size. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "io32Size", HCF_RES_INT, (void *)&pDrvCtrl->io32Size);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The pimmrBase resource specifies the
|
|
* PIMMR base address. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "pimmrBase", HCF_RES_ADDR, &pDrvCtrl->pimmrBase);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The mstrMemBus resource specifies the
|
|
* address on CPU from PCI buss. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "mstrMemBus", HCF_RES_ADDR, &pDrvCtrl->mstrMemBus);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The lclMemAddr resource specifies the
|
|
* local memory address on the BSP. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "lclMemAddr", HCF_RES_ADDR, &pDrvCtrl->lclMemAddr);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The lclMemMapSize resource specifies the
|
|
* mappable local memory size on the BSP. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "lclMemMapSize", HCF_RES_INT, (void *)&pDrvCtrl->lclMemMapSize);
|
|
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The owAttrMem resource specifies the
|
|
* outbound attributes register setting for prefetchable memory. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "owAttrMem", HCF_RES_INT, (void *)&pDrvCtrl->owAttrMem);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The owAttrMemIo resource specifies the
|
|
* outbound attributes register setting for non-prefetchable memory. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "owAttrMemIo", HCF_RES_INT, (void *)&pDrvCtrl->owAttrMemIo);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The owAttrMem resource specifies the
|
|
* outbound attributes register setting for I/O. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "owAttrIo", HCF_RES_INT, (void *)&pDrvCtrl->owAttrIo);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The iwAttr resource specifies the
|
|
* inbound attributes. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "iwAttr", HCF_RES_INT, (void *)&pDrvCtrl->iwAttr);
|
|
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The maxBusSet resource specifies the
|
|
* highest sub-bus number. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "maxBusSet", HCF_RES_INT, (void *)&pDrvCtrl->pciMaxBus);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The pciExpressHost resource specifies the
|
|
* PCI Express Host is enabled or not. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "pciExpressHost", HCF_RES_INT, (void*)&pDrvCtrl->pciExpressHost);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The autoConfig resource specifies whether
|
|
* Auto Configuration is enabled or not. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "autoConfig", HCF_RES_INT, (void*)&pDrvCtrl->autoConfig);
|
|
/*
|
|
* resourceDesc {
|
|
* The funcPirqEnable resource specifies the
|
|
* function pointer points to the BSP specific
|
|
* function which enables or disbables PCI
|
|
* PIRQ direct handlig. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "funcPirqEnable", HCF_RES_ADDR, (void*)&pDrvCtrl->funcPirqEnable);
|
|
/*
|
|
* resourceDesc {
|
|
* The msiEnable resource specifies the
|
|
* MSI is enabled or not. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "msiEnable", HCF_RES_INT, (void*)&pDrvCtrl->msiEnable);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The dynamicInterrupts resource specifies the
|
|
* Dynamic Interrupts are enabled or not. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "dynamicInterrupts", HCF_RES_INT, (void*)&pDrvCtrl->dynamicInterrupts);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The msiAddress resource specifies the
|
|
* MSI base address. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "msiAddress", HCF_RES_INT, (void*)&pDrvCtrl->msiAddress);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The msiData resource specifies the
|
|
* MSI data. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "msiData", HCF_RES_INT, (void*)&pDrvCtrl->msiData);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The msiDataWorkaround resource specifies the
|
|
* MSI data workaround is required or not. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "msiDataWorkaround", HCF_RES_INT, (void*)&pDrvCtrl->msiDataWorkaround);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The msiDataWorkaroundAddr resource specifies the
|
|
* MSI data workaround base address. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "msiDataWorkaroundAddr", HCF_RES_INT, (void*)&pDrvCtrl->msiDataWorkaroundAddr);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The extIntMap resource specifies the
|
|
* address of the PCI interrupt mapping table. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "extIntMap", HCF_RES_ADDR, (void*)&pDrvCtrl->extIntMap);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The extIntMap resource specifies the
|
|
* size of the PCI interrupt mapping table. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "extIntMapSize", HCF_RES_INT, (void*)&pDrvCtrl->extIntMapSize);
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The pciEx2ErrataFlag resource specifies the
|
|
* flag to use workaround for PCI-Express EX2 Errata. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "pciEx2ErrataFlag",HCF_RES_INT,(void*)&pDrvCtrl->pciEx2ErrataFlag);
|
|
|
|
pInst->pDrvCtrl = pDrvCtrl;
|
|
|
|
pDrvCtrl->bridgeInitFailed = FALSE;
|
|
|
|
|
|
globalBusCtrlID = pInst;
|
|
|
|
|
|
/* initialize PCI configuration library */
|
|
pDrvCtrl->pIntInfo = (struct vxbPciInt *)hwMemAlloc(sizeof(struct vxbPciInt));
|
|
if(pDrvCtrl->pIntInfo == NULL)
|
|
return;
|
|
|
|
vxbPciIntLibInit(pDrvCtrl->pIntInfo);
|
|
|
|
pDrvCtrl->pPciConfig = (struct vxbPciConfig*)hwMemAlloc(sizeof(struct vxbPciConfig));
|
|
if(pDrvCtrl->pPciConfig == NULL)
|
|
return;
|
|
|
|
SPIN_LOCK_ISR_INIT (&pDrvCtrl->spinlockIsr, 0);
|
|
|
|
if (vxbPciConfigLibInit(pDrvCtrl->pPciConfig,
|
|
pDrvCtrl->pciMaxBus) != OK)
|
|
return;
|
|
|
|
/* initialize PCI interrupt library */
|
|
|
|
pInst->pMethods = &ftPci_methods[0];
|
|
|
|
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* ftPciInstInit2 - initialize ftPci device
|
|
*
|
|
*/
|
|
|
|
LOCAL void ftPciInstInit2
|
|
(
|
|
VXB_DEVICE_ID pInst
|
|
)
|
|
{
|
|
|
|
FT_PCI_DRV_CTRL * pDrvCtrl = pInst->pDrvCtrl;
|
|
|
|
vxbBusAnnounce(pInst, VXB_BUSID_PCI);
|
|
if(pDrvCtrl->autoConfig==TRUE)
|
|
{
|
|
vxbPciAutoConfig(pInst);
|
|
|
|
}
|
|
if (pDrvCtrl->funcPirqEnable != NULL)
|
|
(*pDrvCtrl->funcPirqEnable) (TRUE);
|
|
|
|
vxbPciBusTypeInit(pInst);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* ftPciInstConnect - connect ftPci device to I/O system
|
|
*
|
|
* Nothing to do here. We want serial channels available for output reasonably
|
|
* early during the boot process. Because this is a serial channel, we connect
|
|
* to the I/O system in ftPciInstInit2() instead of here.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO
|
|
*/
|
|
|
|
LOCAL void ftPciInstConnect
|
|
(
|
|
VXB_DEVICE_ID pInst
|
|
)
|
|
{
|
|
|
|
FT_DEBUG_MSG(1,"ftPciInstConnect(): called \n",1,2,3,4,5,6);
|
|
|
|
|
|
}
|
|
|
|
|
|
#ifdef FT_DEBUG_ENABLE
|
|
|
|
/******************************************************************************
|
|
*
|
|
* ftPcipDrvCtrlShow - show pDrvCtrl for ftPci bus controller
|
|
*
|
|
*/
|
|
|
|
int ftPcipDrvCtrlShow
|
|
(
|
|
VXB_DEVICE_ID pInst
|
|
)
|
|
{
|
|
FT_PCI_DRV_CTRL * pDrvCtrl;
|
|
int i;
|
|
union
|
|
{
|
|
UINT32 i[2];
|
|
char magic[10];
|
|
} magic;
|
|
|
|
if ( pInst == NULL )
|
|
pInst = pFtPciDrvCtrl0->pInst;
|
|
pDrvCtrl = pInst->pDrvCtrl;
|
|
|
|
printf("pDrvCtrl @ 0x%08x\n", pDrvCtrl);
|
|
|
|
printf(" pInst @ 0x%08x\n", pDrvCtrl->pInst);
|
|
printf(" pHcf @ 0x%08x\n", pDrvCtrl->pHcf);
|
|
|
|
bzero(magic.magic,10);
|
|
magic.i[0] = pDrvCtrl->magicNumber1;
|
|
magic.i[1] = pDrvCtrl->magicNumber2;
|
|
printf(" magic = \"%s\"\n", &magic.magic[0]);
|
|
|
|
printf(" mem @ 0x%08x, size %d (0x%08x)\n",
|
|
pDrvCtrl->mem32Addr, pDrvCtrl->mem32Size,
|
|
pDrvCtrl->mem32Size);
|
|
|
|
printf(" memIO @ 0x%08x, size %d (0x%08x)\n",
|
|
pDrvCtrl->memIo32Addr, pDrvCtrl->mem32Size,
|
|
pDrvCtrl->memIo32Size);
|
|
|
|
printf(" io32 @ 0x%08x, size %d (0x%08x)\n",
|
|
pDrvCtrl->io32Addr, pDrvCtrl->mem32Size,
|
|
pDrvCtrl->io32Size);
|
|
|
|
printf(" pimmr @ 0x%08x\n", pDrvCtrl->pimmrBase);
|
|
printf(" mstrMemBus @ 0x%08x\n", pDrvCtrl->mstrMemBus);
|
|
printf(" lclMemAddr @ 0x%08x\n", pDrvCtrl->lclMemAddr);
|
|
printf(" lclMemMapSize = 0x%08x\n", pDrvCtrl->lclMemMapSize);
|
|
printf(" autoConfig = 0x%08x\n", pDrvCtrl->autoConfig);
|
|
printf(" pciExpressHost = 0x%08x\n", pDrvCtrl->pciExpressHost);
|
|
|
|
|
|
printf(" Init done: %s\n",
|
|
pDrvCtrl->initDone ? "TRUE" : "FALSE");
|
|
|
|
return(0);
|
|
}
|
|
|
|
#endif /* FT_DEBUG_ENABLE */
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ftPciDevControl - device control routine
|
|
*
|
|
* This routine handles manipulation of downstream devices, such as
|
|
* interrupt management.
|
|
*
|
|
*/
|
|
|
|
LOCAL STATUS ftPciDevControl
|
|
(
|
|
VXB_DEVICE_ID devID,
|
|
pVXB_DEVCTL_HDR pBusDevControl
|
|
)
|
|
{
|
|
VXB_DEVICE_ID busCtrlID;
|
|
struct vxbIntDynaVecInfo dynaVec;
|
|
FT_PCI_DRV_CTRL *pDrvCtrl;
|
|
|
|
VXB_ASSERT(devID != NULL && pBusDevControl != NULL, ERROR)
|
|
|
|
busCtrlID = vxbDevParent(devID);
|
|
pDrvCtrl = ((FT_PCI_DRV_CTRL *)busCtrlID->pDrvCtrl);
|
|
|
|
switch ( pBusDevControl->vxbAccessId)
|
|
{
|
|
case VXB_ACCESS_INT_VEC_GET:
|
|
{
|
|
pVXB_ACCESS_INT_VECTOR_GET accessVectorGet;
|
|
struct pciIntrEntry * pciIntInfo;
|
|
pciIntInfo = (struct pciIntrEntry *)(devID->pIntrInfo);
|
|
|
|
accessVectorGet = (pVXB_ACCESS_INT_VECTOR_GET) pBusDevControl;
|
|
|
|
/*
|
|
* Check if MSI is enabled and if device is MSI capable
|
|
* while it is getting registered.
|
|
*/
|
|
|
|
if ((pDrvCtrl->dynamicInterrupts==TRUE) &&
|
|
(pDrvCtrl->msiEnable == TRUE) &&
|
|
(vxbPciMSIIsCap (devID) == TRUE))
|
|
{
|
|
accessVectorGet->pIntVector = (VOIDFUNCPTR*)VXB_INTR_DYNAMIC;
|
|
return(OK);
|
|
}
|
|
|
|
if (pDrvCtrl->extIntMap != NULL)
|
|
{
|
|
struct vxbPciDevice * pPciDev;
|
|
int devNo;
|
|
int intNum;
|
|
|
|
pPciDev = (struct vxbPciDevice *)devID->pBusSpecificDevInfo;
|
|
devNo = pPciDev->pciDev;
|
|
|
|
intNum = ftPciIntNumGet (devID, pBusDevControl, devNo);
|
|
if (intNum == ERROR)
|
|
return ERROR;
|
|
|
|
accessVectorGet->pIntVector = (VOIDFUNCPTR*)INUM_TO_IVEC(intNum);
|
|
|
|
return(OK);
|
|
}
|
|
|
|
/* check if the index is valid */
|
|
|
|
if (accessVectorGet->intIndex >= 255)
|
|
return ERROR;
|
|
|
|
accessVectorGet->pIntVector =
|
|
(VOIDFUNCPTR*)INUM_TO_IVEC(pciIntInfo->intVecInfo[accessVectorGet->intIndex].index);
|
|
|
|
return(OK);
|
|
}
|
|
|
|
case VXB_ACCESS_INT_CONNECT:
|
|
{
|
|
pVXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
|
|
struct pciIntrEntry * pInterruptInfo;
|
|
STATUS retVal;
|
|
|
|
/* get appropriate structures */
|
|
|
|
accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
|
|
pInterruptInfo = (struct pciIntrEntry *)(devID->pIntrInfo);
|
|
|
|
|
|
/*
|
|
* check if the interrupt vector is set to a dynamic one;
|
|
* This only happens when the device is already registered
|
|
* and checked for MSI enable and MSI capability.
|
|
*/
|
|
|
|
if (pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector
|
|
==(VOIDFUNCPTR*) VXB_INTR_DYNAMIC)
|
|
{
|
|
dynaVec.isr = accessIntrInfo->pISR;
|
|
dynaVec.pArg = accessIntrInfo->pParameter;
|
|
|
|
retVal=ERROR;
|
|
|
|
if(_func_vxbIntDynaConnect!=NULL)
|
|
retVal = _func_vxbIntDynaConnect(devID,
|
|
1,
|
|
&dynaVec);
|
|
|
|
|
|
if (retVal == OK)
|
|
return(OK);
|
|
|
|
/* Drop through to the original mechanism and prevent further
|
|
attempts if function not available or fails */
|
|
pDrvCtrl->dynamicInterrupts=FALSE;
|
|
|
|
}
|
|
|
|
/* connect the interrupt */
|
|
|
|
retVal = vxbPciIntConnect(devID,
|
|
(VOIDFUNCPTR*)pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector,
|
|
(VOIDFUNCPTR)accessIntrInfo->pISR,
|
|
(int)accessIntrInfo->pParameter
|
|
);
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
case VXB_ACCESS_INT_ENABLE:
|
|
{
|
|
pVXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
|
|
struct pciIntrEntry * pInterruptInfo;
|
|
STATUS retVal;
|
|
|
|
accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
|
|
pInterruptInfo = (struct pciIntrEntry *)(devID->pIntrInfo);
|
|
|
|
/*
|
|
* check if the interrupt vector is set to a dynamic one;
|
|
* This only happens when the device is already registered
|
|
* and checked for MSI enable and MSI capability.
|
|
*/
|
|
|
|
if (pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector
|
|
== (VOIDFUNCPTR*)VXB_INTR_DYNAMIC )
|
|
{
|
|
retVal = vxbIntEnable(devID,
|
|
0,
|
|
(VOIDFUNCPTR)accessIntrInfo->pISR,
|
|
(void*)accessIntrInfo->pParameter);
|
|
return (retVal);
|
|
}
|
|
|
|
retVal = intEnable(IVEC_TO_INUM(pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector));
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
|
|
case VXB_ACCESS_INT_DISABLE:
|
|
{
|
|
pVXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
|
|
struct pciIntrEntry * pInterruptInfo;
|
|
STATUS retVal;
|
|
|
|
accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
|
|
pInterruptInfo = (struct pciIntrEntry *)(devID->pIntrInfo);
|
|
|
|
|
|
/*
|
|
* check if the interrupt vector is set to a dynamic one;
|
|
* This only happens when the device is already registered
|
|
* and checked for MSI enable and MSI capability.
|
|
*/
|
|
|
|
if (pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector
|
|
==(VOIDFUNCPTR*)VXB_INTR_DYNAMIC )
|
|
{
|
|
retVal = vxbIntDisable(devID,
|
|
0,
|
|
(VOIDFUNCPTR)accessIntrInfo->pISR,
|
|
(void*)accessIntrInfo->pParameter);
|
|
return(retVal);
|
|
}
|
|
|
|
/* disable the interrupt */
|
|
|
|
retVal = intDisable(IVEC_TO_INUM(pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector));
|
|
|
|
return(retVal);
|
|
|
|
}
|
|
|
|
case VXB_ACCESS_INT_ACKNOWLEDGE:
|
|
return OK;
|
|
|
|
case VXB_ACCESS_INT_DISCONN:
|
|
return(ERROR);
|
|
|
|
default:
|
|
return ERROR;
|
|
}
|
|
|
|
}
|
|
/*******************************************************************************
|
|
*
|
|
* ftPciIntNumGet - get int num for specified device
|
|
*
|
|
* This routine looks through the interrupt table passed in as extIntMap and
|
|
* and returns the appropriate value, or ERROR, if the device number is not
|
|
* found.
|
|
*
|
|
*/
|
|
|
|
LOCAL int ftPciIntNumGet
|
|
(
|
|
VXB_DEVICE_ID devID,
|
|
pVXB_DEVCTL_HDR pBusDevControl,
|
|
int devNo
|
|
)
|
|
{
|
|
pVXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
|
|
int l;
|
|
UINT8 header;
|
|
#ifndef VXB_LEGACY_ACCESS
|
|
PCI_HARDWARE * pPciDev = (PCI_HARDWARE *) devID->pBusSpecificDevInfo;
|
|
#endif /* !VXB_LEGACY_ACCESS */
|
|
int pciIntSlots = pFtPciDrvCtrl0->extIntMapSize;
|
|
int * pciIntMap = pFtPciDrvCtrl0->extIntMap;
|
|
int * pPciInt;
|
|
|
|
accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
|
|
|
|
if (accessIntrInfo->intIndex == 0)
|
|
{
|
|
for (pPciInt = pciIntMap, l = 0; l < pciIntSlots; pPciInt += 5, l++)
|
|
{
|
|
if (devNo == pPciInt[0])
|
|
return pPciInt[accessIntrInfo->intIndex + 1];
|
|
}
|
|
return ERROR;
|
|
}
|
|
else if (0 < accessIntrInfo->intIndex && accessIntrInfo->intIndex < 4)
|
|
{
|
|
FT_PCI_CFG_READ(devID, PCI_CFG_HEADER_TYPE, 1, header);
|
|
|
|
if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC)
|
|
{
|
|
FT_DEBUG_MSG(1,"device is not multifunction , illegal intPin %d\n",accessIntrInfo->intIndex,2,3,4,5,6);
|
|
return ERROR;
|
|
}
|
|
else
|
|
{
|
|
for (pPciInt = pciIntMap, l = 0; l < pciIntSlots; pPciInt += 5, l++)
|
|
{
|
|
if (devNo == pPciInt[0])
|
|
return pPciInt[accessIntrInfo->intIndex + 1];
|
|
}
|
|
return ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FT_DEBUG_MSG(1,"illegal intPin %d, allowed 0,1,2,3\n",accessIntrInfo->intIndex,2,3,4,5,6);
|
|
return ERROR;
|
|
}
|
|
return ERROR;
|
|
}
|
|
|
|
|
|
int pci_config_bdf_pack_ex
|
|
(
|
|
int busno,
|
|
int devno,
|
|
int fnno
|
|
)
|
|
{
|
|
return(((busno << 20) & 0x0ff00000) |
|
|
((devno << 15) & 0x000f8000) |
|
|
((fnno << 12) & 0x00007000));
|
|
}
|
|
|
|
BOOL ft_pci_isbridge
|
|
(
|
|
int busno, /* bus number */
|
|
int devno, /* device number */
|
|
int fnno /* function number */
|
|
)
|
|
{
|
|
volatile UINT32 addr = 0;
|
|
volatile UINT16 pci_class = 0;
|
|
volatile UINT8 pci_head = 0;
|
|
|
|
|
|
|
|
/* Header Type: bit7: 0:single func. 1: multi func
|
|
* bit6-0: 00: normal dev. 01: normal bridge. 02: CARDBUS bridge
|
|
*/
|
|
addr = (ft_pcicfg_va_base +
|
|
pci_config_bdf_pack_ex (busno, devno, fnno) + PCI_CFG_HEADER_TYPE );
|
|
pci_head = *(volatile UINT8*) addr;
|
|
pci_head &= PCI_HEADER_TYPE_MASK;
|
|
|
|
addr = (ft_pcicfg_va_base +
|
|
pci_config_bdf_pack_ex (busno, devno, fnno) + PCI_CFG_SUBCLASS );
|
|
pci_class = *(volatile UINT16*) addr;
|
|
|
|
|
|
if((pci_class == ((PCI_CLASS_BRIDGE_CTLR << 8) + PCI_SUBCLASS_P2P_BRIDGE)) ||
|
|
(pci_class == ((PCI_CLASS_BRIDGE_CTLR << 8) + PCI_SUBCLASS_CARDBUS_BRIDGE)) ||
|
|
(pci_head == PCI_HEADER_PCI_PCI) ||(pci_head == PCI_HEADER_PCI_CARDBUS))
|
|
{
|
|
return TRUE; /* is bridge */
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int ft_pci_cfg_read
|
|
(
|
|
pci_dev_addr_t *dev,
|
|
UINT32 offset,
|
|
pci_cfg_trans_width_t size,
|
|
void *data
|
|
)
|
|
{
|
|
UINT8 busno = 0;
|
|
UINT8 devno = 0;
|
|
UINT8 fnno = 0;
|
|
volatile UINT32 addr = 0;
|
|
|
|
if(NULL == dev)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
busno = dev->busno;
|
|
devno = dev->devno;
|
|
fnno = dev->fnno;
|
|
|
|
addr = (ft_pcicfg_va_base +
|
|
pci_config_bdf_pack_ex (busno, devno, fnno) + offset);
|
|
|
|
switch(size)
|
|
{
|
|
case PCI_CFG_TRANS_8BIT:
|
|
*((UINT8*)data) = *((volatile UINT8*) addr);
|
|
break;
|
|
|
|
case PCI_CFG_TRANS_16BIT:
|
|
*((UINT16*)data) = *((volatile UINT16*) addr);
|
|
break;
|
|
|
|
case PCI_CFG_TRANS_32BIT:
|
|
*((UINT32*)data) = *((volatile UINT32*) addr);
|
|
break;
|
|
|
|
default:
|
|
|
|
return ERROR;
|
|
}
|
|
|
|
return(OK);
|
|
}
|
|
|
|
int ft_pci_cfg_write
|
|
(
|
|
pci_dev_addr_t *dev,
|
|
UINT32 offset,
|
|
pci_cfg_trans_width_t size,
|
|
UINT32 data
|
|
)
|
|
{
|
|
UINT8 busno = 0;
|
|
UINT8 devno = 0;
|
|
UINT8 fnno = 0;
|
|
volatile UINT32 addr = 0;
|
|
|
|
|
|
if(NULL == dev)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
busno = dev->busno;
|
|
devno = dev->devno;
|
|
fnno = dev->fnno;
|
|
|
|
|
|
addr = (ft_pcicfg_va_base +
|
|
pci_config_bdf_pack_ex (busno, devno, fnno) + offset);
|
|
|
|
switch(size)
|
|
{
|
|
case PCI_CFG_TRANS_8BIT:
|
|
*((volatile UINT8*)addr) = (UINT8)data;
|
|
break;
|
|
|
|
case PCI_CFG_TRANS_16BIT:
|
|
*((volatile UINT16*)addr) = (UINT16)data;
|
|
break;
|
|
|
|
case PCI_CFG_TRANS_32BIT:
|
|
*((volatile UINT32*)addr) = (UINT32)data;
|
|
break;
|
|
|
|
default:
|
|
|
|
return ERROR;
|
|
}
|
|
|
|
return(OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
int ftPciCfgRead
|
|
(
|
|
UINT8 b,
|
|
UINT8 d,
|
|
UINT8 f,
|
|
unsigned int offset,
|
|
unsigned int size,
|
|
void *data
|
|
)
|
|
{
|
|
pci_dev_addr_t dev;
|
|
|
|
dev.busno = b;
|
|
dev.devno = d;
|
|
dev.fnno = f;
|
|
|
|
return ft_pci_cfg_read(&dev,(UINT32)offset,
|
|
(pci_cfg_trans_width_t)size,data);
|
|
|
|
}
|
|
|
|
int ftPciCfgWrite
|
|
(
|
|
UINT8 b,
|
|
UINT8 d,
|
|
UINT8 f,
|
|
unsigned int offset,
|
|
unsigned int size,
|
|
UINT32 data
|
|
)
|
|
{
|
|
pci_dev_addr_t dev;
|
|
|
|
dev.busno = b;
|
|
dev.devno = d;
|
|
dev.fnno = f;
|
|
|
|
return ft_pci_cfg_write(&dev, (UINT32)offset,
|
|
(pci_cfg_trans_width_t)size,data);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* ftPciMethodConvertBaseAddress - PCI BAR address conversion method
|
|
*
|
|
* This routine implements the convertBaseAddress method exported by this
|
|
* driver via its VxBus methods table. The vxbPci.c module uses this
|
|
* routine to apply fixups to the addresses read from the BARs on
|
|
* devices that are enumerated on this bus.
|
|
*
|
|
* RETURNS: ERROR if base address is invalid, otherwise OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS ftPciMethodConvertBaseAddress
|
|
(
|
|
VXB_DEVICE_ID devID, /* device info */
|
|
UINT32 * pBaseAddr /* pointer to base address */
|
|
)
|
|
{
|
|
UINT32 baseAddress;
|
|
FT_PCI_DRV_CTRL * pDrvCtrl;
|
|
UINT32 param1 = 0;
|
|
|
|
pDrvCtrl = devID->pDrvCtrl;
|
|
|
|
/* if base address pointer is NULL, return ERROR */
|
|
|
|
if (pBaseAddr == NULL)
|
|
return ERROR;
|
|
|
|
baseAddress = *pBaseAddr;
|
|
|
|
/* Use the mask values to get the base address */
|
|
|
|
if ((baseAddress & PCI_BAR_SPACE_MASK) == PCI_BAR_SPACE_IO)
|
|
{
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* See the previous description for the ioStart resource. }
|
|
*/
|
|
devResourceGet (pDrvCtrl->pHcf, "ioStart",
|
|
HCF_RES_ADDR, (void *)¶m1);
|
|
baseAddress &= 0xFFFFFFFC;
|
|
baseAddress += param1;
|
|
}
|
|
else
|
|
baseAddress &= 0xFFFFFFF0;
|
|
|
|
|
|
/* update the converted base address */
|
|
|
|
*pBaseAddr = baseAddress;
|
|
|
|
return (OK);
|
|
}
|
|
|
|
#endif
|
|
|