2006-06-18 02:52:48 +04:00
/*
2008-10-07 23:00:18 +04:00
* MPC83xx / 85 xx / 86 xx PCI / PCIE support routing .
2006-06-18 02:52:48 +04:00
*
2008-10-07 23:00:18 +04:00
* Copyright 2007 , 2008 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
2008-06-26 21:07:57 +04:00
# if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx)
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
2008-01-15 02:02:19 +03: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 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 ) {
2008-01-15 02:02:19 +03: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 14:46:35 +04:00
out_be32 ( & pci - > pow [ i + 1 ] . potear , 0 ) ;
out_be32 ( & pci - > pow [ i + 1 ] . powbar ,
2008-01-15 02:02:19 +03:00
( hose - > mem_resources [ i ] . start > > 12 ) ) ;
2007-07-10 14:46:35 +04: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-15 02:02:19 +03: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 14:46:35 +04:00
out_be32 ( & pci - > pow [ i + 1 ] . potear , 0 ) ;
2008-01-15 02:02:19 +03:00
out_be32 ( & pci - > pow [ i + 1 ] . powbar , ( hose - > io_base_phys > > 12 ) ) ;
2007-07-10 14:46:35 +04: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-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 ;
2007-07-21 01:29:09 +04:00
int cap_x ;
2006-06-18 02:52:48 +04:00
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 ) ;
2007-07-21 01:29:09 +04: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 09:37:45 +04:00
}
2008-05-23 17:41:02 +04:00
static void __init setup_pci_pcsrbar ( struct pci_controller * hose )
2008-05-23 12:32:46 +04:00
{
2008-05-23 17:41:02 +04:00
# ifdef CONFIG_PCI_MSI
2008-05-23 12:32:46 +04: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 12:32:46 +04:00
2008-01-15 02:02:19 +03:00
static int fsl_pcie_bus_fixup ;
2007-06-27 03:22:40 +04:00
2008-01-15 02:02:19 +03:00
static void __init quirk_fsl_pcie_header ( struct pci_dev * dev )
{
2007-07-11 22:31:58 +04:00
/* if we aren't a PCIe don't bother */
if ( ! pci_find_capability ( dev , PCI_CAP_ID_EXP ) )
return ;
2008-01-15 02:02:19 +03:00
dev - > class = PCI_CLASS_BRIDGE_PCI < < 8 ;
fsl_pcie_bus_fixup = 1 ;
return ;
2007-06-27 03:22:40 +04:00
}
2007-07-10 14:46:35 +04:00
int __init fsl_pcie_check_link ( struct pci_controller * hose )
{
2007-10-04 08:37:33 +04:00
u32 val ;
early_read_config_dword ( hose , 0 , 0 , PCIE_LTSSM , & val ) ;
2007-07-10 14:46:35 +04:00
if ( val < PCIE_LTSSM_L0 )
return 1 ;
return 0 ;
}
2007-06-27 03:22:40 +04:00
2007-07-20 00:29:53 +04:00
void fsl_pcibios_fixup_bus ( struct pci_bus * bus )
{
struct pci_controller * hose = ( struct pci_controller * ) bus - > sysdata ;
int i ;
2008-01-15 02:02:19 +03: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-20 00:29:53 +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-12-20 06:54:46 +03:00
ppc_pci_flags | = PPC_PCI_REASSIGN_ALL_BUS ;
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-20 01:07:35 +04:00
setup_indirect_pci ( hose , rsrc . start , rsrc . start + 0x4 ,
PPC_INDIRECT_TYPE_BIG_ENDIAN ) ;
2007-07-10 14:46:35 +04:00
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 */
2007-07-11 22:31:58 +04:00
if ( early_find_capability ( hose , 0 , 0 , PCI_CAP_ID_EXP ) ) {
2007-07-25 09:29:53 +04:00
hose - > indirect_type | = PPC_INDIRECT_TYPE_EXT_REG |
2007-07-11 22:31:58 +04:00
PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS ;
2007-07-10 14:46:35 +04:00
if ( fsl_pcie_check_link ( hose ) )
2007-07-11 22:31:58 +04:00
hose - > indirect_type | = PPC_INDIRECT_TYPE_NO_PCIE_LINK ;
}
2006-06-18 02:52:48 +04:00
2007-11-20 04:47:55 +03:00
printk ( KERN_INFO " Found FSL PCI host bridge at 0x%016llx. "
2007-07-10 14:46:35 +04:00
" 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
2008-05-23 12:32:46 +04:00
/* Setup PEXCSRBAR */
setup_pci_pcsrbar ( hose ) ;
2006-06-18 02:52:48 +04:00
return 0 ;
}
2007-07-10 14:46:35 +04:00
2008-01-15 02:02:19 +03: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 ) ;
2008-07-02 10:36:15 +04:00
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8536E , quirk_fsl_pcie_header ) ;
DECLARE_PCI_FIXUP_HEADER ( 0x1957 , PCI_DEVICE_ID_MPC8536 , quirk_fsl_pcie_header ) ;
2008-01-15 02:02:19 +03:00
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 ) ;
2008-06-26 21:07:57 +04:00
# endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */
2008-10-08 01:13:18 +04:00
# if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x)
2008-06-26 21:07:57 +04:00
int __init mpc83xx_add_bridge ( struct device_node * dev )
{
int len ;
struct pci_controller * hose ;
2008-10-07 23:00:18 +04:00
struct resource rsrc_reg ;
struct resource rsrc_cfg ;
2008-06-26 21:07:57 +04:00
const int * bus_range ;
2008-10-07 23:00:18 +04:00
int primary ;
2008-06-26 21:07:57 +04:00
pr_debug ( " Adding PCI host bridge %s \n " , dev - > full_name ) ;
/* Fetch host bridge registers address */
2008-10-07 23:00:18 +04:00
if ( of_address_to_resource ( dev , 0 , & rsrc_reg ) ) {
printk ( KERN_WARNING " Can't get pci register base! \n " ) ;
return - ENOMEM ;
}
memset ( & rsrc_cfg , 0 , sizeof ( rsrc_cfg ) ) ;
if ( of_address_to_resource ( dev , 1 , & rsrc_cfg ) ) {
printk ( KERN_WARNING
" No pci config register base in dev tree, "
" using default \n " ) ;
/*
* MPC83xx supports up to two host controllers
* one at 0x8500 has config space registers at 0x8300
* one at 0x8600 has config space registers at 0x8380
*/
if ( ( rsrc_reg . start & 0xfffff ) = = 0x8500 )
rsrc_cfg . start = ( rsrc_reg . start & 0xfff00000 ) + 0x8300 ;
else if ( ( rsrc_reg . start & 0xfffff ) = = 0x8600 )
rsrc_cfg . start = ( rsrc_reg . start & 0xfff00000 ) + 0x8380 ;
}
/*
* Controller at offset 0x8500 is primary
*/
if ( ( rsrc_reg . start & 0xfffff ) = = 0x8500 )
primary = 1 ;
else
primary = 0 ;
2008-06-26 21:07:57 +04:00
/* Get bus range if any */
bus_range = of_get_property ( dev , " bus-range " , & len ) ;
if ( bus_range = = NULL | | len < 2 * sizeof ( int ) ) {
printk ( KERN_WARNING " Can't get bus-range for %s, assume "
" bus 0 \n " , dev - > full_name ) ;
}
ppc_pci_flags | = PPC_PCI_REASSIGN_ALL_BUS ;
hose = pcibios_alloc_controller ( dev ) ;
if ( ! hose )
return - ENOMEM ;
hose - > first_busno = bus_range ? bus_range [ 0 ] : 0 ;
hose - > last_busno = bus_range ? bus_range [ 1 ] : 0xff ;
2008-10-07 23:00:18 +04:00
setup_indirect_pci ( hose , rsrc_cfg . start , rsrc_cfg . start + 4 , 0 ) ;
2008-06-26 21:07:57 +04:00
2008-10-08 01:13:18 +04:00
printk ( KERN_INFO " Found FSL PCI host bridge at 0x%016llx. "
2008-06-26 21:07:57 +04:00
" Firmware bus number: %d->%d \n " ,
2008-10-07 23:00:18 +04:00
( unsigned long long ) rsrc_reg . start , hose - > first_busno ,
2008-06-26 21:07:57 +04:00
hose - > last_busno ) ;
pr_debug ( " ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p \n " ,
hose , hose - > cfg_addr , hose - > cfg_data ) ;
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
pci_process_bridge_OF_ranges ( hose , dev , primary ) ;
return 0 ;
}
# endif /* CONFIG_PPC_83xx */