/*
* PCI auto - configuration library
*
* Author : Matt Porter < mporter @ mvista . com >
*
* Copyright 2000 MontaVista Software Inc .
*
* Modifications for driver model :
* Copyright 2015 Google , Inc
* Written by Simon Glass < sjg @ chromium . org >
*
* SPDX - License - Identifier : GPL - 2.0 +
*/
# include <common.h>
# include <dm.h>
# include <errno.h>
# include <pci.h>
void pciauto_region_init ( struct pci_region * res )
{
/*
* Avoid allocating PCI resources from address 0 - - this is illegal
* according to PCI 2.1 and moreover , this is known to cause Linux IDE
* drivers to fail . Use a reasonable starting value of 0x1000 instead .
*/
res - > bus_lower = res - > bus_start ? res - > bus_start : 0x1000 ;
}
void pciauto_region_align ( struct pci_region * res , pci_size_t size )
{
res - > bus_lower = ( ( res - > bus_lower - 1 ) | ( size - 1 ) ) + 1 ;
}
int pciauto_region_allocate ( struct pci_region * res , pci_size_t size ,
pci_addr_t * bar )
{
pci_addr_t addr ;
if ( ! res ) {
debug ( " No resource " ) ;
goto error ;
}
addr = ( ( res - > bus_lower - 1 ) | ( size - 1 ) ) + 1 ;
if ( addr - res - > bus_start + size > res - > size ) {
debug ( " No room in resource " ) ;
goto error ;
}
res - > bus_lower = addr + size ;
debug ( " address=0x%llx bus_lower=0x%llx " , ( unsigned long long ) addr ,
( unsigned long long ) res - > bus_lower ) ;
* bar = addr ;
return 0 ;
error :
* bar = ( pci_addr_t ) - 1 ;
return - 1 ;
}
static void pciauto_show_region ( const char * name , struct pci_region * region )
{
pciauto_region_init ( region ) ;
debug ( " PCI Autoconfig: Bus %s region: [%llx-%llx], \n "
" \t \t Physical Memory [%llx-%llxx] \n " , name ,
( unsigned long long ) region - > bus_start ,
( unsigned long long ) ( region - > bus_start + region - > size - 1 ) ,
( unsigned long long ) region - > phys_start ,
( unsigned long long ) ( region - > phys_start + region - > size - 1 ) ) ;
}
void pciauto_config_init ( struct pci_controller * hose )
{
int i ;
hose - > pci_io = NULL ;
hose - > pci_mem = NULL ;
hose - > pci_prefetch = NULL ;
for ( i = 0 ; i < hose - > region_count ; i + + ) {
switch ( hose - > regions [ i ] . flags ) {
case PCI_REGION_IO :
if ( ! hose - > pci_io | |
hose - > pci_io - > size < hose - > regions [ i ] . size )
hose - > pci_io = hose - > regions + i ;
break ;
case PCI_REGION_MEM :
if ( ! hose - > pci_mem | |
hose - > pci_mem - > size < hose - > regions [ i ] . size )
hose - > pci_mem = hose - > regions + i ;
break ;
case ( PCI_REGION_MEM | PCI_REGION_PREFETCH ) :
if ( ! hose - > pci_prefetch | |
hose - > pci_prefetch - > size < hose - > regions [ i ] . size )
hose - > pci_prefetch = hose - > regions + i ;
break ;
}
}
if ( hose - > pci_mem )
pciauto_show_region ( " Memory " , hose - > pci_mem ) ;
if ( hose - > pci_prefetch )
pciauto_show_region ( " Prefetchable Mem " , hose - > pci_prefetch ) ;
if ( hose - > pci_io )
pciauto_show_region ( " I/O " , hose - > pci_io ) ;
}