📄 pciiomaplib.c
字号:
*pDeviceNo = deviceNo;
*pFuncNo = funcNo;
status = OK;
cont = FALSE; /* terminate all loops */
continue;
}
/* goto next if current device is single function */
pciConfigInByte (busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE,
&header);
if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC &&
funcNo == 0)
break;
}
return (status);
}
/******************************************************************************
*
* pciDevConfig - configure a device on a PCI bus
*
* This routine configures a device that is on a Peripheral Component
* Interconnect (PCI) bus by writing to the configuration header of the
* selected device.
* It first disables the device by clearing the command register in the
* configuration header. It then sets the I/O and/or memory space base
* address registers, the latency timer value and the cache line size.
* Finally, it re-enables the device by loading the command register with
* the specified command.
*
* NOTE: This routine is designed for Type 0 PCI Configuration Headers ONLY.
* It is NOT usable for configuring, for example, a PCI-to-PCI bridge.
*
* RETURNS: OK always.
*/
STATUS pciDevConfig
(
int pciBusNo, /* PCI bus number */
int pciDevNo, /* PCI device number */
int pciFuncNo, /* PCI function number */
ULONG devIoBaseAdrs, /* device IO base address */
ULONG devMemBaseAdrs, /* device memory base address */
ULONG command /* command to issue */
)
{
INT32 ix;
UINT32 tmp32;
/*
* Disable device by clearing its command register field in its
* configuration header.
*/
pciConfigOutWord (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND, 0);
/*
* Due to system constraints, this is a partial implementation
* of enabling the Base Address Registers (BARs).
* It is hoped that all PCI devices only require at most one
* I/O space and/or one memory space.
* If not, this code will re-allocate the device's memory to
* each BAR implemented. Sounds like future trouble!
*/
for (ix = PCI_CFG_BASE_ADDRESS_0; ix <= PCI_CFG_BASE_ADDRESS_5; ix+=4)
{
/* Write all f's and read back value */
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix, 0xffffffff);
pciConfigInLong (pciBusNo, pciDevNo, pciFuncNo, ix, &tmp32);
/* BAR implemented? */
if (tmp32 == 0)
{
/*
* No! According to the spec, BARs must be implemented
* in sequence starting at BAR 0. So, all done.
*/
break;
}
/* I/O space requested? */
/* Yes, set specified I/O space base address */
if (tmp32 & 0x1)
{
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix,
devIoBaseAdrs | 0x1);
}
/* No, memory space required, set specified base address */
else
{
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix,
devMemBaseAdrs & ~0x1);
}
}
/* Configure Cache Line Size Register */
pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_CACHE_LINE_SIZE,
PCI_CLINE_SZ);
/* Configure Latency Timer */
pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_LATENCY_TIMER,
PCI_LAT_TIMER);
/* Enable the device's capabilities as specified */
pciConfigOutWord (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND,
(UINT16)command);
return (OK);
}
/*******************************************************************************
*
* pciPack - pack parameters for the Configuration Address Register
*
* This routine packs three parameters into one integer for accessing the
* Configuration Address Register
*
* RETURNS:
* packed integer.
*
*/
LOCAL int pciPack
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo /* function number */
)
{
return (((busNo << 16) & 0x00ff0000) |
((deviceNo << 11) & 0x0000f800) |
((funcNo << 8) & 0x00000700));
}
/*******************************************************************************
*
* pciConfigInByte - read one byte from the PCI configuration space
*
* This routine reads one byte from the PCI configuration space
*
* RETURNS:
* OK, or ERROR if this library is not initialized.
*
*/
STATUS pciConfigInByte
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo, /* function number */
int offset, /* offset into the configuration space */
char * pData /* data read from the offset */
)
{
int retval = 0;
int key;
int n;
UINT32 w;
if (pciLibInitStatus != OK) /* sanity check */
return (ERROR);
key = intLock (); /* mutual exclusion start */
switch (pciConfigMech)
{
case PCI_MECHANISM_1:
PCI_OUT_LONG (pciConfigAddr0, pciPack (busNo, deviceNo, funcNo) |
(offset & 0xfc) | 0x80000000);
retval = PCI_IN_BYTE (pciConfigAddr1 + (offset & 0x3));
break;
case PCI_MECHANISM_2:
PCI_OUT_BYTE (pciConfigAddr0, 0xf0 | (funcNo << 1));
PCI_OUT_BYTE (pciConfigAddr1, busNo);
retval = PCI_IN_LONG (pciConfigAddr2 | ((deviceNo & 0x000f) << 8) |
(offset & 0xfc));
PCI_OUT_BYTE (pciConfigAddr0, 0);
retval >>= (offset & 0x03) * 8;
break;
case PCI_MECHANISM_3:
/*
* There are reports of hardware (both target and bridge)
* that do not cope well with non-32-bit-aligned accesses,
* particularly non-32-bit-word accesses. We may be overreacting
* here, but restricting all the accesses to 32-bits should be
* safer. Efficiency should not be an issue during PCI
* configuration. In any case, this code is in the BSP and can be
* changed, if required.
*/
n = offset % 4;
IDSEL(busNo, deviceNo); /* Setup IDSEL Lines */
w = PCI_IN_LONG (((busNo == 0) ? pciConfigAddr0 : pciConfigAddr1) |
MAKE_CFG_ADDR(busNo, deviceNo, funcNo, (offset & ~3)));
retval = (w >> (8 * n)) & 0xFF;
CLR_IDSEL; /* Clear IDSEL Lines */
break;
default:
break;
}
intUnlock (key); /* mutual exclusion stop */
*pData = (char)retval;
return (OK);
}
/*******************************************************************************
*
* pciConfigInWord - read one word from the PCI configuration space
*
* This routine reads one word from the PCI configuration space
*
* RETURNS:
* OK, or ERROR if this library is not initialized.
*
*/
STATUS pciConfigInWord
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo, /* function number */
int offset, /* offset into the configuration space */
short * pData /* data read from the offset */
)
{
int retval = 0;
int key;
int n;
UINT32 w;
if (pciLibInitStatus != OK) /* sanity check */
return (ERROR);
key = intLock (); /* mutual exclusion start */
switch (pciConfigMech)
{
case PCI_MECHANISM_1:
PCI_OUT_LONG (pciConfigAddr0, pciPack (busNo, deviceNo, funcNo) |
(offset & 0xfc) | 0x80000000);
retval = PCI_IN_WORD (pciConfigAddr1 + (offset & 0x2));
break;
case PCI_MECHANISM_2:
PCI_OUT_BYTE (pciConfigAddr0, 0xf0 | (funcNo << 1));
PCI_OUT_BYTE (pciConfigAddr1, busNo);
retval = PCI_IN_LONG (pciConfigAddr2 | ((deviceNo & 0x000f) << 8) |
(offset & 0xfc));
PCI_OUT_BYTE (pciConfigAddr0, 0);
retval >>= (offset & 0x02) * 8;
break;
case PCI_MECHANISM_3:
n = offset % 4;
IDSEL(busNo, deviceNo); /* Setup IDSEL Lines */
w = PCI_IN_LONG (((busNo == 0) ? pciConfigAddr0 : pciConfigAddr1) |
MAKE_CFG_ADDR(busNo, deviceNo, funcNo, (offset & ~3)));
retval = (w >> (8 * n)) & 0xFFFF;
CLR_IDSEL; /* Clear IDSEL Lines */
break;
default:
break;
}
intUnlock (key); /* mutual exclusion stop */
*pData = retval;
return (OK);
}
/*******************************************************************************
*
* pciConfigInLong - read one longword from the PCI configuration space
*
* This routine reads one longword from the PCI configuration space
*
* RETURNS:
* OK, or ERROR if this library is not initialized.
*
*/
STATUS pciConfigInLong
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo, /* function number */
int offset, /* offset into the configuration space */
int * pData /* data read from the offset */
)
{
int key;
volatile int retval = 0;
FAST int ix;
if (pciLibInitStatus != OK) /* sanity check */
return (ERROR);
key = intLock (); /* mutual exclusion start */
switch (pciConfigMech)
{
case PCI_MECHANISM_1:
PCI_OUT_LONG (pciConfigAddr0, pciPack (busNo, deviceNo, funcNo) |
(offset & 0xfc) | 0x80000000);
for (ix = 0; ix < PCI_DELAY; ++ix) /* XXXmas */
;
retval = PCI_IN_LONG (pciConfigAddr1);
break;
case PCI_MECHANISM_2:
PCI_OUT_BYTE (pciConfigAddr0, 0xf0 | (funcNo << 1));
PCI_OUT_BYTE (pciConfigAddr1, busNo);
retval = PCI_IN_LONG (pciConfigAddr2 | ((deviceNo & 0x000f) << 8) |
(offset & 0xfc));
PCI_OUT_BYTE (pciConfigAddr0, 0);
break;
case PCI_MECHANISM_3:
IDSEL(busNo, deviceNo); /* Setup IDSEL Lines */
retval =
PCI_IN_LONG (((busNo == 0) ? pciConfigAddr0 : pciConfigAddr1) |
MAKE_CFG_ADDR(busNo, deviceNo, funcNo, offset));
CLR_IDSEL; /* Clear IDSEL Lines */
break;
default:
break;
}
intUnlock (key); /* mutual exclusion stop */
*pData = retval;
return (OK);
}
/*******************************************************************************
*
* pciConfigOutByte - write one byte to the PCI configuration space
*
* This routine writes one byte to the PCI configuration space.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -