📄 pci.c
字号:
}
else
return FALSE;
}
/************************************************************************
*
* pci_lookup_bar
* Description :
* -------------
*
* Determine base address (physical) of specific BAR of specific device.
*
* If more than one device fits the IDs and function number, the
* device is selected based on the following priority :
*
* 1) Known local (bus 0) device
* 2) First unknown local (bus 0) device found (based on device number)
* 3) First unknown remote (bus != 0) device found (based on device number)
*
* Return values :
* ---------------
*
* TRUE : BAR found
* FALSE : BAR not found
*
************************************************************************/
bool
pci_lookup_bar(
UINT16 vendorid, /* Vendor ID */
UINT16 devid, /* Device ID */
UINT8 function, /* Function number */
UINT8 bar, /* Address of BAR register */
void **param ) /* OUT : Base address of BAR */
{
t_pci_cfg_dev pci_device;
UINT32 i;
/* Default */
*param = NULL;
/* This address must be provided by PCI config manager */
if( pci_lookup_device( vendorid, devid, function, &pci_device ) )
{
for( i=0; i<pci_device.bar_count; i++ )
{
if( pci_device.bar[i].pos == bar )
{
*param =
(void *) ( pci_device.bar[i].start +
(pci_device.bar[i].io ?
pci_device.io_offset :
pci_device.mem_offset) );
return TRUE;
}
}
}
return FALSE;
}
/************************************************************************
*
* pci_display
* Description :
* -------------
*
* Display devices detected during autodetect and display the
* autoconfiguration data (memory space and IO space allocations)
*
* Return values :
* ---------------
*
* None
*
************************************************************************/
void
pci_display(void)
{
t_pci_cfg_dev *dev;
t_pci_bar *bar;
UINT32 i, t;
char msg[200];
UINT32 freq_kHz;
char *known_vendor, *known_device;
UINT8 slotnum;
/* Determine bus frequency */
SYSCON_read(
SYSCON_BOARD_PCI_FREQ_KHZ_ID,
(void *)&freq_kHz,
sizeof(UINT32) );
strcpy( msg , "PCI bus frequency = " );
pci_busfreq_string( &msg[strlen(msg)], freq_kHz );
if( SHELL_PUTS( msg ) ) return;
if( SHELL_PUTS( "\n\nPCI devices:\n" ) ) return;
sprintf( msg, "Bus count = %d, Device count = %d\n",
bus_count, dev_count );
if( SHELL_PUTS( msg ) ) return;
for( i=0; i<dev_count; i++ )
{
if( SHELL_PUTC( '\n' ) )
return;
dev = &dev_data[i];
SEARCH_KNOWN( dev, t )
if( t != known_devs_count )
{
known_vendor = known_devs[t].vendor;
known_device = known_devs[t].device;
}
else
known_vendor = NULL;
sprintf( msg, "Bus = 0x%02x, Dev = 0x%02x", dev->bus, dev->dev );
if(SHELL_PUTS( msg ) ) return;
if( (dev->bus == PCI_BUS_LOCAL) &&
arch_pci_slot( dev->dev, &slotnum ) )
{
sprintf( msg, " (PCI slot %hd)", slotnum );
if(SHELL_PUTS( msg )) return;
}
sprintf( msg, ", Function = 0x%02x\nVendor Id = 0x%04x",
dev->function, dev->vendorid );
if(SHELL_PUTS( msg ) ) return;
if( known_vendor )
{
sprintf( msg, " (%s), Dev ID = 0x%04x (%s)\n",
known_vendor, dev->devid, known_device );
}
else
{
sprintf( msg, ", Dev ID = 0x%04x\n", dev->devid );
}
if(SHELL_PUTS( msg )) return;
sprintf( msg, " Min Gnt = 0x%02x, Max Lat = 0x%02x, Lat Tim = 0x%02x\n",
dev->min_gnt, dev->max_lat, dev->lat_tim );
if( SHELL_PUTS( msg ) ) return;
sprintf( msg, " Int Pin = " );
switch( dev->intpin )
{
case PCI_MMII_INTPIN_A :
strcat( msg, "A" ); break;
case PCI_MMII_INTPIN_B :
strcat( msg, "B" ); break;
case PCI_MMII_INTPIN_C :
strcat( msg, "C" ); break;
case PCI_MMII_INTPIN_D :
strcat( msg, "D" ); break;
default :
strcat( msg, "None" ); break;
}
if( SHELL_PUTS( msg ) ) return;
if( dev->intline == PCI_MMII_INTLINE_NONE )
{
strcpy( msg, ", Int Line = None\n" );
}
else
{
sprintf( msg, ", Int Line = 0x%02x\n", dev->intline );
}
if( SHELL_PUTS( msg ) ) return;
sprintf( msg, " BAR count = 0x%02x\n", dev->bar_count );
if( SHELL_PUTS( msg ) ) return;
for( t=0; t<dev->bar_count; t++ )
{
bar = &dev->bar[t];
if(SHELL_PUTS( ( bar->io == 1 ) ? " IO: " : " MEM:" )) return;
sprintf( msg,
" Pos = 0x%02x, Base(CPU/PCI) = 0x%08x/0x%08x, Size = 0x%08x\n",
bar->pos,
bar->start + (bar->io ? dev->io_offset : dev->mem_offset),
bar->start,
bar->size );
if( SHELL_PUTS( msg ) ) return;
}
}
}
/************************************************************************
*
* pci_busfreq_string
* Description :
* -------------
*
* Format string containing PCI bus freqency in format xx.yy MHz
*
* Return values :
* ---------------
*
* None
*
************************************************************************/
void
pci_busfreq_string(
char *msg,
UINT32 freq_kHz )
{
UINT32 freq_MHz = freq_kHz/1000;
sprintf( msg, "%d MHz", freq_MHz );
/* Calc remaining kHz */
freq_kHz -= freq_MHz*1000;
if( freq_kHz )
{
/* Adjust accuracy (e.g. 33330 kHz => 33.33 MHz, not 33.330 MHz) */
while( (freq_kHz % 10) == 0 )
freq_kHz /= 10;
sprintf( &msg[strlen(msg)-4], ".%d MHz", freq_kHz );
}
}
/************************************************************************
*
* pci_check_range
* Description :
* -------------
*
* Validate PCI memory range
*
* Return values :
* ---------------
*
* OK : Range OK
* ERROR_PCI_RANGE : Range not OK
*
************************************************************************/
UINT32
pci_check_range(
UINT32 addr, /* Start of range */
UINT32 size, /* Size of range */
UINT32 *mask ) /* Mask corresponding to range */
{
UINT32 n;
/* Find N (0..31) such that size = 2^N */
for( n = 0; (n <= 31) && (size != (1 << n)); n++ );
if( n == 32 )
return ERROR_PCI_RANGE;
/* Calc mask for bank size register ('1' at all don't care positions) */
*mask = (1 << n) - 1;
/* Check that address is naturally aligned */
if( addr != (addr & ~(*mask)) )
return ERROR_PCI_RANGE;
return OK;
}
/************************************************************************
* Implementation : Static functions
************************************************************************/
/************************************************************************
* detect_devices
************************************************************************/
static UINT32
detect_devices(
UINT32 maxbus,
UINT32 maxdev )
{
UINT32 bus, dev, func;
UINT32 rc;
dev_count = 0;
bus_count = 1; /* The local bus */
for( bus = 0; (bus < bus_count) && (bus < maxbus); bus++ )
{
for( dev = 0; dev <= 31; dev++ )
{
/* Read function 0 */
rc = query_dev( bus, dev, 0, &dev_data[dev_count], maxbus );
if( rc == OK )
{
/* Found device */
dev_count++;
if( dev_count == maxdev )
return OK;
if( dev_data[dev_count-1].multi )
{
/* Multi function device */
for( func = 1; func < PCI_MAX_FUNC; func++ )
{
rc = query_dev( bus, dev, func, &dev_data[dev_count], maxbus );
if( rc == OK )
dev_count++;
if( dev_count == maxdev )
return OK;
}
}
}
}
}
return OK;
}
/************************************************************************
* query_dev
************************************************************************/
static UINT32
query_dev(
UINT32 bus, /* Bus number */
UINT32 devnum, /* Device number */
UINT32 function, /* Device function */
t_pci_cfg_dev *dev, /* Device data */
UINT32 maxbus )
{
UINT32 data;
t_pci_bar *bar;
UINT32 pci_bar_max;
UINT32 rc;
UINT32 i;
UINT8 type;
/* Read configuration data common to all PCI devices */
rc = pci_config_read32( bus, devnum, function, PCI_ID, &data );
if( rc != OK ) return rc;
if(data == 0xffffffff) return ERROR_PCI_ABORT;
dev->devid = (data & PCI_ID_DEVID_MSK) >> PCI_ID_DEVID_SHF;
dev->vendorid = (data & PCI_ID_VENDORID_MSK) >> PCI_ID_VENDORID_SHF;
rc = pci_config_read32( bus, devnum, function, PCI_SC, &data );
if( rc != OK ) return rc;
dev->status = data;
rc = pci_config_read32( bus, devnum, function, PCI_CCREV, &data );
if( rc != OK ) return rc;
dev->class = (data & PCI_CCREV_CC_MSK) >> PCI_CCREV_CC_SHF;
dev->revid = (data & PCI_CCREV_REVID_MSK) >> PCI_CCREV_REVID_SHF;
rc = pci_config_read32( bus, devnum, function, PCI_BHLC, &data );
if( rc != OK ) return rc;
dev->ht = (data & PCI_BHLC_HT_MSK) >> PCI_BHLC_HT_SHF;
if( dev->ht > PCI_HEADERTYPE_MAX )
{
/* Unknown header type, ignore device */
return ERROR_PCI_ABORT;
}
dev->multi = arch_pci_multi( dev, data );
rc = pci_config_read32( bus, devnum, function, PCI_MMII, &data );
if( rc != OK ) return rc;
dev->intpin = (data & PCI_MMII_INTPIN_MSK) >> PCI_MMII_INTPIN_SHF;
/* max_lat and min_gnt actually only valid for header type 0 dev */
dev->max_lat = (data & PCI_MMII_MAXLAT_MSK) >> PCI_MMII_MAXLAT_SHF;
dev->min_gnt = (data & PCI_MMII_MINGNT_MSK) >> PCI_MMII_MINGNT_SHF;
/* Read BARs */
dev->bar_count = 0;
pci_bar_max = DEV_PPB(dev) ? PCI_BAR_MAX_PPB : PCI_BAR_MAX;
for(i = PCI_BAR_MIN; i <= pci_bar_max; i+= sizeof(UINT32) )
{
rc = pci_config_write32( bus, devnum, function, i, 0xFFFFFFFF );
if( rc != OK )
return rc;
rc = pci_config_read32( bus, devnum, function, i, &data );
if( rc != OK )
return rc;
if( data != 0 )
{
bar = &dev->bar[dev->bar_count];
bar->pos = i;
bar->io = (data & PCI_BAR_IO_MSK) >> PCI_BAR_IO_SHF;
if(bar->io)
{
bar->mask = data & PCI_BAR_IOSIZE_MSK;
dev->bar_count++;
}
else
{
type = (data & PCI_BAR_TYPE_MSK) >> PCI_BAR_TYPE_SHF;
if( type == PCI_BAR_TYPE_64 )
{
/* 64 bit addressing. Ignore bar and increase
* loop counter since bar field is 2 words
*/
i += sizeof(UINT32);
}
else if( type != PCI_BAR_TYPE_RSVD )
{
bar->mask = data & PCI_BAR_MEMSIZE_MSK;
bar->prefetch = (data & PCI_BAR_PREFETCH_MSK) >>
PCI_BAR_PREFETCH_SHF;
dev->bar_count++;
}
}
}
}
if( DEV_PPB(dev) )
{
/* PCI-PCI Bridge */
/* Configure bus numbers */
data = (bus << PCI_SSSP_PBN_SHF) |
(bus_count++ << PCI_SSSP_SECBN_SHF ) |
((maxbus-1) << PCI_SSSP_SUBBN_SHF);
rc = pci_config_write32( bus, devnum, function, PCI_SSSP, data );
if( rc != OK ) return rc;
if( (bus == PCI_BUS_LOCAL) && arch_pci_system_slot() )
{
/* Enable backplane clocks (TBD : Use #define for 0x68) */
rc = pci_config_write32( bus, devnum, function, 0x68, 0 );
if( rc != OK ) return rc;
/* Pause for a while to allow target devices on PCI
* backplane to boot.
* This is necessary when interfacing to the RIO
* board, which uses an i960 as PCI South bridge since
* the i960 needs to boot.
*/
DISP_STR( "PCI WAIT" );
sys_wait_ms( 1000 );
DISP_STR( "PCI" );
}
}
/* Everything OK */
dev->bus = bus;
dev->dev = devnum;
dev->function = function;
return OK;
}
/************************************************************************
* config_system
************************************************************************/
static UINT32
config_system(
UINT32 freemem_start, /* First valid mem address */
UINT32 freemem_end, /* First non valid mem address */
UINT32 freeio_start, /* First valid IO address */
UINT32 freeio_end, /* First non valid IO address */
UINT32 maxbus )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -