@ -35,6 +35,7 @@ DECLARE_GLOBAL_DATA_PTR;
*/
# include <pci.h>
# include <asm/io.h>
# include <asm/fsl_pci.h>
/* Freescale-specific PCI config registers */
@ -60,35 +61,98 @@ void pciauto_config_init(struct pci_controller *hose);
# define CONFIG_SYS_PCI64_MEMORY_BUS (64ull*1024*1024*1024)
# endif
static int fsl_pci_setup_inbound_windows ( struct pci_region * r )
/* Setup one inbound ATMU window.
*
* We let the caller decide what the window size should be
*/
static void set_inbound_window ( volatile pit_t * pi ,
struct pci_region * r ,
u64 size )
{
struct pci_region * rgn_base = r ;
u64 sz = min ( ( u64 ) gd - > ram_size , ( 1ull < < 32 ) - 1 ) ;
u32 sz = ( __ilog2_u64 ( size ) - 1 ) ;
u32 flag = PIWAR_EN | PIWAR_LOCAL |
PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP ;
out_be32 ( & pi - > pitar , r - > phys_start > > 12 ) ;
out_be32 ( & pi - > piwbar , r - > bus_start > > 12 ) ;
# ifdef CONFIG_SYS_PCI_64BIT
out_be32 ( & pi - > piwbear , r - > bus_start > > 44 ) ;
# else
out_be32 ( & pi - > piwbear , 0 ) ;
# endif
if ( r - > flags & PCI_REGION_PREFETCH )
flag | = PIWAR_PF ;
out_be32 ( & pi - > piwar , flag | sz ) ;
}
static int fsl_pci_setup_inbound_windows ( struct pci_controller * hose ,
u64 out_lo , u8 pcie_cap ,
volatile pit_t * pi )
{
struct pci_region * r = hose - > regions + hose - > region_count ;
u64 sz = min ( ( u64 ) gd - > ram_size , ( 1ull < < 32 ) ) ;
phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS ;
pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS ;
pci_size_t pci_sz = 1ull < < __ilog2_u64 ( sz ) ;
pci_size_t pci_sz ;
debug ( " R0 bus_start: %llx phys_start: %llx size: %llx \n " ,
( u64 ) bus_start , ( u64 ) phys_start , ( u64 ) pci_sz ) ;
pci_set_region ( r + + , bus_start , phys_start , pci_sz ,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
PCI_REGION_PREFETCH ) ;
/* we have no space available for inbound memory mapping */
if ( bus_start > out_lo ) {
printf ( " no space for inbound mapping of memory \n " ) ;
return 0 ;
}
sz - = pci_sz ;
bus_start + = pci_sz ;
phys_start + = pci_sz ;
/* limit size */
if ( ( bus_start + sz ) > out_lo ) {
sz = out_lo - bus_start ;
debug ( " limiting size to %llx \n " , sz ) ;
}
pci_sz = 1ull < < __ilog2_u64 ( sz ) ;
if ( sz ) {
debug ( " R1 bus_start: %llx phys_start: %llx size: %llx \n " ,
/*
* we can overlap inbound / outbound windows on PCI - E since RX & TX
* links a separate
*/
if ( ( pcie_cap = = PCI_CAP_ID_EXP ) & & ( pci_sz < sz ) ) {
debug ( " R0 bus_start: %llx phys_start: %llx size: %llx \n " ,
( u64 ) bus_start , ( u64 ) phys_start , ( u64 ) sz ) ;
pci_set_region ( r , bus_start , phys_start , sz ,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
PCI_REGION_PREFETCH ) ;
/* if we aren't an exact power of two match, pci_sz is smaller
* round it up to the next power of two . We report the actual
* size to pci region tracking .
*/
if ( pci_sz ! = sz )
sz = 2ull < < __ilog2_u64 ( sz ) ;
set_inbound_window ( pi - - , r + + , sz ) ;
sz = 0 ; /* make sure we dont set the R2 window */
} else {
debug ( " R0 bus_start: %llx phys_start: %llx size: %llx \n " ,
( u64 ) bus_start , ( u64 ) phys_start , ( u64 ) pci_sz ) ;
pci_set_region ( r + + , bus_start , phys_start , pci_sz ,
pci_set_region ( r , bus_start , phys_start , pci_sz ,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
PCI_REGION_PREFETCH ) ;
set_inbound_window ( pi - - , r + + , pci_sz ) ;
sz - = pci_sz ;
bus_start + = pci_sz ;
phys_start + = pci_sz ;
pci_sz = 1ull < < __ilog2_u64 ( sz ) ;
if ( sz ) {
debug ( " R1 bus_start: %llx phys_start: %llx size: %llx \n " ,
( u64 ) bus_start , ( u64 ) phys_start , ( u64 ) pci_sz ) ;
pci_set_region ( r , bus_start , phys_start , pci_sz ,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
PCI_REGION_PREFETCH ) ;
set_inbound_window ( pi - - , r + + , pci_sz ) ;
sz - = pci_sz ;
bus_start + = pci_sz ;
phys_start + = pci_sz ;
}
}
# if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
@ -104,23 +168,25 @@ static int fsl_pci_setup_inbound_windows(struct pci_region *r)
( u64 ) CONFIG_SYS_PCI64_MEMORY_BUS ,
( u64 ) CONFIG_SYS_PCI_MEMORY_PHYS ,
( u64 ) pci_sz ) ;
pci_set_region ( r + + ,
pci_set_region ( r ,
CONFIG_SYS_PCI64_MEMORY_BUS ,
CONFIG_SYS_PCI_MEMORY_PHYS ,
pci_sz ,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
PCI_REGION_PREFETCH ) ;
set_inbound_window ( pi - - , r + + , pci_sz ) ;
# else
pci_sz = 1ull < < __ilog2_u64 ( sz ) ;
if ( sz ) {
debug ( " R2 bus_start: %llx phys_start: %llx size: %llx \n " ,
( u64 ) bus_start , ( u64 ) phys_start , ( u64 ) pci_sz ) ;
pci_set_region ( r + + , bus_start , phys_start , pci_sz ,
pci_set_region ( r , bus_start , phys_start , pci_sz ,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
PCI_REGION_PREFETCH ) ;
sz - = pci_sz ;
bus_start + = pci_sz ;
phys_start + = pci_sz ;
set_inbound_window ( pi - - , r + + , pci_sz ) ;
}
# endif
@ -130,7 +196,9 @@ static int fsl_pci_setup_inbound_windows(struct pci_region *r)
" inbound windows -- %lld remaining \n " , sz ) ;
# endif
return r - rgn_base ;
hose - > region_count = r - hose - > regions ;
return 1 ;
}
void fsl_pci_init ( struct pci_controller * hose , u32 cfg_addr , u32 cfg_data )
@ -146,7 +214,10 @@ void fsl_pci_init(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data)
/* Initialize ATMU registers based on hose regions and flags */
volatile pot_t * po = & pci - > pot [ 1 ] ; /* skip 0 */
volatile pit_t * pi = & pci - > pit [ 0 ] ; /* ranges from: 3 to 1 */
volatile pit_t * pi = & pci - > pit [ 2 ] ; /* ranges from: 3 to 1 */
u64 out_hi = 0 , out_lo = - 1ULL ;
u32 pcicsrbar , pcicsrbar_sz ;
# ifdef DEBUG
int neg_link_w ;
@ -154,60 +225,81 @@ void fsl_pci_init(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data)
pci_setup_indirect ( hose , cfg_addr , cfg_data ) ;
/* inbound */
reg + = fsl_pci_setup_inbound_windows ( reg ) ;
/* Handle setup of outbound windows first */
for ( r = 0 ; r < hose - > region_count ; r + + ) {
unsigned long flags = hose - > regions [ r ] . flags ;
u32 sz = ( __ilog2_u64 ( ( u64 ) hose - > regions [ r ] . size ) - 1 ) ;
hose - > region_count = reg - hose - > regions ;
flags & = PCI_REGION_SYS_MEMORY | PCI_REGION_TYPE ;
if ( flags ! = PCI_REGION_SYS_MEMORY ) {
u64 start = hose - > regions [ r ] . bus_start ;
u64 end = start + hose - > regions [ r ] . size ;
for ( r = 0 ; r < hose - > region_count ; r + + ) {
u32 sz = ( __ilog2_u64 ( ( u64 ) hose - > regions [ r ] . size ) - 1 ) ;
if ( hose - > regions [ r ] . flags & PCI_REGION_SYS_MEMORY ) { /* inbound */
u32 flag = PIWAR_EN | PIWAR_LOCAL |
PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP ;
pi - > pitar = ( hose - > regions [ r ] . phys_start > > 12 ) ;
pi - > piwbar = ( hose - > regions [ r ] . bus_start > > 12 ) ;
# ifdef CONFIG_SYS_PCI_64BIT
pi - > piwbear = ( hose - > regions [ r ] . bus_start > > 44 ) ;
# else
pi - > piwbear = 0 ;
# endif
if ( hose - > regions [ r ] . flags & PCI_REGION_PREFETCH )
flag | = PIWAR_PF ;
pi - > piwar = flag | sz ;
pi + + ;
inbound = hose - > regions [ r ] . size > 0 ;
} else { /* Outbound */
po - > powbar = ( hose - > regions [ r ] . phys_start > > 12 ) ;
po - > potar = ( hose - > regions [ r ] . bus_start > > 12 ) ;
out_be32 ( & po - > powbar , hose - > regions [ r ] . phys_start > > 12 ) ;
out_be32 ( & po - > potar , start > > 12 ) ;
# ifdef CONFIG_SYS_PCI_64BIT
po - > potear = ( hose - > regions [ r ] . bus_ start > > 44 ) ;
out_be32 ( & po - > potear , start > > 44 ) ;
# else
po - > potear = 0 ;
out_be32 ( & po - > potear , 0 ) ;
# endif
if ( hose - > regions [ r ] . flags & PCI_REGION_IO )
po - > powar = POWAR_EN | sz |
POWAR_IO_READ | POWAR_IO_WRITE ;
else
po - > powar = POWAR_EN | sz |
POWAR_MEM_READ | POWAR_MEM_WRITE ;
if ( hose - > regions [ r ] . flags & PCI_REGION_IO ) {
out_be32 ( & po - > powar , POWAR_EN | sz |
POWAR_IO_READ | POWAR_IO_WRITE ) ;
} else {
out_be32 ( & po - > powar , POWAR_EN | sz |
POWAR_MEM_READ | POWAR_MEM_WRITE ) ;
out_lo = min ( start , out_lo ) ;
out_hi = max ( end , out_hi ) ;
}
po + + ;
}
}
debug ( " Outbound memory range: %llx:%llx \n " , out_lo , out_hi ) ;
/* setup PCSRBAR/PEXCSRBAR */
pci_hose_write_config_dword ( hose , dev , PCI_BASE_ADDRESS_0 , 0xffffffff ) ;
pci_hose_read_config_dword ( hose , dev , PCI_BASE_ADDRESS_0 , & pcicsrbar_sz ) ;
pcicsrbar_sz = ~ pcicsrbar_sz + 1 ;
if ( out_hi < ( 0x100000000ull - pcicsrbar_sz ) | |
( out_lo > 0x100000000ull ) )
pcicsrbar = 0x100000000ull - pcicsrbar_sz ;
else
pcicsrbar = ( out_lo - pcicsrbar_sz ) & - pcicsrbar_sz ;
pci_hose_write_config_dword ( hose , dev , PCI_BASE_ADDRESS_0 , pcicsrbar ) ;
out_lo = min ( out_lo , ( u64 ) pcicsrbar ) ;
debug ( " PCICSRBAR @ 0x%x \n " , pcicsrbar ) ;
pci_set_region ( reg + + , pcicsrbar , CONFIG_SYS_CCSRBAR_PHYS ,
pcicsrbar_sz , PCI_REGION_SYS_MEMORY ) ;
hose - > region_count + + ;
/* see if we are a PCIe or PCI controller */
pci_hose_read_config_byte ( hose , dev , FSL_PCIE_CAP_ID , & pcie_cap ) ;
/* inbound */
inbound = fsl_pci_setup_inbound_windows ( hose , out_lo , pcie_cap , pi ) ;
for ( r = 0 ; r < hose - > region_count ; r + + )
debug ( " PCI reg:%d %016llx:%016llx %016llx %08x \n " , r ,
( u64 ) hose - > regions [ r ] . phys_start ,
hose - > regions [ r ] . bus_start ,
hose - > regions [ r ] . size ,
hose - > regions [ r ] . flags ) ;
pci_register_hose ( hose ) ;
pciauto_config_init ( hose ) ; /* grab pci_{mem,prefetch,io} */
hose - > current_busno = hose - > first_busno ;
pci - > pedr = 0xffffffff ; /* Clear any errors */
pci - > peer = ~ 0x20140 ; /* Enable All Error Interupts except
out_be32 ( & pci - > pedr , 0xffffffff ) ; /* Clear any errors */
out_be32 ( & pci - > peer , ~ 0x20140 ) ; /* Enable All Error Interupts except
* - Master abort ( pci )
* - Master PERR ( pci )
* - ICCA ( PCIe )
*/
pci_hose_read_config_dword ( hose , dev , PCI_DCR , & temp32 ) ;
pci_hose_read_config_dword ( hose , dev , PCI_DCR , & temp32 ) ;
temp32 | = 0xf000e ; /* set URR, FER, NFER (but not CER) */
pci_hose_write_config_dword ( hose , dev , PCI_DCR , temp32 ) ;
@ -218,14 +310,15 @@ void fsl_pci_init(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data)
# ifdef CONFIG_FSL_PCIE_RESET
if ( ltssm = = 1 ) {
int i ;
debug ( " ....PCIe link error. "
" LTSSM=0x%02x. " , ltssm ) ;
pci - > pdb_stat | = 0x08000000 ; /* assert PCIe reset */
temp32 = pci - > pdb_stat ;
debug ( " ....PCIe link error. " " LTSSM=0x%02x. " , ltssm ) ;
/* assert PCIe reset */
setbits_be32 ( & pci - > pdb_stat , 0x08000000 ) ;
( void ) in_be32 ( & pci - > pdb_stat ) ;
udelay ( 100 ) ;
debug ( " Asserting PCIe reset @%x = %x \n " ,
& pci - > pdb_stat , pci - > pdb_stat ) ;
pci - > pdb_stat & = ~ 0x08000000 ; /* clear reset */
& pci - > pdb_stat , in_be32 ( & pci - > pdb_stat ) ) ;
/* clear PCIe reset */
clrbits_be32 ( & pci - > pdb_stat , 0x08000000 ) ;
asm ( " sync;isync " ) ;
for ( i = 0 ; i < 100 & & ltssm < PCI_LTSSM_L0 ; i + + ) {
pci_hose_read_config_word ( hose , dev , PCI_LTSSM ,
@ -235,6 +328,12 @@ void fsl_pci_init(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data)
" LTSSM=0x%02x. \n " , ltssm ) ;
}
enabled = ltssm > = PCI_LTSSM_L0 ;
/* we need to re-write the bar0 since a reset will
* clear it
*/
pci_hose_write_config_dword ( hose , dev ,
PCI_BASE_ADDRESS_0 , pcicsrbar ) ;
}
# endif
@ -245,8 +344,8 @@ void fsl_pci_init(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data)
return ;
}
pci - > pme_msg_det = 0xffffffff ;
pci - > pme_msg_int_en = 0xffffffff ;
out_be32 ( & pci - > pme_msg_det , 0xffffffff ) ;
out_be32 ( & pci - > pme_msg_int_en , 0xffffffff ) ;
# ifdef DEBUG
pci_hose_read_config_word ( hose , dev , PCI_LSR , & temp16 ) ;
neg_link_w = ( temp16 & 0x3f0 ) > > 4 ;
@ -299,8 +398,8 @@ void fsl_pci_init(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data)
/* Clear all error indications */
if ( pcie_cap = = PCI_CAP_ID_EXP )
pci - > pme_msg_det = 0xffffffff ;
pci - > pedr = 0xffffffff ;
out_be32 ( & pci - > pme_msg_det , 0xffffffff ) ;
out_be32 ( & pci - > pedr , 0xffffffff ) ;
pci_hose_read_config_word ( hose , dev , PCI_DSR , & temp16 ) ;
if ( temp16 ) {