📄 ixp1200pci.c
字号:
return (void*) (((UINT32) PciAddr) + SDRAM_PHYS_BASE);
} else {
/* Other Memspace address */
return (void*) (((UINT32) PciAddr) + PCI_MEM_BASE);
}
}
/******************************************************************************
*
* sysPhysToPci - translate a physical address to a Pci address
*
* This function converts a physical address to a Pci address. This only works
* for PCI Memory space.
*
* RETURNS: the Pci adddress
*/
void * sysPhysToPci
(
void * PhysAddr /* Physical address */
)
{
if ((((UINT32) PhysAddr) >= SDRAM_VIRT_OFFSET) &&
(((UINT32) PhysAddr) < SDRAM_PF_BASE))
{
/* SDRAM address */
return (void*) (((UINT32) PhysAddr) - SDRAM_PHYS_BASE);
} else {
/* Other Memspace address */
return (void*) (((UINT32) PhysAddr) - PCI_MEM_BASE);
}
}
#ifdef AUTO_PCI_CONFIG
/******************************************************************************
*
* sortBars - Sort Bars largest to smallest and assign addresses
*
* This function takes in an array of pointers to BARs and a starting
* PCI address, then it will sort the BARS from largest to smallest. It will
* then align the address appropriately for the first (largest) BAR, and then
* assign increasing addresses with no gaps.
*
* RETURNS: N/A
*/
static void
sortBars
(
PciBar *Bars[], /* Array of pointers to BARs */
const int nBars, /* Number of BARs in array */
UINT32 startAddr /* PCI address at which to start */
)
{
int i, j;
PciBar *tmp;
/* 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;
}
} /* end for j */
} /* end for i */
/* 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;
} /* end for i */
}
/******************************************************************************
*
* addPageEntries - Call sysMmuMapAdd to add page entries for specified range
*
* This function takes a range of addresses containing a gap, and then calls
* sysMmuMapAdd to add page table entries for the one or two memory ranges
* specified.
*
* RETURNS: N/A
*/
static void
addPageEntries
(
UINT32 start, /* Starting PCI address of range*/
UINT32 end, /* Ending PCI address of range */
UINT32 startSkip, /* Starting PCI address of hole */
UINT32 skipLen, /* Ending PCI address of hole */
UINT32 offset /* Offset from PCI address to virtual address */
)
{
UINT32 start1, end1;
start1 = start;
end1 = startSkip;
if (start1 != end1) {
start1 = ROUND_DOWN(start1, PAGE_SIZE);
end1 = ROUND_UP(end1, PAGE_SIZE);
sysMmuMapAdd((void*)(offset + start1), end1-start1,
VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE,
VM_STATE_VALID | VM_STATE_WRITABLE | VM_STATE_CACHEABLE_NOT);
}
start1 = startSkip + skipLen;
end1 = end;
if (start1 != end1) {
start1 = ROUND_DOWN(start1, PAGE_SIZE);
end1 = ROUND_UP(end1, PAGE_SIZE);
sysMmuMapAdd((void*)(offset + start1), end1-start1,
VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE,
VM_STATE_VALID | VM_STATE_WRITABLE | VM_STATE_CACHEABLE_NOT);
}
}
/******************************************************************************
*
* 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 also adds page
* entries to cover the range of PCI space used. It enables PCI transactions
* as defined by INITIAL_PCI_CMD, which defaults to enabling IO transactions.
*
* As a special case, it assigns its own SDRAM space to PCI address zero.
*
* This funciton only has an effect if this processor is the PCI central function.
*
* RETURNS: N/A
*/
void
sysPciAssignAddrs(void)
{
PciBar *memBars[MAX_BARS];
PciBar *ioBars[MAX_BARS];
int nMBars, nIOBars;
int bus, dev, func, i, j;
UINT16 data;
INT32 data32, tmp, size;
#ifndef IXM1200
int central_func;
central_func =
IXP1200_SA_CONTROL_PCF & *(UINT32 *)IXP1200_SA_CONTROL;
if (! central_func)
return;
#endif
/* Assign first device to ourselves */
devices[0].bus = 0;
devices[0].device = 0;
devices[0].func = 0;
devices[0].vendor_id = sysRead16((void*)IXP1200_PCI_VENDOR_ID);
devices[0].device_id = sysRead16((void*)IXP1200_PCI_DEVICE_ID);
devices[0].error = FALSE;
devices[0].bar[CSR_BAR].size = 0x00100000; /* 1 Meg: CSR Mem Base */
devices[0].bar[CSR_BAR].address = 0; /* Mem addr */
devices[0].bar[IO_BAR].size = 0x00000080; /* 128: CSR I/O Base */
devices[0].bar[IO_BAR].address = 1; /* I/O addr */
devices[0].bar[SD_BAR].size = LOCAL_MEM_SIZE_ACTUAL; /* SDRAM Mem Base */
devices[0].bar[SD_BAR].address = 0; /* Mem addr */
devices[0].bar[NO_BAR].size = 0;
nDevices = 1;
nMBars = nIOBars = 0;
/* But SDRAM base first */
memBars[nMBars++] = &devices[0].bar[SD_BAR];
memBars[nMBars++] = &devices[0].bar[CSR_BAR];
ioBars[nIOBars++] = &devices[0].bar[IO_BAR];
func = 0;
for ( bus = 0; bus < PCI_MAX_BUS; bus++ ) {
for (dev = 0; dev < PCI_MAX_DEV; dev++ ) {
pciConfigInWord(bus, dev, func, PCI_CFG_VENDOR_ID, &data);
if (data == 0xFFFF)
continue;
if (nDevices == MAX_DEVICES)
break;
devices[nDevices].bus = bus;
devices[nDevices].device = dev;
devices[nDevices].func = func;
devices[nDevices].vendor_id = data;
pciConfigInWord(bus, dev, func, PCI_CFG_DEVICE_ID, &data);
devices[nDevices].device_id = data;
devices[nDevices].error = FALSE;
for (i=0; i<6; i++) {
pciConfigOutLong(bus, dev, func,
PCI_CFG_BASE_ADDRESS_0 + (4*i),
0xFFFFFFFF);
pciConfigInLong(bus, dev, func,
PCI_CFG_BASE_ADDRESS_0 + (4*i),
&data32);
if (data32 == 0)
break;
devices[nDevices].bar[i].address = (data32 & 1);
if (data32 & 1) {
/* IO space */
tmp = data32 & ~0x00000003;
size = ~(tmp-1);
devices[nDevices].bar[i].size = size;
if (tmp != ~(size-1))
devices[nDevices].error = TRUE;
else {
if (nIOBars < MAX_BARS)
ioBars[nIOBars++] = &devices[nDevices].bar[i];
}
} else {
/* Mem space */
tmp = data32 & ~0x0000000F;
size = ~(tmp-1);
devices[nDevices].bar[i].size = size;
if (tmp != ~(size-1))
devices[nDevices].error = TRUE;
else {
if (nMBars < MAX_BARS)
memBars[nMBars++] = &devices[nDevices].bar[i];
}
}
} /* end for i */
devices[nDevices].bar[i].size = 0;
nDevices++;
} /* end for dev */
} /* end for bus */
/* Sort bars, Leave our SDRAM at Mem zero */
sortBars(memBars+1, nMBars-1, LOCAL_MEM_SIZE_ACTUAL);
sortBars(ioBars, nIOBars, 0);
data = INITIAL_PCI_CMD;
*(UINT32 *)(IXP1200_PCI_MEM_BAR) = devices[0].bar[CSR_BAR].address;
*(UINT32 *)(IXP1200_PCI_IO_BAR) = devices[0].bar[IO_BAR].address;
*(UINT32 *)(IXP1200_PCI_DRAM_BAR) = devices[0].bar[SD_BAR].address;
/* Fix C0/Hyannis PCI CSR bug */
*(volatile int*)(IXP1200_PCI_MEM_BAR);
for (i=1; i<nDevices; i++) {
if (devices[i].error)
continue;
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,
INT_VEC_PIL);
pciConfigOutWord(devices[i].bus,
devices[i].device,
devices[i].func,
PCI_CFG_COMMAND,
data);
} /* end for i */
/* Add page table entries, skip our SDRAM */
addPageEntries(memBars[1]->address, /* start */
memBars[nMBars-1]->address + memBars[nMBars-1]->size, /*end*/
devices[0].bar[CSR_BAR].address, /* skip start */
devices[0].bar[CSR_BAR].size, /* skip len */
PCI_MEM_BASE);
addPageEntries(ioBars[0]->address,
ioBars[nIOBars-1]->address + ioBars[nIOBars-1]->size,
devices[0].bar[IO_BAR].address,
devices[0].bar[IO_BAR].size,
PCI_IO_BASE);
}
#ifdef INCLUDE_AUTO_PCI_CONFIG_SHOW_ROUTINE
/******************************************************************************
*
* pciAddrShow - Shows PCI address assignments
*
* This function prints the PCI address assignments automatically generated.
* It prints a table giving for each device the bus number, device number,
* a flag indicating whether there was an error for that device, and the
* vendor/device ID. Then it lists the BARs for that device, giving the
* size of the region and its address. If the low-order bit of the address
* is "1", then the address corresponds to I/O space, otherwise it is in
* memory space.
*
* RETURNS: N/A
*/
void pciAddrShow(void)
{
int i, j;
for (i=0; i<nDevices; i++) {
printf("bus %d dev %d error %d id %04X%04X\n",
devices[i].bus,
devices[i].device,
devices[i].error,
devices[i].vendor_id,
devices[i].device_id);
for (j=0; devices[i].bar[j].size; j++) {
printf(" size %08X addr %08X\n",
devices[i].bar[j].size,
devices[i].bar[j].address);
}
} /* end for i */
}
/******************************************************************************
*
* pciInfoGet - Retrieves PCI device information
*
* This function retrieves the PCI assignments of the specified device.
* It returns a pointer to a PciDevice structure containing the bus number,
* device number, a flag indicating whether there was an error for that
* device, the vendor/device ID and a lists the BARs indicating the size of
* the region and its address for that device. A NULL pointer will be
* returned if the specified device is not within range of the configured
* devices.
*
* RETURNS: Pointer to PCI device information, or NULL
*/
PciDevice *pciInfoGet
(
UINT16 device
)
{
if(device >= nDevices) return(NULL);
return(&devices[device]);
}
#endif /* ifdef #ifdef INCLUDE_AUTO_PCI_CONFIG_SHOW_ROUTINE */
#endif /* ifdef AUTO_PCI_CONFIG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -