2015-04-08 11:21:35 -07:00
/*
* Copyright ( C ) 2015 Broadcom Corporation
*
* 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 version 2.
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/clk.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/of_address.h>
# include <linux/of_pci.h>
# include <linux/of_irq.h>
# include <linux/of_platform.h>
# include <linux/phy/phy.h>
# include "pcie-iproc.h"
2015-12-04 09:34:59 -08:00
static const struct of_device_id iproc_pcie_of_match_table [ ] = {
{
. compatible = " brcm,iproc-pcie " ,
. data = ( int * ) IPROC_PCIE_PAXB ,
2016-10-31 17:38:41 -07:00
} , {
. compatible = " brcm,iproc-pcie-paxb-v2 " ,
. data = ( int * ) IPROC_PCIE_PAXB_V2 ,
2015-12-04 09:34:59 -08:00
} , {
. compatible = " brcm,iproc-pcie-paxc " ,
. data = ( int * ) IPROC_PCIE_PAXC ,
2016-10-31 17:38:35 -07:00
} , {
. compatible = " brcm,iproc-pcie-paxc-v2 " ,
. data = ( int * ) IPROC_PCIE_PAXC_V2 ,
2015-12-04 09:34:59 -08:00
} ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , iproc_pcie_of_match_table ) ;
2015-04-08 11:21:35 -07:00
static int iproc_pcie_pltfm_probe ( struct platform_device * pdev )
{
2016-10-06 13:36:08 -05:00
struct device * dev = & pdev - > dev ;
2015-12-04 09:34:59 -08:00
const struct of_device_id * of_id ;
2015-04-08 11:21:35 -07:00
struct iproc_pcie * pcie ;
2016-10-06 13:36:08 -05:00
struct device_node * np = dev - > of_node ;
2015-04-08 11:21:35 -07:00
struct resource reg ;
resource_size_t iobase = 0 ;
LIST_HEAD ( res ) ;
int ret ;
2016-10-06 13:36:08 -05:00
of_id = of_match_device ( iproc_pcie_of_match_table , dev ) ;
2015-12-04 09:34:59 -08:00
if ( ! of_id )
return - EINVAL ;
2016-10-06 13:36:08 -05:00
pcie = devm_kzalloc ( dev , sizeof ( * pcie ) , GFP_KERNEL ) ;
2015-04-08 11:21:35 -07:00
if ( ! pcie )
return - ENOMEM ;
2016-10-06 13:36:08 -05:00
pcie - > dev = dev ;
2015-12-04 09:34:59 -08:00
pcie - > type = ( enum iproc_pcie_type ) of_id - > data ;
2015-04-08 11:21:35 -07:00
ret = of_address_to_resource ( np , 0 , & reg ) ;
if ( ret < 0 ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev , " unable to obtain controller resources \n " ) ;
2015-04-08 11:21:35 -07:00
return ret ;
}
2016-10-06 13:36:08 -05:00
pcie - > base = devm_ioremap ( dev , reg . start , resource_size ( & reg ) ) ;
2015-04-08 11:21:35 -07:00
if ( ! pcie - > base ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev , " unable to map controller registers \n " ) ;
2015-04-08 11:21:35 -07:00
return - ENOMEM ;
}
2016-01-06 18:04:35 -06:00
pcie - > base_addr = reg . start ;
2015-04-08 11:21:35 -07:00
2015-10-16 08:18:24 -05:00
if ( of_property_read_bool ( np , " brcm,pcie-ob " ) ) {
u32 val ;
ret = of_property_read_u32 ( np , " brcm,pcie-ob-axi-offset " ,
& val ) ;
if ( ret ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev ,
2015-10-16 08:18:24 -05:00
" missing brcm,pcie-ob-axi-offset property \n " ) ;
return ret ;
}
pcie - > ob . axi_offset = val ;
pcie - > need_ob_cfg = true ;
}
2015-04-08 11:21:35 -07:00
/* PHY use is optional */
2016-10-06 13:36:08 -05:00
pcie - > phy = devm_phy_get ( dev , " pcie-phy " ) ;
2015-04-08 11:21:35 -07:00
if ( IS_ERR ( pcie - > phy ) ) {
if ( PTR_ERR ( pcie - > phy ) = = - EPROBE_DEFER )
return - EPROBE_DEFER ;
pcie - > phy = NULL ;
}
ret = of_pci_get_host_bridge_resources ( np , 0 , 0xff , & res , & iobase ) ;
if ( ret ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev ,
2015-04-08 11:21:35 -07:00
" unable to get PCI host bridge resources \n " ) ;
return ret ;
}
2016-12-01 15:34:52 -05:00
/* PAXC doesn't support legacy IRQs, skip mapping */
switch ( pcie - > type ) {
case IPROC_PCIE_PAXC :
case IPROC_PCIE_PAXC_V2 :
break ;
default :
pcie - > map_irq = of_irq_parse_and_map_pci ;
}
2015-05-12 23:23:00 +02:00
2015-05-24 22:37:02 +02:00
ret = iproc_pcie_setup ( pcie , & res ) ;
2015-05-24 22:37:03 +02:00
if ( ret )
2016-10-06 13:36:08 -05:00
dev_err ( dev , " PCIe controller setup failed \n " ) ;
2015-04-08 11:21:35 -07:00
2015-05-24 22:37:03 +02:00
pci_free_resource_list ( & res ) ;
2016-10-06 13:36:08 -05:00
platform_set_drvdata ( pdev , pcie ) ;
2015-05-24 22:37:03 +02:00
return ret ;
2015-04-08 11:21:35 -07:00
}
static int iproc_pcie_pltfm_remove ( struct platform_device * pdev )
{
struct iproc_pcie * pcie = platform_get_drvdata ( pdev ) ;
return iproc_pcie_remove ( pcie ) ;
}
static struct platform_driver iproc_pcie_pltfm_driver = {
. driver = {
. name = " iproc-pcie " ,
. of_match_table = of_match_ptr ( iproc_pcie_of_match_table ) ,
} ,
. probe = iproc_pcie_pltfm_probe ,
. remove = iproc_pcie_pltfm_remove ,
} ;
module_platform_driver ( iproc_pcie_pltfm_driver ) ;
MODULE_AUTHOR ( " Ray Jui <rjui@broadcom.com> " ) ;
MODULE_DESCRIPTION ( " Broadcom iPROC PCIe platform driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;