2006-06-17 17:52:48 -05:00
/*
2007-07-10 18:46:35 +08:00
* MPC85xx / 86 xx PCI / PCIE support routing .
2006-06-17 17:52:48 -05:00
*
2007-07-10 18:46:35 +08:00
* Copyright 2007 Freescale Semiconductor , Inc
2006-06-17 17:52:48 -05:00
*
2007-07-10 18:46:35 +08: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-17 17:52:48 -05: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 18:46:35 +08:00
# include <linux/kernel.h>
2006-06-17 17:52:48 -05:00
# include <linux/pci.h>
2007-07-10 18:46:35 +08:00
# include <linux/delay.h>
# include <linux/string.h>
# include <linux/init.h>
# include <linux/bootmem.h>
2006-06-17 17:52:48 -05:00
# include <asm/io.h>
# include <asm/prom.h>
# include <asm/pci-bridge.h>
2007-07-10 18:46:35 +08:00
# include <asm/machdep.h>
2006-06-17 17:52:48 -05:00
# include <sysdev/fsl_soc.h>
2007-07-10 18:44:34 +08:00
# include <sysdev/fsl_pci.h>
2006-06-17 17:52:48 -05:00
2007-07-10 18:46:35 +08:00
/* atmu setup for fsl pci/pcie controller */
void __init setup_pci_atmu ( struct pci_controller * hose , struct resource * rsrc )
2006-06-17 17:52:48 -05:00
{
2007-07-10 18:46:35 +08:00
struct ccsr_pci __iomem * pci ;
int i ;
2006-06-17 17:52:48 -05:00
2008-01-14 17:02:19 -06:00
pr_debug ( " PCI memory map start 0x%016llx, size 0x%016llx \n " ,
( u64 ) rsrc - > start , ( u64 ) rsrc - > end - ( u64 ) rsrc - > start + 1 ) ;
2007-07-10 18:46:35 +08: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 ) {
2008-01-14 17:02:19 -06:00
resource_size_t pci_addr_start =
hose - > mem_resources [ i ] . start -
hose - > pci_mem_offset ;
pr_debug ( " PCI MEM resource start 0x%016llx, size 0x%016llx. \n " ,
( u64 ) hose - > mem_resources [ i ] . start ,
( u64 ) hose - > mem_resources [ i ] . end
- ( u64 ) hose - > mem_resources [ i ] . start + 1 ) ;
out_be32 ( & pci - > pow [ i + 1 ] . potar , ( pci_addr_start > > 12 ) ) ;
2007-07-10 18:46:35 +08:00
out_be32 ( & pci - > pow [ i + 1 ] . potear , 0 ) ;
out_be32 ( & pci - > pow [ i + 1 ] . powbar ,
2008-01-14 17:02:19 -06:00
( hose - > mem_resources [ i ] . start > > 12 ) ) ;
2007-07-10 18:46:35 +08:00
/* 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 ) {
2008-01-14 17:02:19 -06:00
pr_debug ( " PCI IO resource start 0x%016llx, size 0x%016llx, "
" phy base 0x%016llx. \n " ,
( u64 ) hose - > io_resource . start ,
( u64 ) hose - > io_resource . end - ( u64 ) hose - > io_resource . start + 1 ,
( u64 ) hose - > io_base_phys ) ;
out_be32 ( & pci - > pow [ i + 1 ] . potar , ( hose - > io_resource . start > > 12 ) ) ;
2007-07-10 18:46:35 +08:00
out_be32 ( & pci - > pow [ i + 1 ] . potear , 0 ) ;
2008-01-14 17:02:19 -06:00
out_be32 ( & pci - > pow [ i + 1 ] . powbar , ( hose - > io_base_phys > > 12 ) ) ;
2007-07-10 18:46:35 +08:00
/* 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-17 17:52:48 -05:00
}
2007-07-10 18:46:35 +08:00
void __init setup_pci_cmd ( struct pci_controller * hose )
2006-06-17 17:52:48 -05:00
{
u16 cmd ;
2007-07-20 16:29:09 -05:00
int cap_x ;
2006-06-17 17:52:48 -05:00
early_read_config_word ( hose , 0 , 0 , PCI_COMMAND , & cmd ) ;
cmd | = PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
2007-07-10 18:46:35 +08:00
| PCI_COMMAND_IO ;
2006-06-17 17:52:48 -05:00
early_write_config_word ( hose , 0 , 0 , PCI_COMMAND , cmd ) ;
2007-07-20 16:29:09 -05:00
cap_x = early_find_capability ( hose , 0 , 0 , PCI_CAP_ID_PCIX ) ;
if ( cap_x ) {
int pci_x_cmd = cap_x + PCI_X_CMD ;
cmd = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
| PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E ;
early_write_config_word ( hose , 0 , 0 , pci_x_cmd , cmd ) ;
} else {
early_write_config_byte ( hose , 0 , 0 , PCI_LATENCY_TIMER , 0x80 ) ;
}
2006-06-28 00:37:45 -05:00
}
2008-05-23 17:41:02 +04:00
static void __init setup_pci_pcsrbar ( struct pci_controller * hose )
2008-05-23 16:32:46 +08:00
{
2008-05-23 17:41:02 +04:00
# ifdef CONFIG_PCI_MSI
2008-05-23 16:32:46 +08:00
phys_addr_t immr_base ;
immr_base = get_immrbase ( ) ;
early_write_config_dword ( hose , 0 , 0 , PCI_BASE_ADDRESS_0 , immr_base ) ;
# endif
2008-05-23 17:41:02 +04:00
}
2008-05-23 16:32:46 +08:00
2008-01-14 17:02:19 -06:00
static int fsl_pcie_bus_fixup ;
2007-06-26 18:22:40 -05:00
2008-01-14 17:02:19 -06:00
static void __init quirk_fsl_pcie_header ( struct pci_dev * dev )
{
2007-07-11 13:31:58 -05:00
/* if we aren't a PCIe don't bother */
if ( ! pci_find_capability ( dev , PCI_CAP_ID_EXP ) )
return ;
2008-01-14 17:02:19 -06:00
dev - > class = PCI_CLASS_BRIDGE_PCI < < 8 ;
fsl_pcie_bus_fixup = 1 ;
return ;
2007-06-26 18:22:40 -05:00
}
2007-07-10 18:46:35 +08:00
int __init fsl_pcie_check_link ( struct pci_controller * hose )
{
2007-10-03 23:37:33 -05:00
u32 val ;
early_read_config_dword ( hose , 0 , 0 , PCIE_LTSSM , & val ) ;
2007-07-10 18:46:35 +08:00
if ( val < PCIE_LTSSM_L0 )
return 1 ;
return 0 ;
}
2007-06-26 18:22:40 -05:00
2007-07-19 15:29:53 -05:00
void fsl_pcibios_fixup_bus ( struct pci_bus * bus )
{
struct pci_controller * hose = ( struct pci_controller * ) bus - > sysdata ;
int i ;
2008-01-14 17:02:19 -06:00
if ( ( bus - > parent = = hose - > bus ) & &
( ( fsl_pcie_bus_fixup & &
early_find_capability ( hose , 0 , 0 , PCI_CAP_ID_EXP ) ) | |
( hose - > indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK ) ) )
{
for ( i = 0 ; i < 4 ; + + i ) {
struct resource * res = bus - > resource [ i ] ;
struct resource * par = bus - > parent - > resource [ i ] ;
if ( res ) {
res - > start = 0 ;
res - > end = 0 ;
res - > flags = 0 ;
}
if ( res & & par ) {
res - > start = par - > start ;
res - > end = par - > end ;
res - > flags = par - > flags ;
}
2007-07-19 15:29:53 -05:00
}
}
}
2007-07-10 18:46:35 +08:00
int __init fsl_add_bridge ( struct device_node * dev , int is_primary )
2006-06-17 17:52:48 -05:00
{
int len ;
struct pci_controller * hose ;
struct resource rsrc ;
2006-07-12 15:39:42 +10:00
const int * bus_range ;
2006-06-17 17:52:48 -05:00
2007-07-10 18:46:35 +08:00
pr_debug ( " Adding PCI host bridge %s \n " , dev - > full_name ) ;
2006-06-17 17:52:48 -05:00
/* Fetch host bridge registers address */
2007-07-10 18:46:35 +08:00
if ( of_address_to_resource ( dev , 0 , & rsrc ) ) {
printk ( KERN_WARNING " Can't get pci register base! " ) ;
return - ENOMEM ;
}
2006-06-17 17:52:48 -05:00
/* Get bus range if any */
2007-04-03 22:26:41 +10:00
bus_range = of_get_property ( dev , " bus-range " , & len ) ;
2006-06-17 17:52:48 -05:00
if ( bus_range = = NULL | | len < 2 * sizeof ( int ) )
printk ( KERN_WARNING " Can't get bus-range for %s, assume "
2007-07-10 18:46:35 +08:00
" bus 0 \n " , dev - > full_name ) ;
2006-06-17 17:52:48 -05:00
2007-12-20 14:54:46 +11:00
ppc_pci_flags | = PPC_PCI_REASSIGN_ALL_BUS ;
2007-06-27 01:56:50 -05:00
hose = pcibios_alloc_controller ( dev ) ;
2006-06-17 17:52:48 -05:00
if ( ! hose )
return - ENOMEM ;
2007-06-27 01:56:50 -05:00
2006-06-17 17:52:48 -05:00
hose - > first_busno = bus_range ? bus_range [ 0 ] : 0x0 ;
2007-05-22 11:38:26 +08:00
hose - > last_busno = bus_range ? bus_range [ 1 ] : 0xff ;
2006-06-17 17:52:48 -05:00
2007-07-19 16:07:35 -05:00
setup_indirect_pci ( hose , rsrc . start , rsrc . start + 0x4 ,
PPC_INDIRECT_TYPE_BIG_ENDIAN ) ;
2007-07-10 18:46:35 +08:00
setup_pci_cmd ( hose ) ;
2006-06-17 17:52:48 -05:00
2007-07-10 18:46:35 +08:00
/* check PCI express link status */
2007-07-11 13:31:58 -05:00
if ( early_find_capability ( hose , 0 , 0 , PCI_CAP_ID_EXP ) ) {
2007-07-25 00:29:53 -05:00
hose - > indirect_type | = PPC_INDIRECT_TYPE_EXT_REG |
2007-07-11 13:31:58 -05:00
PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS ;
2007-07-10 18:46:35 +08:00
if ( fsl_pcie_check_link ( hose ) )
2007-07-11 13:31:58 -05:00
hose - > indirect_type | = PPC_INDIRECT_TYPE_NO_PCIE_LINK ;
}
2006-06-17 17:52:48 -05:00
2007-11-20 12:47:55 +11:00
printk ( KERN_INFO " Found FSL PCI host bridge at 0x%016llx. "
2007-07-10 18:46:35 +08:00
" Firmware bus number: %d->%d \n " ,
( unsigned long long ) rsrc . start , hose - > first_busno ,
hose - > last_busno ) ;
2006-06-17 17:52:48 -05:00
2007-07-10 18:46:35 +08:00
pr_debug ( " ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p \n " ,
2006-06-17 17:52:48 -05: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 18:46:35 +08:00
pci_process_bridge_OF_ranges ( hose , dev , is_primary ) ;
2006-06-17 17:52:48 -05:00
/* Setup PEX window registers */
2007-07-10 18:46:35 +08:00
setup_pci_atmu ( hose , & rsrc ) ;
2006-06-17 17:52:48 -05:00
2008-05-23 16:32:46 +08:00
/* Setup PEXCSRBAR */
setup_pci_pcsrbar ( hose ) ;
2006-06-17 17:52:48 -05:00
return 0 ;
}
2007-07-10 18:46:35 +08:00
2008-01-14 17:02:19 -06:00
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8548E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8548 , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8543E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8543 , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8547E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8545E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8545 , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8568E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8568 , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8567E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8567 , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8533E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8533 , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8544E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8544 , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8572E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8572 , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8641 , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8641D , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8610 , quirk_fsl_pcie_header ) ;