2007-10-23 23:14:42 +04:00
/*
2008-03-27 21:51:41 +03:00
* arch / arm / mach - orion5x / pci . c
2007-10-23 23:14:42 +04:00
*
2008-03-27 21:51:41 +03:00
* PCI and PCIe functions for Marvell Orion System On Chip
2007-10-23 23:14:42 +04:00
*
* Maintainer : Tzachi Perelstein < tzachi @ marvell . com >
*
2008-03-27 21:51:41 +03:00
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
2007-10-23 23:14:42 +04:00
* warranty of any kind , whether express or implied .
*/
# include <linux/kernel.h>
# include <linux/pci.h>
2008-03-27 21:51:39 +03:00
# include <linux/mbus.h>
2009-01-07 06:52:58 +03:00
# include <asm/irq.h>
2007-10-23 23:14:42 +04:00
# include <asm/mach/pci.h>
2008-08-09 15:44:58 +04:00
# include <plat/pcie.h>
2007-10-23 23:14:42 +04:00
# include "common.h"
/*****************************************************************************
2008-03-27 21:51:41 +03:00
* Orion has one PCIe controller and one PCI controller .
2007-10-23 23:14:42 +04:00
*
2008-03-27 21:51:41 +03:00
* Note1 : The local PCIe bus number is ' 0 ' . The local PCI bus number
* follows the scanned PCIe bridged busses , if any .
2007-10-23 23:14:42 +04:00
*
2008-03-27 21:51:41 +03:00
* Note2 : It is possible for PCI / PCIe agents to access many subsystem ' s
2007-10-23 23:14:42 +04:00
* space , by configuring BARs and Address Decode Windows , e . g . flashes on
* device bus , Orion registers , etc . However this code only enable the
* access to DDR banks .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*****************************************************************************
2008-03-27 21:51:41 +03:00
* PCIe controller
2007-10-23 23:14:42 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-03-27 21:51:41 +03:00
# define PCIE_BASE ((void __iomem *)ORION5X_PCIE_VIRT_BASE)
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:41 +03:00
void __init orion5x_pcie_id ( u32 * dev , u32 * rev )
2007-10-23 23:14:42 +04:00
{
2008-03-27 21:51:40 +03:00
* dev = orion_pcie_dev_id ( PCIE_BASE ) ;
* rev = orion_pcie_rev ( PCIE_BASE ) ;
2007-10-23 23:14:42 +04:00
}
2008-03-27 21:51:40 +03:00
static int pcie_valid_config ( int bus , int dev )
2007-10-23 23:14:42 +04:00
{
/*
* Don ' t go out when trying to access - -
2008-03-27 21:51:41 +03:00
* 1. nonexisting device on local bus
2007-10-23 23:14:42 +04:00
* 2. where there ' s no device connected ( no link )
*/
2008-03-27 21:51:41 +03:00
if ( bus = = 0 & & dev = = 0 )
return 1 ;
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:40 +03:00
if ( ! orion_pcie_link_up ( PCIE_BASE ) )
2007-10-23 23:14:42 +04:00
return 0 ;
2008-03-27 21:51:41 +03:00
if ( bus = = 0 & & dev ! = 1 )
return 0 ;
2007-10-23 23:14:42 +04:00
return 1 ;
}
2008-03-27 21:51:40 +03:00
/*
2008-03-27 21:51:41 +03:00
* PCIe config cycles are done by programming the PCIE_CONF_ADDR register
2008-03-27 21:51:40 +03:00
* and then reading the PCIE_CONF_DATA register . Need to make sure these
* transactions are atomic .
*/
2008-03-27 21:51:41 +03:00
static DEFINE_SPINLOCK ( orion5x_pcie_lock ) ;
2008-03-27 21:51:40 +03:00
static int pcie_rd_conf ( struct pci_bus * bus , u32 devfn , int where ,
int size , u32 * val )
2007-10-23 23:14:42 +04:00
{
unsigned long flags ;
2008-03-27 21:51:40 +03:00
int ret ;
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:40 +03:00
if ( pcie_valid_config ( bus - > number , PCI_SLOT ( devfn ) ) = = 0 ) {
2007-10-23 23:14:42 +04:00
* val = 0xffffffff ;
return PCIBIOS_DEVICE_NOT_FOUND ;
}
2008-03-27 21:51:41 +03:00
spin_lock_irqsave ( & orion5x_pcie_lock , flags ) ;
2008-03-27 21:51:40 +03:00
ret = orion_pcie_rd_conf ( PCIE_BASE , bus , devfn , where , size , val ) ;
2008-03-27 21:51:41 +03:00
spin_unlock_irqrestore ( & orion5x_pcie_lock , flags ) ;
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:40 +03:00
return ret ;
}
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:40 +03:00
static int pcie_rd_conf_wa ( struct pci_bus * bus , u32 devfn ,
int where , int size , u32 * val )
{
int ret ;
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:40 +03:00
if ( pcie_valid_config ( bus - > number , PCI_SLOT ( devfn ) ) = = 0 ) {
* val = 0xffffffff ;
return PCIBIOS_DEVICE_NOT_FOUND ;
}
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:40 +03:00
/*
* We only support access to the non - extended configuration
* space when using the WA access method ( or we would have to
* sacrifice 256 M of CPU virtual address space . )
*/
if ( where > = 0x100 ) {
* val = 0xffffffff ;
return PCIBIOS_DEVICE_NOT_FOUND ;
}
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:41 +03:00
ret = orion_pcie_rd_conf_wa ( ( void __iomem * ) ORION5X_PCIE_WA_VIRT_BASE ,
2008-03-27 21:51:40 +03:00
bus , devfn , where , size , val ) ;
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:40 +03:00
return ret ;
}
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:40 +03:00
static int pcie_wr_conf ( struct pci_bus * bus , u32 devfn ,
int where , int size , u32 val )
2007-10-23 23:14:42 +04:00
{
unsigned long flags ;
int ret ;
2008-03-27 21:51:40 +03:00
if ( pcie_valid_config ( bus - > number , PCI_SLOT ( devfn ) ) = = 0 )
2007-10-23 23:14:42 +04:00
return PCIBIOS_DEVICE_NOT_FOUND ;
2008-03-27 21:51:41 +03:00
spin_lock_irqsave ( & orion5x_pcie_lock , flags ) ;
2008-03-27 21:51:40 +03:00
ret = orion_pcie_wr_conf ( PCIE_BASE , bus , devfn , where , size , val ) ;
2008-03-27 21:51:41 +03:00
spin_unlock_irqrestore ( & orion5x_pcie_lock , flags ) ;
2007-10-23 23:14:42 +04:00
return ret ;
}
2008-03-27 21:51:41 +03:00
static struct pci_ops pcie_ops = {
2008-03-27 21:51:40 +03:00
. read = pcie_rd_conf ,
. write = pcie_wr_conf ,
2007-10-23 23:14:42 +04:00
} ;
2008-03-27 21:51:41 +03:00
static int __init pcie_setup ( struct pci_sys_data * sys )
2007-10-23 23:14:42 +04:00
{
struct resource * res ;
2008-03-27 21:51:40 +03:00
int dev ;
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:39 +03:00
/*
2008-03-27 21:51:40 +03:00
* Generic PCIe unit setup .
2007-10-23 23:14:42 +04:00
*/
2008-03-27 21:51:41 +03:00
orion_pcie_setup ( PCIE_BASE , & orion5x_mbus_dram_info ) ;
2007-10-23 23:14:42 +04:00
/*
2008-03-27 21:51:40 +03:00
* Check whether to apply Orion - 1 / Orion - NAS PCIe config
* read transaction workaround .
2007-10-23 23:14:42 +04:00
*/
2008-03-27 21:51:40 +03:00
dev = orion_pcie_dev_id ( PCIE_BASE ) ;
if ( dev = = MV88F5181_DEV_ID | | dev = = MV88F5182_DEV_ID ) {
printk ( KERN_NOTICE " Applying Orion-1/Orion-NAS PCIe config "
" read transaction workaround \n " ) ;
2008-05-10 19:01:18 +04:00
orion5x_setup_pcie_wa_win ( ORION5X_PCIE_WA_PHYS_BASE ,
ORION5X_PCIE_WA_SIZE ) ;
2008-03-27 21:51:40 +03:00
pcie_ops . read = pcie_rd_conf_wa ;
}
2007-10-23 23:14:42 +04:00
/*
2008-03-27 21:51:40 +03:00
* Request resources .
2007-10-23 23:14:42 +04:00
*/
res = kzalloc ( sizeof ( struct resource ) * 2 , GFP_KERNEL ) ;
if ( ! res )
2008-03-27 21:51:40 +03:00
panic ( " pcie_setup unable to alloc resources " ) ;
2007-10-23 23:14:42 +04:00
/*
* IORESOURCE_IO
*/
2008-03-27 21:51:41 +03:00
res [ 0 ] . name = " PCIe I/O Space " ;
2007-10-23 23:14:42 +04:00
res [ 0 ] . flags = IORESOURCE_IO ;
2008-03-27 21:51:41 +03:00
res [ 0 ] . start = ORION5X_PCIE_IO_BUS_BASE ;
res [ 0 ] . end = res [ 0 ] . start + ORION5X_PCIE_IO_SIZE - 1 ;
2007-10-23 23:14:42 +04:00
if ( request_resource ( & ioport_resource , & res [ 0 ] ) )
2008-03-27 21:51:41 +03:00
panic ( " Request PCIe IO resource failed \n " ) ;
2007-10-23 23:14:42 +04:00
sys - > resource [ 0 ] = & res [ 0 ] ;
/*
* IORESOURCE_MEM
*/
2008-03-27 21:51:41 +03:00
res [ 1 ] . name = " PCIe Memory Space " ;
2007-10-23 23:14:42 +04:00
res [ 1 ] . flags = IORESOURCE_MEM ;
2008-03-27 21:51:41 +03:00
res [ 1 ] . start = ORION5X_PCIE_MEM_PHYS_BASE ;
res [ 1 ] . end = res [ 1 ] . start + ORION5X_PCIE_MEM_SIZE - 1 ;
2007-10-23 23:14:42 +04:00
if ( request_resource ( & iomem_resource , & res [ 1 ] ) )
2008-03-27 21:51:41 +03:00
panic ( " Request PCIe Memory resource failed \n " ) ;
2007-10-23 23:14:42 +04:00
sys - > resource [ 1 ] = & res [ 1 ] ;
sys - > resource [ 2 ] = NULL ;
sys - > io_offset = 0 ;
return 1 ;
}
/*****************************************************************************
* PCI controller
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-04-22 23:08:17 +04:00
# define ORION5X_PCI_REG(x) (ORION5X_PCI_VIRT_BASE | (x))
2008-03-27 21:51:41 +03:00
# define PCI_MODE ORION5X_PCI_REG(0xd00)
# define PCI_CMD ORION5X_PCI_REG(0xc00)
# define PCI_P2P_CONF ORION5X_PCI_REG(0x1d14)
# define PCI_CONF_ADDR ORION5X_PCI_REG(0xc78)
# define PCI_CONF_DATA ORION5X_PCI_REG(0xc7c)
2007-10-23 23:14:42 +04:00
/*
* PCI_MODE bits
*/
# define PCI_MODE_64BIT (1 << 2)
# define PCI_MODE_PCIX ((1 << 4) | (1 << 5))
/*
* PCI_CMD bits
*/
# define PCI_CMD_HOST_REORDER (1 << 29)
/*
* PCI_P2P_CONF bits
*/
# define PCI_P2P_BUS_OFFS 16
# define PCI_P2P_BUS_MASK (0xff << PCI_P2P_BUS_OFFS)
# define PCI_P2P_DEV_OFFS 24
# define PCI_P2P_DEV_MASK (0x1f << PCI_P2P_DEV_OFFS)
/*
* PCI_CONF_ADDR bits
*/
# define PCI_CONF_REG(reg) ((reg) & 0xfc)
# define PCI_CONF_FUNC(func) (((func) & 0x3) << 8)
# define PCI_CONF_DEV(dev) (((dev) & 0x1f) << 11)
# define PCI_CONF_BUS(bus) (((bus) & 0xff) << 16)
# define PCI_CONF_ADDR_EN (1 << 31)
/*
* Internal configuration space
*/
# define PCI_CONF_FUNC_STAT_CMD 0
# define PCI_CONF_REG_STAT_CMD 4
# define PCIX_STAT 0x64
# define PCIX_STAT_BUS_OFFS 8
# define PCIX_STAT_BUS_MASK (0xff << PCIX_STAT_BUS_OFFS)
2008-03-27 21:51:39 +03:00
/*
* PCI Address Decode Windows registers
*/
2008-03-27 21:51:41 +03:00
# define PCI_BAR_SIZE_DDR_CS(n) (((n) == 0) ? ORION5X_PCI_REG(0xc08) : \
2008-05-10 18:30:01 +04:00
( ( n ) = = 1 ) ? ORION5X_PCI_REG ( 0xd08 ) : \
( ( n ) = = 2 ) ? ORION5X_PCI_REG ( 0xc0c ) : \
( ( n ) = = 3 ) ? ORION5X_PCI_REG ( 0xd0c ) : 0 )
# define PCI_BAR_REMAP_DDR_CS(n) (((n) == 0) ? ORION5X_PCI_REG(0xc48) : \
( ( n ) = = 1 ) ? ORION5X_PCI_REG ( 0xd48 ) : \
( ( n ) = = 2 ) ? ORION5X_PCI_REG ( 0xc4c ) : \
( ( n ) = = 3 ) ? ORION5X_PCI_REG ( 0xd4c ) : 0 )
2008-03-27 21:51:41 +03:00
# define PCI_BAR_ENABLE ORION5X_PCI_REG(0xc3c)
# define PCI_ADDR_DECODE_CTRL ORION5X_PCI_REG(0xd3c)
2008-03-27 21:51:39 +03:00
/*
* PCI configuration helpers for BAR settings
*/
# define PCI_CONF_FUNC_BAR_CS(n) ((n) >> 1)
# define PCI_CONF_REG_BAR_LO_CS(n) (((n) & 1) ? 0x18 : 0x10)
# define PCI_CONF_REG_BAR_HI_CS(n) (((n) & 1) ? 0x1c : 0x14)
2007-10-23 23:14:42 +04:00
/*
* PCI config cycles are done by programming the PCI_CONF_ADDR register
* and then reading the PCI_CONF_DATA register . Need to make sure these
* transactions are atomic .
*/
2008-03-27 21:51:41 +03:00
static DEFINE_SPINLOCK ( orion5x_pci_lock ) ;
2007-10-23 23:14:42 +04:00
2008-06-26 19:12:50 +04:00
static int orion5x_pci_cardbus_mode ;
2008-04-26 00:28:33 +04:00
static int orion5x_pci_local_bus_nr ( void )
2007-10-23 23:14:42 +04:00
{
2008-05-28 18:43:48 +04:00
u32 conf = readl ( PCI_P2P_CONF ) ;
2007-10-23 23:14:42 +04:00
return ( ( conf & PCI_P2P_BUS_MASK ) > > PCI_P2P_BUS_OFFS ) ;
}
2008-03-27 21:51:41 +03:00
static int orion5x_pci_hw_rd_conf ( int bus , int dev , u32 func ,
2007-10-23 23:14:42 +04:00
u32 where , u32 size , u32 * val )
{
unsigned long flags ;
2008-03-27 21:51:41 +03:00
spin_lock_irqsave ( & orion5x_pci_lock , flags ) ;
2007-10-23 23:14:42 +04:00
2008-05-28 18:43:48 +04:00
writel ( PCI_CONF_BUS ( bus ) |
PCI_CONF_DEV ( dev ) | PCI_CONF_REG ( where ) |
PCI_CONF_FUNC ( func ) | PCI_CONF_ADDR_EN , PCI_CONF_ADDR ) ;
2007-10-23 23:14:42 +04:00
2008-05-28 18:43:48 +04:00
* val = readl ( PCI_CONF_DATA ) ;
2007-10-23 23:14:42 +04:00
if ( size = = 1 )
* val = ( * val > > ( 8 * ( where & 0x3 ) ) ) & 0xff ;
else if ( size = = 2 )
* val = ( * val > > ( 8 * ( where & 0x3 ) ) ) & 0xffff ;
2008-03-27 21:51:41 +03:00
spin_unlock_irqrestore ( & orion5x_pci_lock , flags ) ;
2007-10-23 23:14:42 +04:00
return PCIBIOS_SUCCESSFUL ;
}
2008-03-27 21:51:41 +03:00
static int orion5x_pci_hw_wr_conf ( int bus , int dev , u32 func ,
2007-10-23 23:14:42 +04:00
u32 where , u32 size , u32 val )
{
unsigned long flags ;
int ret = PCIBIOS_SUCCESSFUL ;
2008-03-27 21:51:41 +03:00
spin_lock_irqsave ( & orion5x_pci_lock , flags ) ;
2007-10-23 23:14:42 +04:00
2008-05-28 18:43:48 +04:00
writel ( PCI_CONF_BUS ( bus ) |
PCI_CONF_DEV ( dev ) | PCI_CONF_REG ( where ) |
PCI_CONF_FUNC ( func ) | PCI_CONF_ADDR_EN , PCI_CONF_ADDR ) ;
2007-10-23 23:14:42 +04:00
if ( size = = 4 ) {
__raw_writel ( val , PCI_CONF_DATA ) ;
} else if ( size = = 2 ) {
__raw_writew ( val , PCI_CONF_DATA + ( where & 0x3 ) ) ;
} else if ( size = = 1 ) {
__raw_writeb ( val , PCI_CONF_DATA + ( where & 0x3 ) ) ;
} else {
ret = PCIBIOS_BAD_REGISTER_NUMBER ;
}
2008-03-27 21:51:41 +03:00
spin_unlock_irqrestore ( & orion5x_pci_lock , flags ) ;
2007-10-23 23:14:42 +04:00
return ret ;
}
2008-06-26 19:12:50 +04:00
static int orion5x_pci_valid_config ( int bus , u32 devfn )
{
if ( bus = = orion5x_pci_local_bus_nr ( ) ) {
/*
* Don ' t go out for local device
*/
if ( PCI_SLOT ( devfn ) = = 0 & & PCI_FUNC ( devfn ) ! = 0 )
return 0 ;
/*
* When the PCI signals are directly connected to a
* Cardbus slot , ignore all but device IDs 0 and 1.
*/
if ( orion5x_pci_cardbus_mode & & PCI_SLOT ( devfn ) > 1 )
return 0 ;
}
return 1 ;
}
2008-03-27 21:51:41 +03:00
static int orion5x_pci_rd_conf ( struct pci_bus * bus , u32 devfn ,
2007-10-23 23:14:42 +04:00
int where , int size , u32 * val )
{
2008-06-26 19:12:50 +04:00
if ( ! orion5x_pci_valid_config ( bus - > number , devfn ) ) {
2007-10-23 23:14:42 +04:00
* val = 0xffffffff ;
return PCIBIOS_DEVICE_NOT_FOUND ;
}
2008-03-27 21:51:41 +03:00
return orion5x_pci_hw_rd_conf ( bus - > number , PCI_SLOT ( devfn ) ,
2007-10-23 23:14:42 +04:00
PCI_FUNC ( devfn ) , where , size , val ) ;
}
2008-03-27 21:51:41 +03:00
static int orion5x_pci_wr_conf ( struct pci_bus * bus , u32 devfn ,
2007-10-23 23:14:42 +04:00
int where , int size , u32 val )
{
2008-06-26 19:12:50 +04:00
if ( ! orion5x_pci_valid_config ( bus - > number , devfn ) )
2007-10-23 23:14:42 +04:00
return PCIBIOS_DEVICE_NOT_FOUND ;
2008-03-27 21:51:41 +03:00
return orion5x_pci_hw_wr_conf ( bus - > number , PCI_SLOT ( devfn ) ,
2007-10-23 23:14:42 +04:00
PCI_FUNC ( devfn ) , where , size , val ) ;
}
2008-03-27 21:51:41 +03:00
static struct pci_ops pci_ops = {
2008-03-27 21:51:41 +03:00
. read = orion5x_pci_rd_conf ,
. write = orion5x_pci_wr_conf ,
2007-10-23 23:14:42 +04:00
} ;
2008-03-27 21:51:41 +03:00
static void __init orion5x_pci_set_bus_nr ( int nr )
2007-10-23 23:14:42 +04:00
{
2008-05-28 18:43:48 +04:00
u32 p2p = readl ( PCI_P2P_CONF ) ;
2007-10-23 23:14:42 +04:00
2008-05-28 18:43:48 +04:00
if ( readl ( PCI_MODE ) & PCI_MODE_PCIX ) {
2007-10-23 23:14:42 +04:00
/*
* PCI - X mode
*/
u32 pcix_status , bus , dev ;
bus = ( p2p & PCI_P2P_BUS_MASK ) > > PCI_P2P_BUS_OFFS ;
dev = ( p2p & PCI_P2P_DEV_MASK ) > > PCI_P2P_DEV_OFFS ;
2008-03-27 21:51:41 +03:00
orion5x_pci_hw_rd_conf ( bus , dev , 0 , PCIX_STAT , 4 , & pcix_status ) ;
2007-10-23 23:14:42 +04:00
pcix_status & = ~ PCIX_STAT_BUS_MASK ;
pcix_status | = ( nr < < PCIX_STAT_BUS_OFFS ) ;
2008-03-27 21:51:41 +03:00
orion5x_pci_hw_wr_conf ( bus , dev , 0 , PCIX_STAT , 4 , pcix_status ) ;
2007-10-23 23:14:42 +04:00
} else {
/*
* PCI Conventional mode
*/
p2p & = ~ PCI_P2P_BUS_MASK ;
p2p | = ( nr < < PCI_P2P_BUS_OFFS ) ;
2008-05-28 18:43:48 +04:00
writel ( p2p , PCI_P2P_CONF ) ;
2007-10-23 23:14:42 +04:00
}
}
2008-03-27 21:51:41 +03:00
static void __init orion5x_pci_master_slave_enable ( void )
2007-10-23 23:14:42 +04:00
{
2008-03-27 21:51:41 +03:00
int bus_nr , func , reg ;
2008-03-27 21:51:40 +03:00
u32 val ;
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:41 +03:00
bus_nr = orion5x_pci_local_bus_nr ( ) ;
2007-10-23 23:14:42 +04:00
func = PCI_CONF_FUNC_STAT_CMD ;
reg = PCI_CONF_REG_STAT_CMD ;
2008-03-27 21:51:41 +03:00
orion5x_pci_hw_rd_conf ( bus_nr , 0 , func , reg , 4 , & val ) ;
2007-10-23 23:14:42 +04:00
val | = ( PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER ) ;
2008-03-27 21:51:41 +03:00
orion5x_pci_hw_wr_conf ( bus_nr , 0 , func , reg , 4 , val | 0x7 ) ;
2007-10-23 23:14:42 +04:00
}
2008-03-27 21:51:41 +03:00
static void __init orion5x_setup_pci_wins ( struct mbus_dram_target_info * dram )
2008-03-27 21:51:39 +03:00
{
u32 win_enable ;
2008-03-27 21:51:40 +03:00
int bus ;
2008-03-27 21:51:39 +03:00
int i ;
/*
* First , disable windows .
*/
win_enable = 0xffffffff ;
2008-05-28 18:43:48 +04:00
writel ( win_enable , PCI_BAR_ENABLE ) ;
2008-03-27 21:51:39 +03:00
/*
* Setup windows for DDR banks .
*/
2008-03-27 21:51:41 +03:00
bus = orion5x_pci_local_bus_nr ( ) ;
2008-03-27 21:51:39 +03:00
for ( i = 0 ; i < dram - > num_cs ; i + + ) {
struct mbus_dram_window * cs = dram - > cs + i ;
u32 func = PCI_CONF_FUNC_BAR_CS ( cs - > cs_index ) ;
u32 reg ;
u32 val ;
/*
* Write DRAM bank base address register .
*/
reg = PCI_CONF_REG_BAR_LO_CS ( cs - > cs_index ) ;
2008-03-27 21:51:41 +03:00
orion5x_pci_hw_rd_conf ( bus , 0 , func , reg , 4 , & val ) ;
2008-03-27 21:51:39 +03:00
val = ( cs - > base & 0xfffff000 ) | ( val & 0xfff ) ;
2008-03-27 21:51:41 +03:00
orion5x_pci_hw_wr_conf ( bus , 0 , func , reg , 4 , val ) ;
2008-03-27 21:51:39 +03:00
/*
* Write DRAM bank size register .
*/
reg = PCI_CONF_REG_BAR_HI_CS ( cs - > cs_index ) ;
2008-03-27 21:51:41 +03:00
orion5x_pci_hw_wr_conf ( bus , 0 , func , reg , 4 , 0 ) ;
2008-05-28 18:43:48 +04:00
writel ( ( cs - > size - 1 ) & 0xfffff000 ,
PCI_BAR_SIZE_DDR_CS ( cs - > cs_index ) ) ;
writel ( cs - > base & 0xfffff000 ,
PCI_BAR_REMAP_DDR_CS ( cs - > cs_index ) ) ;
2008-03-27 21:51:39 +03:00
/*
* Enable decode window for this chip select .
*/
win_enable & = ~ ( 1 < < cs - > cs_index ) ;
}
/*
* Re - enable decode windows .
*/
2008-05-28 18:43:48 +04:00
writel ( win_enable , PCI_BAR_ENABLE ) ;
2008-03-27 21:51:39 +03:00
/*
* Disable automatic update of address remaping when writing to BARs .
*/
2008-03-27 21:51:41 +03:00
orion5x_setbits ( PCI_ADDR_DECODE_CTRL , 1 ) ;
2008-03-27 21:51:39 +03:00
}
2008-03-27 21:51:41 +03:00
static int __init pci_setup ( struct pci_sys_data * sys )
2007-10-23 23:14:42 +04:00
{
struct resource * res ;
2008-03-27 21:51:39 +03:00
/*
* Point PCI unit MBUS decode windows to DRAM space .
*/
2008-03-27 21:51:41 +03:00
orion5x_setup_pci_wins ( & orion5x_mbus_dram_info ) ;
2008-03-27 21:51:39 +03:00
2007-10-23 23:14:42 +04:00
/*
* Master + Slave enable
*/
2008-03-27 21:51:41 +03:00
orion5x_pci_master_slave_enable ( ) ;
2007-10-23 23:14:42 +04:00
/*
* Force ordering
*/
2008-03-27 21:51:41 +03:00
orion5x_setbits ( PCI_CMD , PCI_CMD_HOST_REORDER ) ;
2007-10-23 23:14:42 +04:00
/*
* Request resources
*/
res = kzalloc ( sizeof ( struct resource ) * 2 , GFP_KERNEL ) ;
if ( ! res )
2008-03-27 21:51:40 +03:00
panic ( " pci_setup unable to alloc resources " ) ;
2007-10-23 23:14:42 +04:00
/*
* IORESOURCE_IO
*/
res [ 0 ] . name = " PCI I/O Space " ;
res [ 0 ] . flags = IORESOURCE_IO ;
2008-03-27 21:51:41 +03:00
res [ 0 ] . start = ORION5X_PCI_IO_BUS_BASE ;
res [ 0 ] . end = res [ 0 ] . start + ORION5X_PCI_IO_SIZE - 1 ;
2007-10-23 23:14:42 +04:00
if ( request_resource ( & ioport_resource , & res [ 0 ] ) )
panic ( " Request PCI IO resource failed \n " ) ;
sys - > resource [ 0 ] = & res [ 0 ] ;
/*
* IORESOURCE_MEM
*/
res [ 1 ] . name = " PCI Memory Space " ;
res [ 1 ] . flags = IORESOURCE_MEM ;
2008-03-27 21:51:41 +03:00
res [ 1 ] . start = ORION5X_PCI_MEM_PHYS_BASE ;
res [ 1 ] . end = res [ 1 ] . start + ORION5X_PCI_MEM_SIZE - 1 ;
2007-10-23 23:14:42 +04:00
if ( request_resource ( & iomem_resource , & res [ 1 ] ) )
panic ( " Request PCI Memory resource failed \n " ) ;
sys - > resource [ 1 ] = & res [ 1 ] ;
sys - > resource [ 2 ] = NULL ;
sys - > io_offset = 0 ;
return 1 ;
}
/*****************************************************************************
2008-03-27 21:51:41 +03:00
* General PCIe + PCI
2007-10-23 23:14:42 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-03-27 21:51:41 +03:00
static void __devinit rc_pci_fixup ( struct pci_dev * dev )
{
/*
* Prevent enumeration of root complex .
*/
if ( dev - > bus - > parent = = NULL & & dev - > devfn = = 0 ) {
int i ;
for ( i = 0 ; i < DEVICE_COUNT_RESOURCE ; i + + ) {
dev - > resource [ i ] . start = 0 ;
dev - > resource [ i ] . end = 0 ;
dev - > resource [ i ] . flags = 0 ;
}
}
}
DECLARE_PCI_FIXUP_HEADER ( PCI_VENDOR_ID_MARVELL , PCI_ANY_ID , rc_pci_fixup ) ;
2008-08-11 14:00:52 +04:00
static int orion5x_pci_disabled __initdata ;
void __init orion5x_pci_disable ( void )
{
orion5x_pci_disabled = 1 ;
}
2008-06-26 19:12:50 +04:00
void __init orion5x_pci_set_cardbus_mode ( void )
{
orion5x_pci_cardbus_mode = 1 ;
}
2008-03-27 21:51:41 +03:00
int __init orion5x_pci_sys_setup ( int nr , struct pci_sys_data * sys )
2007-10-23 23:14:42 +04:00
{
int ret = 0 ;
if ( nr = = 0 ) {
2008-03-27 21:51:40 +03:00
orion_pcie_set_local_bus_nr ( PCIE_BASE , sys - > busnr ) ;
ret = pcie_setup ( sys ) ;
2008-08-11 14:00:52 +04:00
} else if ( nr = = 1 & & ! orion5x_pci_disabled ) {
2008-03-27 21:51:41 +03:00
orion5x_pci_set_bus_nr ( sys - > busnr ) ;
2008-03-27 21:51:40 +03:00
ret = pci_setup ( sys ) ;
2007-10-23 23:14:42 +04:00
}
return ret ;
}
2008-03-27 21:51:41 +03:00
struct pci_bus __init * orion5x_pci_sys_scan_bus ( int nr , struct pci_sys_data * sys )
2007-10-23 23:14:42 +04:00
{
struct pci_bus * bus ;
if ( nr = = 0 ) {
2008-03-27 21:51:40 +03:00
bus = pci_scan_bus ( sys - > busnr , & pcie_ops , sys ) ;
2008-08-11 14:00:52 +04:00
} else if ( nr = = 1 & & ! orion5x_pci_disabled ) {
2008-03-27 21:51:40 +03:00
bus = pci_scan_bus ( sys - > busnr , & pci_ops , sys ) ;
2007-10-23 23:14:42 +04:00
} else {
bus = NULL ;
2008-03-27 21:51:40 +03:00
BUG ( ) ;
2007-10-23 23:14:42 +04:00
}
return bus ;
}
2008-04-26 00:28:33 +04:00
int __init orion5x_pci_map_irq ( struct pci_dev * dev , u8 slot , u8 pin )
{
int bus = dev - > bus - > number ;
/*
* PCIe endpoint ?
*/
2008-08-11 14:00:52 +04:00
if ( orion5x_pci_disabled | | bus < orion5x_pci_local_bus_nr ( ) )
2008-04-26 00:28:33 +04:00
return IRQ_ORION5X_PCIE0_INT ;
return - 1 ;
}