2009-08-06 15:12:43 +03:00
/*
* arch / arm / mach - dove / pcie . c
*
* PCIe functions for Marvell Dove 88 AP510 SoC
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/kernel.h>
# include <linux/pci.h>
2012-09-25 02:02:13 +02:00
# include <linux/clk.h>
2011-06-28 21:22:40 -05:00
# include <video/vga.h>
2009-08-06 15:12:43 +03:00
# include <asm/mach/pci.h>
# include <asm/mach/arch.h>
# include <asm/setup.h>
# include <asm/delay.h>
# include <plat/pcie.h>
# include <mach/irqs.h>
# include <mach/bridge-regs.h>
2011-12-07 21:48:06 +01:00
# include <plat/addr-map.h>
2009-08-06 15:12:43 +03:00
# include "common.h"
struct pcie_port {
u8 index ;
u8 root_bus_nr ;
void __iomem * base ;
spinlock_t conf_lock ;
char mem_space_name [ 16 ] ;
2012-02-28 16:05:10 -06:00
struct resource res ;
2009-08-06 15:12:43 +03:00
} ;
static struct pcie_port pcie_port [ 2 ] ;
static int num_pcie_ports ;
static int __init dove_pcie_setup ( int nr , struct pci_sys_data * sys )
{
struct pcie_port * pp ;
if ( nr > = num_pcie_ports )
return 0 ;
pp = & pcie_port [ nr ] ;
2012-03-10 13:31:34 +00:00
sys - > private_data = pp ;
2009-08-06 15:12:43 +03:00
pp - > root_bus_nr = sys - > busnr ;
/*
* Generic PCIe unit setup .
*/
orion_pcie_set_local_bus_nr ( pp - > base , sys - > busnr ) ;
2011-12-07 21:48:07 +01:00
orion_pcie_setup ( pp - > base ) ;
2009-08-06 15:12:43 +03:00
2012-02-28 16:05:10 -06:00
if ( pp - > index = = 0 )
pci_ioremap_io ( sys - > busnr * SZ_64K , DOVE_PCIE0_IO_PHYS_BASE ) ;
else
pci_ioremap_io ( sys - > busnr * SZ_64K , DOVE_PCIE1_IO_PHYS_BASE ) ;
2009-08-06 15:12:43 +03:00
/*
* IORESOURCE_MEM
*/
snprintf ( pp - > mem_space_name , sizeof ( pp - > mem_space_name ) ,
" PCIe %d MEM " , pp - > index ) ;
pp - > mem_space_name [ sizeof ( pp - > mem_space_name ) - 1 ] = 0 ;
2012-02-28 16:05:10 -06:00
pp - > res . name = pp - > mem_space_name ;
2009-08-06 15:12:43 +03:00
if ( pp - > index = = 0 ) {
2012-02-28 16:05:10 -06:00
pp - > res . start = DOVE_PCIE0_MEM_PHYS_BASE ;
pp - > res . end = pp - > res . start + DOVE_PCIE0_MEM_SIZE - 1 ;
2009-08-06 15:12:43 +03:00
} else {
2012-02-28 16:05:10 -06:00
pp - > res . start = DOVE_PCIE1_MEM_PHYS_BASE ;
pp - > res . end = pp - > res . start + DOVE_PCIE1_MEM_SIZE - 1 ;
2009-08-06 15:12:43 +03:00
}
2012-02-28 16:05:10 -06:00
pp - > res . flags = IORESOURCE_MEM ;
if ( request_resource ( & iomem_resource , & pp - > res ) )
2009-08-06 15:12:43 +03:00
panic ( " Request PCIe Memory resource failed \n " ) ;
2012-02-28 16:05:10 -06:00
pci_add_resource_offset ( & sys - > resources , & pp - > res , sys - > mem_offset ) ;
2009-08-06 15:12:43 +03:00
return 1 ;
}
static int pcie_valid_config ( struct pcie_port * pp , int bus , int dev )
{
/*
* Don ' t go out when trying to access nonexisting devices
* on the local bus .
*/
if ( bus = = pp - > root_bus_nr & & dev > 1 )
return 0 ;
return 1 ;
}
static int pcie_rd_conf ( struct pci_bus * bus , u32 devfn , int where ,
int size , u32 * val )
{
2012-03-10 13:31:34 +00:00
struct pci_sys_data * sys = bus - > sysdata ;
struct pcie_port * pp = sys - > private_data ;
2009-08-06 15:12:43 +03:00
unsigned long flags ;
int ret ;
if ( pcie_valid_config ( pp , bus - > number , PCI_SLOT ( devfn ) ) = = 0 ) {
* val = 0xffffffff ;
return PCIBIOS_DEVICE_NOT_FOUND ;
}
spin_lock_irqsave ( & pp - > conf_lock , flags ) ;
ret = orion_pcie_rd_conf ( pp - > base , bus , devfn , where , size , val ) ;
spin_unlock_irqrestore ( & pp - > conf_lock , flags ) ;
return ret ;
}
static int pcie_wr_conf ( struct pci_bus * bus , u32 devfn ,
int where , int size , u32 val )
{
2012-03-10 13:31:34 +00:00
struct pci_sys_data * sys = bus - > sysdata ;
struct pcie_port * pp = sys - > private_data ;
2009-08-06 15:12:43 +03:00
unsigned long flags ;
int ret ;
if ( pcie_valid_config ( pp , bus - > number , PCI_SLOT ( devfn ) ) = = 0 )
return PCIBIOS_DEVICE_NOT_FOUND ;
spin_lock_irqsave ( & pp - > conf_lock , flags ) ;
ret = orion_pcie_wr_conf ( pp - > base , bus , devfn , where , size , val ) ;
spin_unlock_irqrestore ( & pp - > conf_lock , flags ) ;
return ret ;
}
static struct pci_ops pcie_ops = {
. read = pcie_rd_conf ,
. write = pcie_wr_conf ,
} ;
2012-12-21 14:02:24 -08:00
static void rc_pci_fixup ( struct pci_dev * dev )
2009-08-06 15:12:43 +03:00
{
/*
* 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 ) ;
2017-06-28 15:13:55 -05:00
static int __init
dove_pcie_scan_bus ( int nr , struct pci_host_bridge * bridge )
2009-08-06 15:12:43 +03:00
{
2017-06-28 15:13:55 -05:00
struct pci_sys_data * sys = pci_host_bridge_priv ( bridge ) ;
2015-03-12 15:07:04 -05:00
if ( nr > = num_pcie_ports ) {
2009-08-06 15:12:43 +03:00
BUG ( ) ;
2017-06-28 15:13:55 -05:00
return - EINVAL ;
2009-08-06 15:12:43 +03:00
}
2017-06-28 15:13:55 -05:00
list_splice_init ( & sys - > resources , & bridge - > windows ) ;
bridge - > dev . parent = NULL ;
bridge - > sysdata = sys ;
bridge - > busnr = sys - > busnr ;
bridge - > ops = & pcie_ops ;
return pci_scan_root_bus_bridge ( bridge ) ;
2009-08-06 15:12:43 +03:00
}
2011-06-10 15:30:21 +01:00
static int __init dove_pcie_map_irq ( const struct pci_dev * dev , u8 slot , u8 pin )
2009-08-06 15:12:43 +03:00
{
2012-03-10 13:31:34 +00:00
struct pci_sys_data * sys = dev - > sysdata ;
struct pcie_port * pp = sys - > private_data ;
2009-08-06 15:12:43 +03:00
return pp - > index ? IRQ_DOVE_PCIE1 : IRQ_DOVE_PCIE0 ;
}
static struct hw_pci dove_pci __initdata = {
. nr_controllers = 2 ,
. setup = dove_pcie_setup ,
. scan = dove_pcie_scan_bus ,
. map_irq = dove_pcie_map_irq ,
} ;
2012-09-11 14:27:18 +02:00
static void __init add_pcie_port ( int index , void __iomem * base )
2009-08-06 15:12:43 +03:00
{
printk ( KERN_INFO " Dove PCIe port %d: " , index ) ;
2012-09-11 14:27:18 +02:00
if ( orion_pcie_link_up ( base ) ) {
2009-08-06 15:12:43 +03:00
struct pcie_port * pp = & pcie_port [ num_pcie_ports + + ] ;
2012-09-25 02:02:13 +02:00
struct clk * clk = clk_get_sys ( " pcie " , ( index ? " 1 " : " 0 " ) ) ;
if ( ! IS_ERR ( clk ) )
clk_prepare_enable ( clk ) ;
2009-08-06 15:12:43 +03:00
printk ( KERN_INFO " link up \n " ) ;
pp - > index = index ;
pp - > root_bus_nr = - 1 ;
2012-09-11 14:27:18 +02:00
pp - > base = base ;
2009-08-06 15:12:43 +03:00
spin_lock_init ( & pp - > conf_lock ) ;
2012-02-28 16:05:10 -06:00
memset ( & pp - > res , 0 , sizeof ( pp - > res ) ) ;
2009-08-06 15:12:43 +03:00
} else {
printk ( KERN_INFO " link down, ignoring \n " ) ;
}
}
void __init dove_pcie_init ( int init_port0 , int init_port1 )
{
2011-06-28 21:22:40 -05:00
vga_base = DOVE_PCIE0_MEM_PHYS_BASE ;
2009-08-06 15:12:43 +03:00
if ( init_port0 )
add_pcie_port ( 0 , DOVE_PCIE0_VIRT_BASE ) ;
if ( init_port1 )
add_pcie_port ( 1 , DOVE_PCIE1_VIRT_BASE ) ;
pci_common_init ( & dove_pci ) ;
}