2006-06-17 17:52:48 -05:00
/*
* MPC86XX pci setup code
*
* Recode : ZHANG WEI < wei . zhang @ freescale . com >
* Initial author : Xianghua Xiao < x . xiao @ freescale . com >
*
* Copyright 2006 Freescale Semiconductor Inc .
*
* 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 .
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/serial.h>
# include <asm/system.h>
# include <asm/atomic.h>
# include <asm/io.h>
# include <asm/prom.h>
# include <asm/pci-bridge.h>
# include <sysdev/fsl_soc.h>
2007-03-09 13:27:28 +08:00
# include <sysdev/fsl_pcie.h>
2006-06-17 17:52:48 -05:00
# include "mpc86xx.h"
# undef DEBUG
# ifdef DEBUG
# define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
# else
# define DBG(fmt, args...)
# endif
struct pcie_outbound_window_regs {
uint pexotar ; /* 0x.0 - PCI Express outbound translation address register */
uint pexotear ; /* 0x.4 - PCI Express outbound translation extended address register */
uint pexowbar ; /* 0x.8 - PCI Express outbound window base address register */
char res1 [ 4 ] ;
uint pexowar ; /* 0x.10 - PCI Express outbound window attributes register */
char res2 [ 12 ] ;
} ;
struct pcie_inbound_window_regs {
uint pexitar ; /* 0x.0 - PCI Express inbound translation address register */
char res1 [ 4 ] ;
uint pexiwbar ; /* 0x.8 - PCI Express inbound window base address register */
uint pexiwbear ; /* 0x.c - PCI Express inbound window base extended address register */
uint pexiwar ; /* 0x.10 - PCI Express inbound window attributes register */
char res2 [ 12 ] ;
} ;
static void __init setup_pcie_atmu ( struct pci_controller * hose , struct resource * rsrc )
{
volatile struct ccsr_pex * pcie ;
volatile struct pcie_outbound_window_regs * pcieow ;
volatile struct pcie_inbound_window_regs * pcieiw ;
int i = 0 ;
DBG ( " PCIE memory map start 0x%x, size 0x%x \n " , rsrc - > start ,
rsrc - > end - rsrc - > start + 1 ) ;
pcie = ioremap ( rsrc - > start , rsrc - > end - rsrc - > start + 1 ) ;
/* Disable all windows (except pexowar0 since its ignored) */
pcie - > pexowar1 = 0 ;
pcie - > pexowar2 = 0 ;
pcie - > pexowar3 = 0 ;
pcie - > pexowar4 = 0 ;
pcie - > pexiwar1 = 0 ;
pcie - > pexiwar2 = 0 ;
pcie - > pexiwar3 = 0 ;
pcieow = ( struct pcie_outbound_window_regs * ) & pcie - > pexotar1 ;
pcieiw = ( struct pcie_inbound_window_regs * ) & pcie - > pexitar1 ;
/* Setup outbound MEM window */
for ( i = 0 ; i < 3 ; i + + )
if ( hose - > mem_resources [ i ] . flags & IORESOURCE_MEM ) {
DBG ( " PCIE 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 ) ;
pcieow - > pexotar = ( hose - > mem_resources [ i ] . start ) > > 12
& 0x000fffff ;
pcieow - > pexotear = 0 ;
pcieow - > pexowbar = ( hose - > mem_resources [ i ] . start ) > > 12
& 0x000fffff ;
/* Enable, Mem R/W */
pcieow - > pexowar = 0x80044000 |
( __ilog2 ( hose - > mem_resources [ i ] . end
- hose - > mem_resources [ i ] . start + 1 )
- 1 ) ;
pcieow + + ;
}
/* Setup outbound IO window */
if ( hose - > io_resource . flags & IORESOURCE_IO ) {
DBG ( " PCIE 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 ) ;
pcieow - > pexotar = ( hose - > io_resource . start ) > > 12 & 0x000fffff ;
pcieow - > pexotear = 0 ;
pcieow - > pexowbar = ( hose - > io_base_phys ) > > 12 & 0x000fffff ;
/* Enable, IO R/W */
pcieow - > pexowar = 0x80088000 | ( __ilog2 ( hose - > io_resource . end
- hose - > io_resource . start + 1 ) - 1 ) ;
}
/* Setup 2G inbound Memory Window @ 0 */
pcieiw - > pexitar = 0x00000000 ;
pcieiw - > pexiwbar = 0x00000000 ;
/* Enable, Prefetch, Local Mem, Snoop R/W, 2G */
pcieiw - > pexiwar = 0xa0f5501e ;
}
static void __init
mpc86xx_setup_pcie ( struct pci_controller * hose , u32 pcie_offset , u32 pcie_size )
{
u16 cmd ;
unsigned int temps ;
DBG ( " PCIE host controller register offset 0x%08x, size 0x%08x. \n " ,
pcie_offset , pcie_size ) ;
early_read_config_word ( hose , 0 , 0 , PCI_COMMAND , & cmd ) ;
cmd | = PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
| PCI_COMMAND_IO ;
early_write_config_word ( hose , 0 , 0 , PCI_COMMAND , cmd ) ;
early_write_config_byte ( hose , 0 , 0 , PCI_LATENCY_TIMER , 0x80 ) ;
/* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */
early_read_config_dword ( hose , 0 , 0 , PCI_PRIMARY_BUS , & temps ) ;
temps = ( temps & 0xff000000 ) | ( 0xff ) | ( 0x0 < < 8 ) | ( 0xfe < < 16 ) ;
early_write_config_dword ( hose , 0 , 0 , PCI_PRIMARY_BUS , temps ) ;
}
2006-06-28 00:37:45 -05:00
int mpc86xx_exclude_device ( u_char bus , u_char devfn )
{
if ( bus = = 0 & & PCI_SLOT ( devfn ) = = 0 )
return PCIBIOS_DEVICE_NOT_FOUND ;
return PCIBIOS_SUCCESSFUL ;
}
2006-06-17 17:52:48 -05:00
int __init add_bridge ( struct device_node * dev )
{
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
int has_address = 0 ;
int primary = 0 ;
DBG ( " Adding PCIE host bridge %s \n " , dev - > full_name ) ;
/* Fetch host bridge registers address */
has_address = ( of_address_to_resource ( dev , 0 , & rsrc ) = = 0 ) ;
/* Get bus range if any */
2006-07-12 15:39:42 +10:00
bus_range = 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 "
" bus 0 \n " , dev - > full_name ) ;
hose = pcibios_alloc_controller ( ) ;
if ( ! hose )
return - ENOMEM ;
hose - > arch_data = dev ;
hose - > set_cfg_type = 1 ;
/* last_busno = 0xfe cause by MPC8641 PCIE bug */
hose - > first_busno = bus_range ? bus_range [ 0 ] : 0x0 ;
hose - > last_busno = bus_range ? bus_range [ 1 ] : 0xfe ;
setup_indirect_pcie ( hose , rsrc . start , rsrc . start + 0x4 ) ;
/* Setup the PCIE host controller. */
mpc86xx_setup_pcie ( hose , rsrc . start , rsrc . end - rsrc . start + 1 ) ;
if ( ( rsrc . start & 0xfffff ) = = 0x8000 )
primary = 1 ;
printk ( KERN_INFO " Found MPC86xx PCIE host bridge at 0x%08lx. "
" Firmware bus number: %d->%d \n " ,
2006-08-15 16:19:02 -05:00
( unsigned long ) rsrc . start ,
hose - > first_busno , hose - > last_busno ) ;
2006-06-17 17:52:48 -05:00
DBG ( " ->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 ) ;
/* Setup PEX window registers */
setup_pcie_atmu ( hose , & rsrc ) ;
return 0 ;
}