2006-06-18 02:52:48 +04:00
/*
2007-07-10 14:46:35 +04:00
* MPC85xx / 86 xx PCI / PCIE support routing .
2006-06-18 02:52:48 +04:00
*
2007-07-10 14:46:35 +04:00
* Copyright 2007 Freescale Semiconductor , Inc
2006-06-18 02:52:48 +04:00
*
2007-07-10 14:46:35 +04:00
* Initial author : Xianghua Xiao < x . xiao @ freescale . com >
* Recode : ZHANG WEI < wei . zhang @ freescale . com >
* Rewrite the routing for Frescale PCI and PCI Express
* Roy Zang < tie - fei . zang @ freescale . com >
2006-06-18 02:52:48 +04:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
2007-07-10 14:46:35 +04:00
# include <linux/kernel.h>
2006-06-18 02:52:48 +04:00
# include <linux/pci.h>
2007-07-10 14:46:35 +04:00
# include <linux/delay.h>
# include <linux/string.h>
# include <linux/init.h>
# include <linux/bootmem.h>
2006-06-18 02:52:48 +04:00
# include <asm/io.h>
# include <asm/prom.h>
# include <asm/pci-bridge.h>
2007-07-10 14:46:35 +04:00
# include <asm/machdep.h>
2006-06-18 02:52:48 +04:00
# include <sysdev/fsl_soc.h>
2007-07-10 14:44:34 +04:00
# include <sysdev/fsl_pci.h>
2006-06-18 02:52:48 +04:00
2007-07-10 14:46:35 +04:00
/* atmu setup for fsl pci/pcie controller */
void __init setup_pci_atmu ( struct pci_controller * hose , struct resource * rsrc )
2006-06-18 02:52:48 +04:00
{
2007-07-10 14:46:35 +04:00
struct ccsr_pci __iomem * pci ;
int i ;
2006-06-18 02:52:48 +04:00
2007-07-10 14:46:35 +04:00
pr_debug ( " PCI memory map start 0x%x, size 0x%x \n " , rsrc - > start ,
2006-06-18 02:52:48 +04:00
rsrc - > end - rsrc - > start + 1 ) ;
2007-07-10 14:46:35 +04:00
pci = ioremap ( rsrc - > start , rsrc - > end - rsrc - > start + 1 ) ;
/* Disable all windows (except powar0 since its ignored) */
for ( i = 1 ; i < 5 ; i + + )
out_be32 ( & pci - > pow [ i ] . powar , 0 ) ;
for ( i = 0 ; i < 3 ; i + + )
out_be32 ( & pci - > piw [ i ] . piwar , 0 ) ;
/* Setup outbound MEM window */
for ( i = 0 ; i < 3 ; i + + )
if ( hose - > mem_resources [ i ] . flags & IORESOURCE_MEM ) {
pr_debug ( " PCI MEM resource start 0x%08x, size 0x%08x. \n " ,
hose - > mem_resources [ i ] . start ,
hose - > mem_resources [ i ] . end
- hose - > mem_resources [ i ] . start + 1 ) ;
out_be32 ( & pci - > pow [ i + 1 ] . potar ,
( hose - > mem_resources [ i ] . start > > 12 )
& 0x000fffff ) ;
out_be32 ( & pci - > pow [ i + 1 ] . potear , 0 ) ;
out_be32 ( & pci - > pow [ i + 1 ] . powbar ,
( hose - > mem_resources [ i ] . start > > 12 )
& 0x000fffff ) ;
/* Enable, Mem R/W */
out_be32 ( & pci - > pow [ i + 1 ] . powar , 0x80044000
| ( __ilog2 ( hose - > mem_resources [ i ] . end
- hose - > mem_resources [ i ] . start + 1 ) - 1 ) ) ;
}
/* Setup outbound IO window */
if ( hose - > io_resource . flags & IORESOURCE_IO ) {
pr_debug ( " PCI IO resource start 0x%08x, size 0x%08x, phy base 0x%08x. \n " ,
hose - > io_resource . start ,
hose - > io_resource . end - hose - > io_resource . start + 1 ,
hose - > io_base_phys ) ;
out_be32 ( & pci - > pow [ i + 1 ] . potar , ( hose - > io_resource . start > > 12 )
& 0x000fffff ) ;
out_be32 ( & pci - > pow [ i + 1 ] . potear , 0 ) ;
out_be32 ( & pci - > pow [ i + 1 ] . powbar , ( hose - > io_base_phys > > 12 )
& 0x000fffff ) ;
/* Enable, IO R/W */
out_be32 ( & pci - > pow [ i + 1 ] . powar , 0x80088000
| ( __ilog2 ( hose - > io_resource . end
- hose - > io_resource . start + 1 ) - 1 ) ) ;
}
/* Setup 2G inbound Memory Window @ 1 */
out_be32 ( & pci - > piw [ 2 ] . pitar , 0x00000000 ) ;
out_be32 ( & pci - > piw [ 2 ] . piwbar , 0x00000000 ) ;
out_be32 ( & pci - > piw [ 2 ] . piwar , PIWAR_2G ) ;
2006-06-18 02:52:48 +04:00
}
2007-07-10 14:46:35 +04:00
void __init setup_pci_cmd ( struct pci_controller * hose )
2006-06-18 02:52:48 +04:00
{
u16 cmd ;
early_read_config_word ( hose , 0 , 0 , PCI_COMMAND , & cmd ) ;
cmd | = PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
2007-07-10 14:46:35 +04:00
| PCI_COMMAND_IO ;
2006-06-18 02:52:48 +04:00
early_write_config_word ( hose , 0 , 0 , PCI_COMMAND , cmd ) ;
early_write_config_byte ( hose , 0 , 0 , PCI_LATENCY_TIMER , 0x80 ) ;
2006-06-28 09:37:45 +04:00
}
2007-06-27 03:22:40 +04:00
static void __devinit quirk_fsl_pcie_transparent ( struct pci_dev * dev )
{
struct resource * res ;
int i , res_idx = PCI_BRIDGE_RESOURCES ;
struct pci_controller * hose ;
/*
* Make the bridge be transparent .
*/
dev - > transparent = 1 ;
2007-06-27 19:27:33 +04:00
hose = pci_bus_to_host ( dev - > bus ) ;
2007-06-27 03:22:40 +04:00
if ( ! hose ) {
printk ( KERN_ERR " Can't find hose for bus %d \n " ,
dev - > bus - > number ) ;
return ;
}
if ( hose - > io_resource . flags ) {
res = & dev - > resource [ res_idx + + ] ;
res - > start = hose - > io_resource . start ;
res - > end = hose - > io_resource . end ;
res - > flags = hose - > io_resource . flags ;
}
for ( i = 0 ; i < 3 ; i + + ) {
res = & dev - > resource [ res_idx + i ] ;
res - > start = hose - > mem_resources [ i ] . start ;
res - > end = hose - > mem_resources [ i ] . end ;
res - > flags = hose - > mem_resources [ i ] . flags ;
}
}
2007-07-10 14:46:35 +04:00
int __init fsl_pcie_check_link ( struct pci_controller * hose )
{
u16 val ;
early_read_config_word ( hose , 0 , 0 , PCIE_LTSSM , & val ) ;
if ( val < PCIE_LTSSM_L0 )
return 1 ;
return 0 ;
}
2007-06-27 03:22:40 +04:00
2007-07-10 14:46:35 +04:00
int __init fsl_add_bridge ( struct device_node * dev , int is_primary )
2006-06-18 02:52:48 +04:00
{
int len ;
struct pci_controller * hose ;
struct resource rsrc ;
2006-07-12 09:39:42 +04:00
const int * bus_range ;
2006-06-18 02:52:48 +04:00
2007-07-10 14:46:35 +04:00
pr_debug ( " Adding PCI host bridge %s \n " , dev - > full_name ) ;
2006-06-18 02:52:48 +04:00
/* Fetch host bridge registers address */
2007-07-10 14:46:35 +04:00
if ( of_address_to_resource ( dev , 0 , & rsrc ) ) {
printk ( KERN_WARNING " Can't get pci register base! " ) ;
return - ENOMEM ;
}
2006-06-18 02:52:48 +04:00
/* Get bus range if any */
2007-04-03 16:26:41 +04:00
bus_range = of_get_property ( dev , " bus-range " , & len ) ;
2006-06-18 02:52:48 +04:00
if ( bus_range = = NULL | | len < 2 * sizeof ( int ) )
printk ( KERN_WARNING " Can't get bus-range for %s, assume "
2007-07-10 14:46:35 +04:00
" bus 0 \n " , dev - > full_name ) ;
2006-06-18 02:52:48 +04:00
2007-06-26 21:12:55 +04:00
pci_assign_all_buses = 1 ;
2007-06-27 10:56:50 +04:00
hose = pcibios_alloc_controller ( dev ) ;
2006-06-18 02:52:48 +04:00
if ( ! hose )
return - ENOMEM ;
2007-06-27 10:56:50 +04:00
2006-06-18 02:52:48 +04:00
hose - > first_busno = bus_range ? bus_range [ 0 ] : 0x0 ;
2007-05-22 07:38:26 +04:00
hose - > last_busno = bus_range ? bus_range [ 1 ] : 0xff ;
2006-06-18 02:52:48 +04:00
2007-07-10 14:46:35 +04:00
/* check PCI express bridge */
if ( of_device_is_compatible ( dev , " fsl,mpc8548-pcie " ) | |
of_device_is_compatible ( dev , " fsl,mpc8641-pcie " ) )
hose - > indirect_type = PPC_INDIRECT_TYPE_EXT_REG |
PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS ;
2007-06-26 00:21:10 +04:00
2007-07-10 14:46:35 +04:00
setup_indirect_pci ( hose , rsrc . start , rsrc . start + 0x4 ) ;
setup_pci_cmd ( hose ) ;
2006-06-18 02:52:48 +04:00
2007-07-10 14:46:35 +04:00
/* check PCI express link status */
if ( of_device_is_compatible ( dev , " fsl,mpc8548-pcie " ) | |
of_device_is_compatible ( dev , " fsl,mpc8641-pcie " ) )
if ( fsl_pcie_check_link ( hose ) )
return - ENXIO ;
2006-06-18 02:52:48 +04:00
2007-07-10 14:46:35 +04:00
printk ( KERN_INFO " Found FSL PCI host bridge at 0x%016llx. "
" Firmware bus number: %d->%d \n " ,
( unsigned long long ) rsrc . start , hose - > first_busno ,
hose - > last_busno ) ;
2006-06-18 02:52:48 +04:00
2007-07-10 14:46:35 +04:00
pr_debug ( " ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p \n " ,
2006-06-18 02:52:48 +04:00
hose , hose - > cfg_addr , hose - > cfg_data ) ;
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
2007-07-10 14:46:35 +04:00
pci_process_bridge_OF_ranges ( hose , dev , is_primary ) ;
2006-06-18 02:52:48 +04:00
/* Setup PEX window registers */
2007-07-10 14:46:35 +04:00
setup_pci_atmu ( hose , & rsrc ) ;
2006-06-18 02:52:48 +04:00
return 0 ;
}
2007-07-10 14:46:35 +04:00
DECLARE_PCI_FIXUP_EARLY ( 0x1957 , 0x7010 , quirk_fsl_pcie_transparent ) ;
DECLARE_PCI_FIXUP_EARLY ( 0x1957 , 0x7011 , quirk_fsl_pcie_transparent ) ;