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

📄 pci.c

📁 MIPS下的boottloader yamon 的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    }
    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 + -