2018-01-26 21:50:27 +03:00
// SPDX-License-Identifier: GPL-2.0
2015-01-28 19:16:18 +03:00
/*
* Copyright 2004 Koninklijke Philips Electronics NV
*
* Conversion to platform driver and DT :
* Copyright 2014 Linaro Ltd .
*
* 14 / 04 / 2005 Initial version , colin . king @ philips . com
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_address.h>
# include <linux/of_pci.h>
# include <linux/of_platform.h>
# include <linux/pci.h>
# include <linux/platform_device.h>
2018-06-07 00:10:27 +03:00
# include "../pci.h"
2015-01-28 19:16:18 +03:00
static void __iomem * versatile_pci_base ;
static void __iomem * versatile_cfg_base [ 2 ] ;
# define PCI_IMAP(m) (versatile_pci_base + ((m) * 4))
# define PCI_SMAP(m) (versatile_pci_base + 0x14 + ((m) * 4))
# define PCI_SELFID (versatile_pci_base + 0xc)
# define VP_PCI_DEVICE_ID 0x030010ee
# define VP_PCI_CLASS_ID 0x0b400000
static u32 pci_slot_ignore ;
static int __init versatile_pci_slot_ignore ( char * str )
{
int retval ;
int slot ;
while ( ( retval = get_option ( & str , & slot ) ) ) {
if ( ( slot < 0 ) | | ( slot > 31 ) )
pr_err ( " Illegal slot value: %d \n " , slot ) ;
else
pci_slot_ignore | = ( 1 < < slot ) ;
}
return 1 ;
}
__setup ( " pci_slot_ignore= " , versatile_pci_slot_ignore ) ;
static void __iomem * versatile_map_bus ( struct pci_bus * bus ,
unsigned int devfn , int offset )
{
unsigned int busnr = bus - > number ;
if ( pci_slot_ignore & ( 1 < < PCI_SLOT ( devfn ) ) )
return NULL ;
return versatile_cfg_base [ 1 ] + ( ( busnr < < 16 ) | ( devfn < < 8 ) | offset ) ;
}
static struct pci_ops pci_versatile_ops = {
. map_bus = versatile_map_bus ,
. read = pci_generic_config_read32 ,
. write = pci_generic_config_write ,
} ;
static int versatile_pci_parse_request_of_pci_ranges ( struct device * dev ,
struct list_head * res )
{
int err , mem = 1 , res_valid = 0 ;
resource_size_t iobase ;
2016-08-15 19:50:43 +03:00
struct resource_entry * win , * tmp ;
2015-01-28 19:16:18 +03:00
2018-05-15 12:07:05 +03:00
err = devm_of_pci_get_host_bridge_resources ( dev , 0 , 0xff , res , & iobase ) ;
2015-01-28 19:16:18 +03:00
if ( err )
return err ;
2016-05-31 20:09:28 +03:00
err = devm_request_pci_bus_resources ( dev , res ) ;
if ( err )
goto out_release_res ;
2016-08-15 19:50:43 +03:00
resource_list_for_each_entry_safe ( win , tmp , res ) {
2016-05-31 20:09:28 +03:00
struct resource * res = win - > res ;
2015-01-28 19:16:18 +03:00
switch ( resource_type ( res ) ) {
case IORESOURCE_IO :
2018-07-18 23:40:40 +03:00
err = devm_pci_remap_iospace ( dev , res , iobase ) ;
2016-08-15 19:50:43 +03:00
if ( err ) {
2015-01-28 19:16:18 +03:00
dev_warn ( dev , " error %d: failed to map resource %pR \n " ,
err , res ) ;
2016-08-15 19:50:43 +03:00
resource_list_destroy_entry ( win ) ;
}
2015-01-28 19:16:18 +03:00
break ;
case IORESOURCE_MEM :
res_valid | = ! ( res - > flags & IORESOURCE_PREFETCH ) ;
writel ( res - > start > > 28 , PCI_IMAP ( mem ) ) ;
writel ( PHYS_OFFSET > > 28 , PCI_SMAP ( mem ) ) ;
mem + + ;
break ;
}
}
2016-05-29 02:31:26 +03:00
if ( res_valid )
return 0 ;
2015-01-28 19:16:18 +03:00
2016-05-29 02:31:26 +03:00
dev_err ( dev , " non-prefetchable memory resource required \n " ) ;
err = - EINVAL ;
2015-01-28 19:16:18 +03:00
out_release_res :
pci_free_resource_list ( res ) ;
return err ;
}
static int versatile_pci_probe ( struct platform_device * pdev )
{
2017-06-28 01:40:00 +03:00
struct device * dev = & pdev - > dev ;
2015-01-28 19:16:18 +03:00
struct resource * res ;
int ret , i , myslot = - 1 ;
u32 val ;
void __iomem * local_pci_cfg_base ;
2017-02-09 00:42:26 +03:00
struct pci_bus * bus , * child ;
2017-06-28 23:13:58 +03:00
struct pci_host_bridge * bridge ;
2015-01-28 19:16:18 +03:00
LIST_HEAD ( pci_res ) ;
2017-06-28 01:40:00 +03:00
bridge = devm_pci_alloc_host_bridge ( dev , 0 ) ;
2017-06-28 23:13:58 +03:00
if ( ! bridge )
return - ENOMEM ;
2015-01-28 19:16:18 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2017-06-28 01:40:00 +03:00
versatile_pci_base = devm_ioremap_resource ( dev , res ) ;
2015-04-03 16:17:05 +03:00
if ( IS_ERR ( versatile_pci_base ) )
return PTR_ERR ( versatile_pci_base ) ;
2015-01-28 19:16:18 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
2017-06-28 01:40:00 +03:00
versatile_cfg_base [ 0 ] = devm_ioremap_resource ( dev , res ) ;
2015-04-03 16:17:05 +03:00
if ( IS_ERR ( versatile_cfg_base [ 0 ] ) )
return PTR_ERR ( versatile_cfg_base [ 0 ] ) ;
2015-01-28 19:16:18 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 2 ) ;
2017-06-28 01:40:00 +03:00
versatile_cfg_base [ 1 ] = devm_pci_remap_cfg_resource ( dev , res ) ;
2015-04-03 16:17:05 +03:00
if ( IS_ERR ( versatile_cfg_base [ 1 ] ) )
return PTR_ERR ( versatile_cfg_base [ 1 ] ) ;
2015-01-28 19:16:18 +03:00
2017-06-28 01:40:00 +03:00
ret = versatile_pci_parse_request_of_pci_ranges ( dev , & pci_res ) ;
2015-01-28 19:16:18 +03:00
if ( ret )
return ret ;
/*
* We need to discover the PCI core first to configure itself
* before the main PCI probing is performed
*/
for ( i = 0 ; i < 32 ; i + + ) {
if ( ( readl ( versatile_cfg_base [ 0 ] + ( i < < 11 ) + PCI_VENDOR_ID ) = = VP_PCI_DEVICE_ID ) & &
( readl ( versatile_cfg_base [ 0 ] + ( i < < 11 ) + PCI_CLASS_REVISION ) = = VP_PCI_CLASS_ID ) ) {
myslot = i ;
break ;
}
}
if ( myslot = = - 1 ) {
2017-06-28 01:40:00 +03:00
dev_err ( dev , " Cannot find PCI core! \n " ) ;
2015-01-28 19:16:18 +03:00
return - EIO ;
}
/*
* Do not to map Versatile FPGA PCI device into memory space
*/
pci_slot_ignore | = ( 1 < < myslot ) ;
2017-06-28 01:40:00 +03:00
dev_info ( dev , " PCI core found (slot %d) \n " , myslot ) ;
2015-01-28 19:16:18 +03:00
writel ( myslot , PCI_SELFID ) ;
local_pci_cfg_base = versatile_cfg_base [ 1 ] + ( myslot < < 11 ) ;
val = readl ( local_pci_cfg_base + PCI_COMMAND ) ;
val | = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE ;
writel ( val , local_pci_cfg_base + PCI_COMMAND ) ;
/*
* Configure the PCI inbound memory windows to be 1 : 1 mapped to SDRAM
*/
writel ( PHYS_OFFSET , local_pci_cfg_base + PCI_BASE_ADDRESS_0 ) ;
writel ( PHYS_OFFSET , local_pci_cfg_base + PCI_BASE_ADDRESS_1 ) ;
writel ( PHYS_OFFSET , local_pci_cfg_base + PCI_BASE_ADDRESS_2 ) ;
/*
* For many years the kernel and QEMU were symbiotically buggy
* in that they both assumed the same broken IRQ mapping .
* QEMU therefore attempts to auto - detect old broken kernels
* so that they still work on newer QEMU as they did on old
* QEMU . Since we now use the correct ( ie matching - hardware )
* IRQ mapping we write a definitely different value to a
* PCI_INTERRUPT_LINE register to tell QEMU that we expect
* real hardware behaviour and it need not be backwards
* compatible for us . This write is harmless on real hardware .
*/
writel ( 0 , versatile_cfg_base [ 0 ] + PCI_INTERRUPT_LINE ) ;
pci_add_flags ( PCI_ENABLE_PROC_DOMAINS ) ;
PCI: Remove PCI_REASSIGN_ALL_RSRC use on arm and arm64
On arm, PCI_REASSIGN_ALL_RSRC is used only in pcibios_assign_all_busses(),
which helps decide whether to reconfigure bridge bus numbers. It has
nothing to do with BAR assignments. On arm64 and powerpc,
pcibios_assign_all_busses() tests PCI_REASSIGN_ALL_BUS, which makes more
sense.
Align arm with arm64 and powerpc, so they all use PCI_REASSIGN_ALL_BUS for
pcibios_assign_all_busses().
Remove PCI_REASSIGN_ALL_RSRC from the generic, Tegra, Versatile, and
R-Car drivers. These drivers are used only on arm or arm64, where
PCI_REASSIGN_ALL_RSRC is not used after this change, so removing it
should have no effect.
No functional change intended.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
2017-11-30 20:21:57 +03:00
pci_add_flags ( PCI_REASSIGN_ALL_BUS ) ;
2015-01-28 19:16:18 +03:00
2017-06-28 23:13:58 +03:00
list_splice_init ( & pci_res , & bridge - > windows ) ;
2017-06-28 01:40:00 +03:00
bridge - > dev . parent = dev ;
2017-06-28 23:13:58 +03:00
bridge - > sysdata = NULL ;
bridge - > busnr = 0 ;
bridge - > ops = & pci_versatile_ops ;
2017-06-28 23:14:09 +03:00
bridge - > map_irq = of_irq_parse_and_map_pci ;
bridge - > swizzle_irq = pci_common_swizzle ;
2017-06-28 23:13:58 +03:00
ret = pci_scan_root_bus_bridge ( bridge ) ;
if ( ret < 0 )
return ret ;
bus = bridge - > bus ;
2015-01-28 19:16:18 +03:00
pci_assign_unassigned_bus_resources ( bus ) ;
2017-02-09 00:42:26 +03:00
list_for_each_entry ( child , & bus - > children , node )
pcie_bus_configure_settings ( child ) ;
PCI: Assign resources before drivers claim devices (pci_scan_root_bus())
Previously, pci_scan_root_bus() created a root PCI bus, enumerated the
devices on it, and called pci_bus_add_devices(), which made the devices
available for drivers to claim them.
Most callers assigned resources to devices after pci_scan_root_bus()
returns, which may be after drivers have claimed the devices. This is
incorrect; the PCI core should not change device resources while a driver
is managing the device.
Remove pci_bus_add_devices() from pci_scan_root_bus() and do it after any
resource assignment in the callers.
Note that ARM's pci_common_init_dev() already called pci_bus_add_devices()
after pci_scan_root_bus(), so we only need to remove the first call:
pci_common_init_dev
pcibios_init_hw
pci_scan_root_bus
pci_bus_add_devices # first call
pci_bus_assign_resources
pci_bus_add_devices # second call
[bhelgaas: changelog, drop "root_bus" var in alpha common_init_pci(),
return failure earlier in mn10300, add "return" in x86 pcibios_scan_root(),
return early if xtensa platform_pcibios_fixup() fails]
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: Richard Henderson <rth@twiddle.net>
CC: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
CC: Matt Turner <mattst88@gmail.com>
CC: David Howells <dhowells@redhat.com>
CC: Tony Luck <tony.luck@intel.com>
CC: Michal Simek <monstr@monstr.eu>
CC: Ralf Baechle <ralf@linux-mips.org>
CC: Koichi Yasutake <yasutake.koichi@jp.panasonic.com>
CC: Sebastian Ott <sebott@linux.vnet.ibm.com>
CC: "David S. Miller" <davem@davemloft.net>
CC: Chris Metcalf <cmetcalf@ezchip.com>
CC: Chris Zankel <chris@zankel.net>
CC: Max Filippov <jcmvbkbc@gmail.com>
CC: Thomas Gleixner <tglx@linutronix.de>
2015-03-16 06:18:56 +03:00
pci_bus_add_devices ( bus ) ;
2015-01-28 19:16:18 +03:00
return 0 ;
}
static const struct of_device_id versatile_pci_of_match [ ] = {
{ . compatible = " arm,versatile-pci " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , versatile_pci_of_match ) ;
static struct platform_driver versatile_pci_driver = {
. driver = {
. name = " versatile-pci " ,
. of_match_table = versatile_pci_of_match ,
2017-04-20 23:36:25 +03:00
. suppress_bind_attrs = true ,
2015-01-28 19:16:18 +03:00
} ,
. probe = versatile_pci_probe ,
} ;
module_platform_driver ( versatile_pci_driver ) ;
MODULE_DESCRIPTION ( " Versatile PCI driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;