2015-04-08 11:21:35 -07:00
/*
* Copyright ( C ) 2014 Hauke Mehrtens < hauke @ hauke - m . de >
2015-10-16 12:04:04 -07:00
* Copyright ( C ) 2015 Broadcom Corporation
2015-04-08 11:21:35 -07:00
*
* 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/msi.h>
# include <linux/clk.h>
# include <linux/module.h>
# include <linux/mbus.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
2016-10-31 17:38:35 -07:00
# include <linux/irqchip/arm-gic-v3.h>
2015-04-08 11:21:35 -07:00
# 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-09-15 17:39:18 -07:00
# define EP_PERST_SOURCE_SELECT_SHIFT 2
# define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT)
2015-04-08 11:21:35 -07:00
# define EP_MODE_SURVIVE_PERST_SHIFT 1
# define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT)
# define RC_PCIE_RST_OUTPUT_SHIFT 0
# define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT)
2015-12-04 09:34:59 -08:00
# define PAXC_RESET_MASK 0x7f
2015-04-08 11:21:35 -07:00
2016-10-31 17:38:35 -07:00
# define GIC_V3_CFG_SHIFT 0
# define GIC_V3_CFG BIT(GIC_V3_CFG_SHIFT)
# define MSI_ENABLE_CFG_SHIFT 0
# define MSI_ENABLE_CFG BIT(MSI_ENABLE_CFG_SHIFT)
2015-04-08 11:21:35 -07:00
# define CFG_IND_ADDR_MASK 0x00001ffc
# define CFG_ADDR_BUS_NUM_SHIFT 20
# define CFG_ADDR_BUS_NUM_MASK 0x0ff00000
# define CFG_ADDR_DEV_NUM_SHIFT 15
# define CFG_ADDR_DEV_NUM_MASK 0x000f8000
# define CFG_ADDR_FUNC_NUM_SHIFT 12
# define CFG_ADDR_FUNC_NUM_MASK 0x00007000
# define CFG_ADDR_REG_NUM_SHIFT 2
# define CFG_ADDR_REG_NUM_MASK 0x00000ffc
# define CFG_ADDR_CFG_TYPE_SHIFT 0
# define CFG_ADDR_CFG_TYPE_MASK 0x00000003
# define SYS_RC_INTX_MASK 0xf
2015-09-15 17:39:19 -07:00
# define PCIE_PHYLINKUP_SHIFT 3
# define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT)
# define PCIE_DL_ACTIVE_SHIFT 2
# define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT)
2016-10-31 17:38:33 -07:00
# define APB_ERR_EN_SHIFT 0
# define APB_ERR_EN BIT(APB_ERR_EN_SHIFT)
2016-10-31 17:38:37 -07:00
/* derive the enum index of the outbound/inbound mapping registers */
# define MAP_REG(base_reg, index) ((base_reg) + (index) * 2)
/*
* Maximum number of outbound mapping window sizes that can be supported by any
* OARR / OMAP mapping pair
*/
# define MAX_NUM_OB_WINDOW_SIZES 4
2015-10-16 08:18:24 -05:00
# define OARR_VALID_SHIFT 0
# define OARR_VALID BIT(OARR_VALID_SHIFT)
# define OARR_SIZE_CFG_SHIFT 1
2016-10-31 17:38:39 -07:00
/*
* Maximum number of inbound mapping region sizes that can be supported by an
* IARR
*/
# define MAX_NUM_IB_REGION_SIZES 9
# define IMAP_VALID_SHIFT 0
# define IMAP_VALID BIT(IMAP_VALID_SHIFT)
2016-10-06 13:36:07 -05:00
# define PCI_EXP_CAP 0xac
2015-12-04 09:34:59 -08:00
# define IPROC_PCIE_REG_INVALID 0xffff
2016-10-31 17:38:37 -07:00
/**
* iProc PCIe outbound mapping controller specific parameters
*
* @ window_sizes : list of supported outbound mapping window sizes in MB
* @ nr_sizes : number of supported outbound mapping window sizes
*/
struct iproc_pcie_ob_map {
resource_size_t window_sizes [ MAX_NUM_OB_WINDOW_SIZES ] ;
unsigned int nr_sizes ;
} ;
static const struct iproc_pcie_ob_map paxb_ob_map [ ] = {
{
/* OARR0/OMAP0 */
. window_sizes = { 128 , 256 } ,
. nr_sizes = 2 ,
} ,
{
/* OARR1/OMAP1 */
. window_sizes = { 128 , 256 } ,
. nr_sizes = 2 ,
} ,
} ;
2016-10-31 17:38:41 -07:00
static const struct iproc_pcie_ob_map paxb_v2_ob_map [ ] = {
{
/* OARR0/OMAP0 */
. window_sizes = { 128 , 256 } ,
. nr_sizes = 2 ,
} ,
{
/* OARR1/OMAP1 */
. window_sizes = { 128 , 256 } ,
. nr_sizes = 2 ,
} ,
{
/* OARR2/OMAP2 */
. window_sizes = { 128 , 256 , 512 , 1024 } ,
. nr_sizes = 4 ,
} ,
{
/* OARR3/OMAP3 */
. window_sizes = { 128 , 256 , 512 , 1024 } ,
. nr_sizes = 4 ,
} ,
} ;
2016-10-31 17:38:39 -07:00
/**
* iProc PCIe inbound mapping type
*/
enum iproc_pcie_ib_map_type {
/* for DDR memory */
IPROC_PCIE_IB_MAP_MEM = 0 ,
/* for device I/O memory */
IPROC_PCIE_IB_MAP_IO ,
/* invalid or unused */
IPROC_PCIE_IB_MAP_INVALID
} ;
/**
* iProc PCIe inbound mapping controller specific parameters
*
* @ type : inbound mapping region type
* @ size_unit : inbound mapping region size unit , could be SZ_1K , SZ_1M , or
* SZ_1G
* @ region_sizes : list of supported inbound mapping region sizes in KB , MB , or
* GB , depedning on the size unit
* @ nr_sizes : number of supported inbound mapping region sizes
* @ nr_windows : number of supported inbound mapping windows for the region
* @ imap_addr_offset : register offset between the upper and lower 32 - bit
* IMAP address registers
* @ imap_window_offset : register offset between each IMAP window
*/
struct iproc_pcie_ib_map {
enum iproc_pcie_ib_map_type type ;
unsigned int size_unit ;
resource_size_t region_sizes [ MAX_NUM_IB_REGION_SIZES ] ;
unsigned int nr_sizes ;
unsigned int nr_windows ;
u16 imap_addr_offset ;
u16 imap_window_offset ;
} ;
2016-10-31 17:38:41 -07:00
static const struct iproc_pcie_ib_map paxb_v2_ib_map [ ] = {
{
/* IARR0/IMAP0 */
. type = IPROC_PCIE_IB_MAP_IO ,
. size_unit = SZ_1K ,
. region_sizes = { 32 } ,
. nr_sizes = 1 ,
. nr_windows = 8 ,
. imap_addr_offset = 0x40 ,
. imap_window_offset = 0x4 ,
} ,
{
/* IARR1/IMAP1 (currently unused) */
. type = IPROC_PCIE_IB_MAP_INVALID ,
} ,
{
/* IARR2/IMAP2 */
. type = IPROC_PCIE_IB_MAP_MEM ,
. size_unit = SZ_1M ,
. region_sizes = { 64 , 128 , 256 , 512 , 1024 , 2048 , 4096 , 8192 ,
16384 } ,
. nr_sizes = 9 ,
. nr_windows = 1 ,
. imap_addr_offset = 0x4 ,
. imap_window_offset = 0x8 ,
} ,
{
/* IARR3/IMAP3 */
. type = IPROC_PCIE_IB_MAP_MEM ,
. size_unit = SZ_1G ,
. region_sizes = { 1 , 2 , 4 , 8 , 16 , 32 } ,
. nr_sizes = 6 ,
. nr_windows = 8 ,
. imap_addr_offset = 0x4 ,
. imap_window_offset = 0x8 ,
} ,
{
/* IARR4/IMAP4 */
. type = IPROC_PCIE_IB_MAP_MEM ,
. size_unit = SZ_1G ,
. region_sizes = { 32 , 64 , 128 , 256 , 512 } ,
. nr_sizes = 5 ,
. nr_windows = 8 ,
. imap_addr_offset = 0x4 ,
. imap_window_offset = 0x8 ,
} ,
} ;
2016-10-31 17:38:30 -07:00
/*
* iProc PCIe host registers
*/
2015-12-04 09:34:59 -08:00
enum iproc_pcie_reg {
2016-10-31 17:38:30 -07:00
/* clock/reset signal control */
2015-12-04 09:34:59 -08:00
IPROC_PCIE_CLK_CTRL = 0 ,
2016-10-31 17:38:30 -07:00
2016-10-31 17:38:35 -07:00
/*
* To allow MSI to be steered to an external MSI controller ( e . g . , ARM
* GICv3 ITS )
*/
IPROC_PCIE_MSI_GIC_MODE ,
/*
* IPROC_PCIE_MSI_BASE_ADDR and IPROC_PCIE_MSI_WINDOW_SIZE define the
* window where the MSI posted writes are written , for the writes to be
* interpreted as MSI writes .
*/
IPROC_PCIE_MSI_BASE_ADDR ,
IPROC_PCIE_MSI_WINDOW_SIZE ,
/*
* To hold the address of the register where the MSI writes are
* programed . When ARM GICv3 ITS is used , this should be programmed
* with the address of the GITS_TRANSLATER register .
*/
IPROC_PCIE_MSI_ADDR_LO ,
IPROC_PCIE_MSI_ADDR_HI ,
/* enable MSI */
IPROC_PCIE_MSI_EN_CFG ,
2016-10-31 17:38:30 -07:00
/* allow access to root complex configuration space */
2015-12-04 09:34:59 -08:00
IPROC_PCIE_CFG_IND_ADDR ,
IPROC_PCIE_CFG_IND_DATA ,
2016-10-31 17:38:30 -07:00
/* allow access to device configuration space */
2015-12-04 09:34:59 -08:00
IPROC_PCIE_CFG_ADDR ,
IPROC_PCIE_CFG_DATA ,
2016-10-31 17:38:30 -07:00
/* enable INTx */
2015-12-04 09:34:59 -08:00
IPROC_PCIE_INTX_EN ,
2016-10-31 17:38:30 -07:00
/* outbound address mapping */
2016-10-31 17:38:37 -07:00
IPROC_PCIE_OARR0 ,
IPROC_PCIE_OMAP0 ,
IPROC_PCIE_OARR1 ,
IPROC_PCIE_OMAP1 ,
IPROC_PCIE_OARR2 ,
IPROC_PCIE_OMAP2 ,
IPROC_PCIE_OARR3 ,
IPROC_PCIE_OMAP3 ,
2016-10-31 17:38:30 -07:00
2016-10-31 17:38:39 -07:00
/* inbound address mapping */
IPROC_PCIE_IARR0 ,
IPROC_PCIE_IMAP0 ,
IPROC_PCIE_IARR1 ,
IPROC_PCIE_IMAP1 ,
IPROC_PCIE_IARR2 ,
IPROC_PCIE_IMAP2 ,
IPROC_PCIE_IARR3 ,
IPROC_PCIE_IMAP3 ,
IPROC_PCIE_IARR4 ,
IPROC_PCIE_IMAP4 ,
2016-10-31 17:38:30 -07:00
/* link status */
2015-12-04 09:34:59 -08:00
IPROC_PCIE_LINK_STATUS ,
2016-10-31 17:38:30 -07:00
2016-10-31 17:38:33 -07:00
/* enable APB error for unsupported requests */
IPROC_PCIE_APB_ERR_EN ,
2016-10-31 17:38:30 -07:00
/* total number of core registers */
IPROC_PCIE_MAX_NUM_REG ,
2015-12-04 09:34:59 -08:00
} ;
2016-10-31 17:38:32 -07:00
/* iProc PCIe PAXB BCMA registers */
static const u16 iproc_pcie_reg_paxb_bcma [ ] = {
[ IPROC_PCIE_CLK_CTRL ] = 0x000 ,
[ IPROC_PCIE_CFG_IND_ADDR ] = 0x120 ,
[ IPROC_PCIE_CFG_IND_DATA ] = 0x124 ,
[ IPROC_PCIE_CFG_ADDR ] = 0x1f8 ,
[ IPROC_PCIE_CFG_DATA ] = 0x1fc ,
[ IPROC_PCIE_INTX_EN ] = 0x330 ,
[ IPROC_PCIE_LINK_STATUS ] = 0xf0c ,
} ;
2015-12-04 09:34:59 -08:00
/* iProc PCIe PAXB registers */
static const u16 iproc_pcie_reg_paxb [ ] = {
2016-10-31 17:38:37 -07:00
[ IPROC_PCIE_CLK_CTRL ] = 0x000 ,
[ IPROC_PCIE_CFG_IND_ADDR ] = 0x120 ,
[ IPROC_PCIE_CFG_IND_DATA ] = 0x124 ,
[ IPROC_PCIE_CFG_ADDR ] = 0x1f8 ,
[ IPROC_PCIE_CFG_DATA ] = 0x1fc ,
[ IPROC_PCIE_INTX_EN ] = 0x330 ,
[ IPROC_PCIE_OARR0 ] = 0xd20 ,
[ IPROC_PCIE_OMAP0 ] = 0xd40 ,
[ IPROC_PCIE_OARR1 ] = 0xd28 ,
[ IPROC_PCIE_OMAP1 ] = 0xd48 ,
[ IPROC_PCIE_LINK_STATUS ] = 0xf0c ,
[ IPROC_PCIE_APB_ERR_EN ] = 0xf40 ,
2015-12-04 09:34:59 -08:00
} ;
2016-10-31 17:38:41 -07:00
/* iProc PCIe PAXB v2 registers */
static const u16 iproc_pcie_reg_paxb_v2 [ ] = {
[ IPROC_PCIE_CLK_CTRL ] = 0x000 ,
[ IPROC_PCIE_CFG_IND_ADDR ] = 0x120 ,
[ IPROC_PCIE_CFG_IND_DATA ] = 0x124 ,
[ IPROC_PCIE_CFG_ADDR ] = 0x1f8 ,
[ IPROC_PCIE_CFG_DATA ] = 0x1fc ,
[ IPROC_PCIE_INTX_EN ] = 0x330 ,
[ IPROC_PCIE_OARR0 ] = 0xd20 ,
[ IPROC_PCIE_OMAP0 ] = 0xd40 ,
[ IPROC_PCIE_OARR1 ] = 0xd28 ,
[ IPROC_PCIE_OMAP1 ] = 0xd48 ,
[ IPROC_PCIE_OARR2 ] = 0xd60 ,
[ IPROC_PCIE_OMAP2 ] = 0xd68 ,
[ IPROC_PCIE_OARR3 ] = 0xdf0 ,
[ IPROC_PCIE_OMAP3 ] = 0xdf8 ,
[ IPROC_PCIE_IARR0 ] = 0xd00 ,
[ IPROC_PCIE_IMAP0 ] = 0xc00 ,
[ IPROC_PCIE_IARR2 ] = 0xd10 ,
[ IPROC_PCIE_IMAP2 ] = 0xcc0 ,
[ IPROC_PCIE_IARR3 ] = 0xe00 ,
[ IPROC_PCIE_IMAP3 ] = 0xe08 ,
[ IPROC_PCIE_IARR4 ] = 0xe68 ,
[ IPROC_PCIE_IMAP4 ] = 0xe70 ,
[ IPROC_PCIE_LINK_STATUS ] = 0xf0c ,
[ IPROC_PCIE_APB_ERR_EN ] = 0xf40 ,
} ;
2015-12-04 09:34:59 -08:00
/* iProc PCIe PAXC v1 registers */
static const u16 iproc_pcie_reg_paxc [ ] = {
2016-10-31 17:38:37 -07:00
[ IPROC_PCIE_CLK_CTRL ] = 0x000 ,
[ IPROC_PCIE_CFG_IND_ADDR ] = 0x1f0 ,
[ IPROC_PCIE_CFG_IND_DATA ] = 0x1f4 ,
[ IPROC_PCIE_CFG_ADDR ] = 0x1f8 ,
[ IPROC_PCIE_CFG_DATA ] = 0x1fc ,
2015-12-04 09:34:59 -08:00
} ;
2015-10-16 08:18:24 -05:00
2016-10-31 17:38:35 -07:00
/* iProc PCIe PAXC v2 registers */
static const u16 iproc_pcie_reg_paxc_v2 [ ] = {
[ IPROC_PCIE_MSI_GIC_MODE ] = 0x050 ,
[ IPROC_PCIE_MSI_BASE_ADDR ] = 0x074 ,
[ IPROC_PCIE_MSI_WINDOW_SIZE ] = 0x078 ,
[ IPROC_PCIE_MSI_ADDR_LO ] = 0x07c ,
[ IPROC_PCIE_MSI_ADDR_HI ] = 0x080 ,
[ IPROC_PCIE_MSI_EN_CFG ] = 0x09c ,
[ IPROC_PCIE_CFG_IND_ADDR ] = 0x1f0 ,
[ IPROC_PCIE_CFG_IND_DATA ] = 0x1f4 ,
[ IPROC_PCIE_CFG_ADDR ] = 0x1f8 ,
[ IPROC_PCIE_CFG_DATA ] = 0x1fc ,
} ;
2015-07-21 18:29:40 -07:00
static inline struct iproc_pcie * iproc_data ( struct pci_bus * bus )
2015-04-08 11:21:35 -07:00
{
2015-07-21 18:29:40 -07:00
struct iproc_pcie * pcie ;
# ifdef CONFIG_ARM
struct pci_sys_data * sys = bus - > sysdata ;
pcie = sys - > private_data ;
# else
pcie = bus - > sysdata ;
# endif
return pcie ;
2015-04-08 11:21:35 -07:00
}
2015-12-04 09:34:59 -08:00
static inline bool iproc_pcie_reg_is_invalid ( u16 reg_offset )
{
return ! ! ( reg_offset = = IPROC_PCIE_REG_INVALID ) ;
}
static inline u16 iproc_pcie_reg_offset ( struct iproc_pcie * pcie ,
enum iproc_pcie_reg reg )
{
return pcie - > reg_offsets [ reg ] ;
}
static inline u32 iproc_pcie_read_reg ( struct iproc_pcie * pcie ,
enum iproc_pcie_reg reg )
{
u16 offset = iproc_pcie_reg_offset ( pcie , reg ) ;
if ( iproc_pcie_reg_is_invalid ( offset ) )
return 0 ;
return readl ( pcie - > base + offset ) ;
}
static inline void iproc_pcie_write_reg ( struct iproc_pcie * pcie ,
enum iproc_pcie_reg reg , u32 val )
{
u16 offset = iproc_pcie_reg_offset ( pcie , reg ) ;
if ( iproc_pcie_reg_is_invalid ( offset ) )
return ;
writel ( val , pcie - > base + offset ) ;
}
2016-10-31 17:38:33 -07:00
/**
* APB error forwarding can be disabled during access of configuration
* registers of the endpoint device , to prevent unsupported requests
* ( typically seen during enumeration with multi - function devices ) from
* triggering a system exception .
*/
static inline void iproc_pcie_apb_err_disable ( struct pci_bus * bus ,
bool disable )
{
struct iproc_pcie * pcie = iproc_data ( bus ) ;
u32 val ;
if ( bus - > number & & pcie - > has_apb_err_disable ) {
val = iproc_pcie_read_reg ( pcie , IPROC_PCIE_APB_ERR_EN ) ;
if ( disable )
val & = ~ APB_ERR_EN ;
else
val | = APB_ERR_EN ;
iproc_pcie_write_reg ( pcie , IPROC_PCIE_APB_ERR_EN , val ) ;
}
}
2015-04-08 11:21:35 -07:00
/**
* Note access to the configuration registers are protected at the higher layer
* by ' pci_lock ' in drivers / pci / access . c
*/
2017-06-28 15:13:50 -05:00
static void __iomem * iproc_pcie_map_cfg_bus ( struct iproc_pcie * pcie ,
int busno ,
2015-04-08 11:21:35 -07:00
unsigned int devfn ,
int where )
{
unsigned slot = PCI_SLOT ( devfn ) ;
unsigned fn = PCI_FUNC ( devfn ) ;
u32 val ;
2015-12-04 09:34:59 -08:00
u16 offset ;
2015-04-08 11:21:35 -07:00
/* root complex access */
if ( busno = = 0 ) {
2016-01-27 16:52:24 -06:00
if ( slot > 0 | | fn > 0 )
return NULL ;
2015-12-04 09:34:59 -08:00
iproc_pcie_write_reg ( pcie , IPROC_PCIE_CFG_IND_ADDR ,
where & CFG_IND_ADDR_MASK ) ;
offset = iproc_pcie_reg_offset ( pcie , IPROC_PCIE_CFG_IND_DATA ) ;
if ( iproc_pcie_reg_is_invalid ( offset ) )
2015-04-08 11:21:35 -07:00
return NULL ;
2015-12-04 09:34:59 -08:00
else
return ( pcie - > base + offset ) ;
2015-04-08 11:21:35 -07:00
}
2016-01-27 16:52:24 -06:00
/*
* PAXC is connected to an internally emulated EP within the SoC . It
* allows only one device .
*/
2016-10-31 17:38:30 -07:00
if ( pcie - > ep_is_internal )
2016-01-27 16:52:24 -06:00
if ( slot > 0 )
return NULL ;
2015-04-08 11:21:35 -07:00
/* EP device access */
val = ( busno < < CFG_ADDR_BUS_NUM_SHIFT ) |
( slot < < CFG_ADDR_DEV_NUM_SHIFT ) |
( fn < < CFG_ADDR_FUNC_NUM_SHIFT ) |
( where & CFG_ADDR_REG_NUM_MASK ) |
( 1 & CFG_ADDR_CFG_TYPE_MASK ) ;
2015-12-04 09:34:59 -08:00
iproc_pcie_write_reg ( pcie , IPROC_PCIE_CFG_ADDR , val ) ;
offset = iproc_pcie_reg_offset ( pcie , IPROC_PCIE_CFG_DATA ) ;
if ( iproc_pcie_reg_is_invalid ( offset ) )
return NULL ;
else
return ( pcie - > base + offset ) ;
2015-04-08 11:21:35 -07:00
}
2017-06-28 15:13:50 -05:00
static void __iomem * iproc_pcie_bus_map_cfg_bus ( struct pci_bus * bus ,
unsigned int devfn ,
int where )
{
return iproc_pcie_map_cfg_bus ( iproc_data ( bus ) , bus - > number , devfn ,
where ) ;
}
static int iproc_pci_raw_config_read32 ( struct iproc_pcie * pcie ,
unsigned int devfn , int where ,
int size , u32 * val )
{
void __iomem * addr ;
addr = iproc_pcie_map_cfg_bus ( pcie , 0 , devfn , where & ~ 0x3 ) ;
if ( ! addr ) {
* val = ~ 0 ;
return PCIBIOS_DEVICE_NOT_FOUND ;
}
* val = readl ( addr ) ;
if ( size < = 2 )
* val = ( * val > > ( 8 * ( where & 3 ) ) ) & ( ( 1 < < ( size * 8 ) ) - 1 ) ;
return PCIBIOS_SUCCESSFUL ;
}
static int iproc_pci_raw_config_write32 ( struct iproc_pcie * pcie ,
unsigned int devfn , int where ,
int size , u32 val )
{
void __iomem * addr ;
u32 mask , tmp ;
addr = iproc_pcie_map_cfg_bus ( pcie , 0 , devfn , where & ~ 0x3 ) ;
if ( ! addr )
return PCIBIOS_DEVICE_NOT_FOUND ;
if ( size = = 4 ) {
writel ( val , addr ) ;
return PCIBIOS_SUCCESSFUL ;
}
mask = ~ ( ( ( 1 < < ( size * 8 ) ) - 1 ) < < ( ( where & 0x3 ) * 8 ) ) ;
tmp = readl ( addr ) & mask ;
tmp | = val < < ( ( where & 0x3 ) * 8 ) ;
writel ( tmp , addr ) ;
return PCIBIOS_SUCCESSFUL ;
}
2016-10-31 17:38:33 -07:00
static int iproc_pcie_config_read32 ( struct pci_bus * bus , unsigned int devfn ,
int where , int size , u32 * val )
{
int ret ;
iproc_pcie_apb_err_disable ( bus , true ) ;
ret = pci_generic_config_read32 ( bus , devfn , where , size , val ) ;
iproc_pcie_apb_err_disable ( bus , false ) ;
return ret ;
}
static int iproc_pcie_config_write32 ( struct pci_bus * bus , unsigned int devfn ,
int where , int size , u32 val )
{
int ret ;
iproc_pcie_apb_err_disable ( bus , true ) ;
ret = pci_generic_config_write32 ( bus , devfn , where , size , val ) ;
iproc_pcie_apb_err_disable ( bus , false ) ;
return ret ;
}
2015-04-08 11:21:35 -07:00
static struct pci_ops iproc_pcie_ops = {
2017-06-28 15:13:50 -05:00
. map_bus = iproc_pcie_bus_map_cfg_bus ,
2016-10-31 17:38:33 -07:00
. read = iproc_pcie_config_read32 ,
. write = iproc_pcie_config_write32 ,
2015-04-08 11:21:35 -07:00
} ;
static void iproc_pcie_reset ( struct iproc_pcie * pcie )
{
u32 val ;
2016-10-31 17:38:31 -07:00
/*
* PAXC and the internal emulated endpoint device downstream should not
* be reset . If firmware has been loaded on the endpoint device at an
* earlier boot stage , reset here causes issues .
*/
if ( pcie - > ep_is_internal )
2015-12-04 09:34:59 -08:00
return ;
2015-04-08 11:21:35 -07:00
/*
2015-09-15 17:39:18 -07:00
* Select perst_b signal as reset source . Put the device into reset ,
* and then bring it out of reset
2015-04-08 11:21:35 -07:00
*/
2015-12-04 09:34:59 -08:00
val = iproc_pcie_read_reg ( pcie , IPROC_PCIE_CLK_CTRL ) ;
2015-09-15 17:39:18 -07:00
val & = ~ EP_PERST_SOURCE_SELECT & ~ EP_MODE_SURVIVE_PERST &
~ RC_PCIE_RST_OUTPUT ;
2015-12-04 09:34:59 -08:00
iproc_pcie_write_reg ( pcie , IPROC_PCIE_CLK_CTRL , val ) ;
2015-04-08 11:21:35 -07:00
udelay ( 250 ) ;
2015-09-15 17:39:18 -07:00
val | = RC_PCIE_RST_OUTPUT ;
2015-12-04 09:34:59 -08:00
iproc_pcie_write_reg ( pcie , IPROC_PCIE_CLK_CTRL , val ) ;
2015-09-15 17:39:18 -07:00
msleep ( 100 ) ;
2015-04-08 11:21:35 -07:00
}
2017-06-28 15:13:50 -05:00
static int iproc_pcie_check_link ( struct iproc_pcie * pcie )
2015-04-08 11:21:35 -07:00
{
2016-10-06 13:36:08 -05:00
struct device * dev = pcie - > dev ;
2017-06-28 15:13:50 -05:00
u32 hdr_type , link_ctrl , link_status , class , val ;
u16 pos = PCI_EXP_CAP ;
2015-09-15 17:39:19 -07:00
bool link_is_active = false ;
2015-12-04 09:34:59 -08:00
/*
* PAXC connects to emulated endpoint devices directly and does not
* have a Serdes . Therefore skip the link detection logic here .
*/
2016-10-31 17:38:30 -07:00
if ( pcie - > ep_is_internal )
2015-12-04 09:34:59 -08:00
return 0 ;
val = iproc_pcie_read_reg ( pcie , IPROC_PCIE_LINK_STATUS ) ;
2015-09-15 17:39:19 -07:00
if ( ! ( val & PCIE_PHYLINKUP ) | | ! ( val & PCIE_DL_ACTIVE ) ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev , " PHY or data link is INACTIVE! \n " ) ;
2015-09-15 17:39:19 -07:00
return - ENODEV ;
}
2015-04-08 11:21:35 -07:00
/* make sure we are not in EP mode */
2017-06-28 15:13:50 -05:00
iproc_pci_raw_config_read32 ( pcie , 0 , PCI_HEADER_TYPE , 1 , & hdr_type ) ;
2015-04-08 11:21:35 -07:00
if ( ( hdr_type & 0x7f ) ! = PCI_HEADER_TYPE_BRIDGE ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev , " in EP mode, hdr=%#02x \n " , hdr_type ) ;
2015-04-08 11:21:35 -07:00
return - EFAULT ;
}
/* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
2015-09-15 17:39:19 -07:00
# define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
# define PCI_CLASS_BRIDGE_MASK 0xffff00
# define PCI_CLASS_BRIDGE_SHIFT 8
2017-06-28 15:13:50 -05:00
iproc_pci_raw_config_read32 ( pcie , 0 , PCI_BRIDGE_CTRL_REG_OFFSET ,
4 , & class ) ;
2015-09-15 17:39:19 -07:00
class & = ~ PCI_CLASS_BRIDGE_MASK ;
class | = ( PCI_CLASS_BRIDGE_PCI < < PCI_CLASS_BRIDGE_SHIFT ) ;
2017-06-28 15:13:50 -05:00
iproc_pci_raw_config_write32 ( pcie , 0 , PCI_BRIDGE_CTRL_REG_OFFSET ,
4 , class ) ;
2015-04-08 11:21:35 -07:00
/* check link status to see if link is active */
2017-06-28 15:13:50 -05:00
iproc_pci_raw_config_read32 ( pcie , 0 , pos + PCI_EXP_LNKSTA ,
2 , & link_status ) ;
2015-04-08 11:21:35 -07:00
if ( link_status & PCI_EXP_LNKSTA_NLW )
2015-09-15 17:39:19 -07:00
link_is_active = true ;
2015-04-08 11:21:35 -07:00
if ( ! link_is_active ) {
/* try GEN 1 link speed */
# define PCI_TARGET_LINK_SPEED_MASK 0xf
# define PCI_TARGET_LINK_SPEED_GEN2 0x2
# define PCI_TARGET_LINK_SPEED_GEN1 0x1
2017-06-28 15:13:50 -05:00
iproc_pci_raw_config_read32 ( pcie , 0 ,
pos + PCI_EXP_LNKCTL2 , 4 ,
2015-04-08 11:21:35 -07:00
& link_ctrl ) ;
if ( ( link_ctrl & PCI_TARGET_LINK_SPEED_MASK ) = =
PCI_TARGET_LINK_SPEED_GEN2 ) {
link_ctrl & = ~ PCI_TARGET_LINK_SPEED_MASK ;
link_ctrl | = PCI_TARGET_LINK_SPEED_GEN1 ;
2017-06-28 15:13:50 -05:00
iproc_pci_raw_config_write32 ( pcie , 0 ,
pos + PCI_EXP_LNKCTL2 ,
4 , link_ctrl ) ;
2015-04-08 11:21:35 -07:00
msleep ( 100 ) ;
2017-06-28 15:13:50 -05:00
iproc_pci_raw_config_read32 ( pcie , 0 ,
pos + PCI_EXP_LNKSTA ,
2 , & link_status ) ;
2015-04-08 11:21:35 -07:00
if ( link_status & PCI_EXP_LNKSTA_NLW )
2015-09-15 17:39:19 -07:00
link_is_active = true ;
2015-04-08 11:21:35 -07:00
}
}
2016-10-06 13:36:08 -05:00
dev_info ( dev , " link: %s \n " , link_is_active ? " UP " : " DOWN " ) ;
2015-04-08 11:21:35 -07:00
return link_is_active ? 0 : - ENODEV ;
}
static void iproc_pcie_enable ( struct iproc_pcie * pcie )
{
2015-12-04 09:34:59 -08:00
iproc_pcie_write_reg ( pcie , IPROC_PCIE_INTX_EN , SYS_RC_INTX_MASK ) ;
2015-04-08 11:21:35 -07:00
}
2016-10-31 17:38:37 -07:00
static inline bool iproc_pcie_ob_is_valid ( struct iproc_pcie * pcie ,
int window_idx )
{
u32 val ;
val = iproc_pcie_read_reg ( pcie , MAP_REG ( IPROC_PCIE_OARR0 , window_idx ) ) ;
return ! ! ( val & OARR_VALID ) ;
}
static inline int iproc_pcie_ob_write ( struct iproc_pcie * pcie , int window_idx ,
int size_idx , u64 axi_addr , u64 pci_addr )
{
struct device * dev = pcie - > dev ;
u16 oarr_offset , omap_offset ;
/*
* Derive the OARR / OMAP offset from the first pair ( OARR0 / OMAP0 ) based
* on window index .
*/
oarr_offset = iproc_pcie_reg_offset ( pcie , MAP_REG ( IPROC_PCIE_OARR0 ,
window_idx ) ) ;
omap_offset = iproc_pcie_reg_offset ( pcie , MAP_REG ( IPROC_PCIE_OMAP0 ,
window_idx ) ) ;
if ( iproc_pcie_reg_is_invalid ( oarr_offset ) | |
iproc_pcie_reg_is_invalid ( omap_offset ) )
return - EINVAL ;
/*
* Program the OARR registers . The upper 32 - bit OARR register is
* always right after the lower 32 - bit OARR register .
*/
writel ( lower_32_bits ( axi_addr ) | ( size_idx < < OARR_SIZE_CFG_SHIFT ) |
OARR_VALID , pcie - > base + oarr_offset ) ;
writel ( upper_32_bits ( axi_addr ) , pcie - > base + oarr_offset + 4 ) ;
/* now program the OMAP registers */
writel ( lower_32_bits ( pci_addr ) , pcie - > base + omap_offset ) ;
writel ( upper_32_bits ( pci_addr ) , pcie - > base + omap_offset + 4 ) ;
dev_info ( dev , " ob window [%d]: offset 0x%x axi %pap pci %pap \n " ,
window_idx , oarr_offset , & axi_addr , & pci_addr ) ;
dev_info ( dev , " oarr lo 0x%x oarr hi 0x%x \n " ,
readl ( pcie - > base + oarr_offset ) ,
readl ( pcie - > base + oarr_offset + 4 ) ) ;
dev_info ( dev , " omap lo 0x%x omap hi 0x%x \n " ,
readl ( pcie - > base + omap_offset ) ,
readl ( pcie - > base + omap_offset + 4 ) ) ;
return 0 ;
}
2015-10-16 08:18:24 -05:00
/**
* Some iProc SoCs require the SW to configure the outbound address mapping
*
* Outbound address translation :
*
* iproc_pcie_address = axi_address - axi_offset
* OARR = iproc_pcie_address
* OMAP = pci_addr
*
* axi_addr - > iproc_pcie_address - > OARR - > OMAP - > pci_address
*/
static int iproc_pcie_setup_ob ( struct iproc_pcie * pcie , u64 axi_addr ,
u64 pci_addr , resource_size_t size )
{
struct iproc_pcie_ob * ob = & pcie - > ob ;
2016-10-06 13:36:08 -05:00
struct device * dev = pcie - > dev ;
2016-10-31 17:38:37 -07:00
int ret = - EINVAL , window_idx , size_idx ;
2015-10-16 08:18:24 -05:00
if ( axi_addr < ob - > axi_offset ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev , " axi address %pap less than offset %pap \n " ,
2015-10-16 08:18:24 -05:00
& axi_addr , & ob - > axi_offset ) ;
return - EINVAL ;
}
/*
* Translate the AXI address to the internal address used by the iProc
* PCIe core before programming the OARR
*/
axi_addr - = ob - > axi_offset ;
2016-10-31 17:38:37 -07:00
/* iterate through all OARR/OMAP mapping windows */
for ( window_idx = ob - > nr_windows - 1 ; window_idx > = 0 ; window_idx - - ) {
const struct iproc_pcie_ob_map * ob_map =
& pcie - > ob_map [ window_idx ] ;
/*
* If current outbound window is already in use , move on to the
* next one .
*/
if ( iproc_pcie_ob_is_valid ( pcie , window_idx ) )
continue ;
/*
* Iterate through all supported window sizes within the
* OARR / OMAP pair to find a match . Go through the window sizes
* in a descending order .
*/
for ( size_idx = ob_map - > nr_sizes - 1 ; size_idx > = 0 ;
size_idx - - ) {
resource_size_t window_size =
ob_map - > window_sizes [ size_idx ] * SZ_1M ;
if ( size < window_size )
continue ;
if ( ! IS_ALIGNED ( axi_addr , window_size ) | |
! IS_ALIGNED ( pci_addr , window_size ) ) {
dev_err ( dev ,
" axi %pap or pci %pap not aligned \n " ,
& axi_addr , & pci_addr ) ;
return - EINVAL ;
}
/*
* Match found ! Program both OARR and OMAP and mark
* them as a valid entry .
*/
ret = iproc_pcie_ob_write ( pcie , window_idx , size_idx ,
axi_addr , pci_addr ) ;
if ( ret )
goto err_ob ;
size - = window_size ;
if ( size = = 0 )
return 0 ;
/*
* If we are here , we are done with the current window ,
* but not yet finished all mappings . Need to move on
* to the next window .
*/
axi_addr + = window_size ;
pci_addr + = window_size ;
2015-10-16 08:18:24 -05:00
break ;
2016-10-31 17:38:37 -07:00
}
2015-10-16 08:18:24 -05:00
}
2016-10-31 17:38:37 -07:00
err_ob :
dev_err ( dev , " unable to configure outbound mapping \n " ) ;
dev_err ( dev ,
" axi %pap, axi offset %pap, pci %pap, res size %pap \n " ,
& axi_addr , & ob - > axi_offset , & pci_addr , & size ) ;
return ret ;
2015-10-16 08:18:24 -05:00
}
static int iproc_pcie_map_ranges ( struct iproc_pcie * pcie ,
struct list_head * resources )
{
2016-10-06 13:36:08 -05:00
struct device * dev = pcie - > dev ;
2015-10-16 08:18:24 -05:00
struct resource_entry * window ;
int ret ;
resource_list_for_each_entry ( window , resources ) {
struct resource * res = window - > res ;
u64 res_type = resource_type ( res ) ;
switch ( res_type ) {
case IORESOURCE_IO :
case IORESOURCE_BUS :
break ;
case IORESOURCE_MEM :
ret = iproc_pcie_setup_ob ( pcie , res - > start ,
res - > start - window - > offset ,
resource_size ( res ) ) ;
if ( ret )
return ret ;
break ;
default :
2016-10-06 13:36:08 -05:00
dev_err ( dev , " invalid resource %pR \n " , res ) ;
2015-10-16 08:18:24 -05:00
return - EINVAL ;
}
}
return 0 ;
}
2016-10-31 17:38:39 -07:00
static inline bool iproc_pcie_ib_is_in_use ( struct iproc_pcie * pcie ,
int region_idx )
{
const struct iproc_pcie_ib_map * ib_map = & pcie - > ib_map [ region_idx ] ;
u32 val ;
val = iproc_pcie_read_reg ( pcie , MAP_REG ( IPROC_PCIE_IARR0 , region_idx ) ) ;
return ! ! ( val & ( BIT ( ib_map - > nr_sizes ) - 1 ) ) ;
}
static inline bool iproc_pcie_ib_check_type ( const struct iproc_pcie_ib_map * ib_map ,
enum iproc_pcie_ib_map_type type )
{
return ! ! ( ib_map - > type = = type ) ;
}
static int iproc_pcie_ib_write ( struct iproc_pcie * pcie , int region_idx ,
int size_idx , int nr_windows , u64 axi_addr ,
u64 pci_addr , resource_size_t size )
{
struct device * dev = pcie - > dev ;
const struct iproc_pcie_ib_map * ib_map = & pcie - > ib_map [ region_idx ] ;
u16 iarr_offset , imap_offset ;
u32 val ;
int window_idx ;
iarr_offset = iproc_pcie_reg_offset ( pcie ,
MAP_REG ( IPROC_PCIE_IARR0 , region_idx ) ) ;
imap_offset = iproc_pcie_reg_offset ( pcie ,
MAP_REG ( IPROC_PCIE_IMAP0 , region_idx ) ) ;
if ( iproc_pcie_reg_is_invalid ( iarr_offset ) | |
iproc_pcie_reg_is_invalid ( imap_offset ) )
return - EINVAL ;
dev_info ( dev , " ib region [%d]: offset 0x%x axi %pap pci %pap \n " ,
region_idx , iarr_offset , & axi_addr , & pci_addr ) ;
/*
* Program the IARR registers . The upper 32 - bit IARR register is
* always right after the lower 32 - bit IARR register .
*/
writel ( lower_32_bits ( pci_addr ) | BIT ( size_idx ) ,
pcie - > base + iarr_offset ) ;
writel ( upper_32_bits ( pci_addr ) , pcie - > base + iarr_offset + 4 ) ;
dev_info ( dev , " iarr lo 0x%x iarr hi 0x%x \n " ,
readl ( pcie - > base + iarr_offset ) ,
readl ( pcie - > base + iarr_offset + 4 ) ) ;
/*
* Now program the IMAP registers . Each IARR region may have one or
* more IMAP windows .
*/
size > > = ilog2 ( nr_windows ) ;
for ( window_idx = 0 ; window_idx < nr_windows ; window_idx + + ) {
val = readl ( pcie - > base + imap_offset ) ;
val | = lower_32_bits ( axi_addr ) | IMAP_VALID ;
writel ( val , pcie - > base + imap_offset ) ;
writel ( upper_32_bits ( axi_addr ) ,
pcie - > base + imap_offset + ib_map - > imap_addr_offset ) ;
dev_info ( dev , " imap window [%d] lo 0x%x hi 0x%x \n " ,
window_idx , readl ( pcie - > base + imap_offset ) ,
readl ( pcie - > base + imap_offset +
ib_map - > imap_addr_offset ) ) ;
imap_offset + = ib_map - > imap_window_offset ;
axi_addr + = size ;
}
return 0 ;
}
static int iproc_pcie_setup_ib ( struct iproc_pcie * pcie ,
struct of_pci_range * range ,
enum iproc_pcie_ib_map_type type )
{
struct device * dev = pcie - > dev ;
struct iproc_pcie_ib * ib = & pcie - > ib ;
int ret ;
unsigned int region_idx , size_idx ;
u64 axi_addr = range - > cpu_addr , pci_addr = range - > pci_addr ;
resource_size_t size = range - > size ;
/* iterate through all IARR mapping regions */
for ( region_idx = 0 ; region_idx < ib - > nr_regions ; region_idx + + ) {
const struct iproc_pcie_ib_map * ib_map =
& pcie - > ib_map [ region_idx ] ;
/*
* If current inbound region is already in use or not a
* compatible type , move on to the next .
*/
if ( iproc_pcie_ib_is_in_use ( pcie , region_idx ) | |
! iproc_pcie_ib_check_type ( ib_map , type ) )
continue ;
/* iterate through all supported region sizes to find a match */
for ( size_idx = 0 ; size_idx < ib_map - > nr_sizes ; size_idx + + ) {
resource_size_t region_size =
ib_map - > region_sizes [ size_idx ] * ib_map - > size_unit ;
if ( size ! = region_size )
continue ;
if ( ! IS_ALIGNED ( axi_addr , region_size ) | |
! IS_ALIGNED ( pci_addr , region_size ) ) {
dev_err ( dev ,
" axi %pap or pci %pap not aligned \n " ,
& axi_addr , & pci_addr ) ;
return - EINVAL ;
}
/* Match found! Program IARR and all IMAP windows. */
ret = iproc_pcie_ib_write ( pcie , region_idx , size_idx ,
ib_map - > nr_windows , axi_addr ,
pci_addr , size ) ;
if ( ret )
goto err_ib ;
else
return 0 ;
}
}
ret = - EINVAL ;
err_ib :
dev_err ( dev , " unable to configure inbound mapping \n " ) ;
dev_err ( dev , " axi %pap, pci %pap, res size %pap \n " ,
& axi_addr , & pci_addr , & size ) ;
return ret ;
}
static int pci_dma_range_parser_init ( struct of_pci_range_parser * parser ,
struct device_node * node )
{
const int na = 3 , ns = 2 ;
int rlen ;
parser - > node = node ;
parser - > pna = of_n_addr_cells ( node ) ;
parser - > np = parser - > pna + na + ns ;
parser - > range = of_get_property ( node , " dma-ranges " , & rlen ) ;
if ( ! parser - > range )
return - ENOENT ;
parser - > end = parser - > range + rlen / sizeof ( __be32 ) ;
return 0 ;
}
static int iproc_pcie_map_dma_ranges ( struct iproc_pcie * pcie )
{
struct of_pci_range range ;
struct of_pci_range_parser parser ;
int ret ;
/* Get the dma-ranges from DT */
ret = pci_dma_range_parser_init ( & parser , pcie - > dev - > of_node ) ;
if ( ret )
return ret ;
for_each_of_pci_range ( & parser , & range ) {
/* Each range entry corresponds to an inbound mapping region */
ret = iproc_pcie_setup_ib ( pcie , & range , IPROC_PCIE_IB_MAP_MEM ) ;
if ( ret )
return ret ;
}
return 0 ;
}
2016-10-31 17:38:35 -07:00
static int iproce_pcie_get_msi ( struct iproc_pcie * pcie ,
struct device_node * msi_node ,
u64 * msi_addr )
{
struct device * dev = pcie - > dev ;
int ret ;
struct resource res ;
/*
* Check if ' msi - map ' points to ARM GICv3 ITS , which is the only
* supported external MSI controller that requires steering .
*/
if ( ! of_device_is_compatible ( msi_node , " arm,gic-v3-its " ) ) {
dev_err ( dev , " unable to find compatible MSI controller \n " ) ;
return - ENODEV ;
}
/* derive GITS_TRANSLATER address from GICv3 */
ret = of_address_to_resource ( msi_node , 0 , & res ) ;
if ( ret < 0 ) {
dev_err ( dev , " unable to obtain MSI controller resources \n " ) ;
return ret ;
}
* msi_addr = res . start + GITS_TRANSLATER ;
return 0 ;
}
2016-10-31 17:38:41 -07:00
static int iproc_pcie_paxb_v2_msi_steer ( struct iproc_pcie * pcie , u64 msi_addr )
{
int ret ;
struct of_pci_range range ;
memset ( & range , 0 , sizeof ( range ) ) ;
range . size = SZ_32K ;
2016-11-21 17:48:30 -08:00
range . pci_addr = range . cpu_addr = msi_addr & ~ ( range . size - 1 ) ;
2016-10-31 17:38:41 -07:00
ret = iproc_pcie_setup_ib ( pcie , & range , IPROC_PCIE_IB_MAP_IO ) ;
return ret ;
}
2016-10-31 17:38:35 -07:00
static void iproc_pcie_paxc_v2_msi_steer ( struct iproc_pcie * pcie , u64 msi_addr )
{
u32 val ;
/*
* Program bits [ 43 : 13 ] of address of GITS_TRANSLATER register into
* bits [ 30 : 0 ] of the MSI base address register . In fact , in all iProc
* based SoCs , all I / O register bases are well below the 32 - bit
* boundary , so we can safely assume bits [ 43 : 32 ] are always zeros .
*/
iproc_pcie_write_reg ( pcie , IPROC_PCIE_MSI_BASE_ADDR ,
( u32 ) ( msi_addr > > 13 ) ) ;
/* use a default 8K window size */
iproc_pcie_write_reg ( pcie , IPROC_PCIE_MSI_WINDOW_SIZE , 0 ) ;
/* steering MSI to GICv3 ITS */
val = iproc_pcie_read_reg ( pcie , IPROC_PCIE_MSI_GIC_MODE ) ;
val | = GIC_V3_CFG ;
iproc_pcie_write_reg ( pcie , IPROC_PCIE_MSI_GIC_MODE , val ) ;
/*
* Program bits [ 43 : 2 ] of address of GITS_TRANSLATER register into the
* iProc MSI address registers .
*/
msi_addr > > = 2 ;
iproc_pcie_write_reg ( pcie , IPROC_PCIE_MSI_ADDR_HI ,
upper_32_bits ( msi_addr ) ) ;
iproc_pcie_write_reg ( pcie , IPROC_PCIE_MSI_ADDR_LO ,
lower_32_bits ( msi_addr ) ) ;
/* enable MSI */
val = iproc_pcie_read_reg ( pcie , IPROC_PCIE_MSI_EN_CFG ) ;
val | = MSI_ENABLE_CFG ;
iproc_pcie_write_reg ( pcie , IPROC_PCIE_MSI_EN_CFG , val ) ;
}
static int iproc_pcie_msi_steer ( struct iproc_pcie * pcie ,
struct device_node * msi_node )
{
struct device * dev = pcie - > dev ;
int ret ;
u64 msi_addr ;
ret = iproce_pcie_get_msi ( pcie , msi_node , & msi_addr ) ;
if ( ret < 0 ) {
dev_err ( dev , " msi steering failed \n " ) ;
return ret ;
}
switch ( pcie - > type ) {
2016-10-31 17:38:41 -07:00
case IPROC_PCIE_PAXB_V2 :
ret = iproc_pcie_paxb_v2_msi_steer ( pcie , msi_addr ) ;
if ( ret )
return ret ;
break ;
2016-10-31 17:38:35 -07:00
case IPROC_PCIE_PAXC_V2 :
iproc_pcie_paxc_v2_msi_steer ( pcie , msi_addr ) ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
2016-01-06 18:04:35 -06:00
static int iproc_pcie_msi_enable ( struct iproc_pcie * pcie )
{
struct device_node * msi_node ;
2016-10-31 17:38:35 -07:00
int ret ;
/*
* Either the " msi-parent " or the " msi-map " phandle needs to exist
* for us to obtain the MSI node .
*/
2016-01-06 18:04:35 -06:00
msi_node = of_parse_phandle ( pcie - > dev - > of_node , " msi-parent " , 0 ) ;
2016-10-31 17:38:35 -07:00
if ( ! msi_node ) {
const __be32 * msi_map = NULL ;
int len ;
u32 phandle ;
msi_map = of_get_property ( pcie - > dev - > of_node , " msi-map " , & len ) ;
if ( ! msi_map )
return - ENODEV ;
phandle = be32_to_cpup ( msi_map + 1 ) ;
msi_node = of_find_node_by_phandle ( phandle ) ;
if ( ! msi_node )
return - ENODEV ;
}
/*
* Certain revisions of the iProc PCIe controller require additional
* configurations to steer the MSI writes towards an external MSI
* controller .
*/
if ( pcie - > need_msi_steer ) {
ret = iproc_pcie_msi_steer ( pcie , msi_node ) ;
if ( ret )
return ret ;
}
2016-01-06 18:04:35 -06:00
/*
* If another MSI controller is being used , the call below should fail
* but that is okay
*/
return iproc_msi_init ( pcie , msi_node ) ;
}
static void iproc_pcie_msi_disable ( struct iproc_pcie * pcie )
{
iproc_msi_exit ( pcie ) ;
}
2016-10-31 17:38:30 -07:00
static int iproc_pcie_rev_init ( struct iproc_pcie * pcie )
{
struct device * dev = pcie - > dev ;
unsigned int reg_idx ;
const u16 * regs ;
switch ( pcie - > type ) {
2016-10-31 17:38:32 -07:00
case IPROC_PCIE_PAXB_BCMA :
regs = iproc_pcie_reg_paxb_bcma ;
break ;
2016-10-31 17:38:30 -07:00
case IPROC_PCIE_PAXB :
regs = iproc_pcie_reg_paxb ;
2016-10-31 17:38:33 -07:00
pcie - > has_apb_err_disable = true ;
2016-10-31 17:38:37 -07:00
if ( pcie - > need_ob_cfg ) {
pcie - > ob_map = paxb_ob_map ;
pcie - > ob . nr_windows = ARRAY_SIZE ( paxb_ob_map ) ;
}
2016-10-31 17:38:30 -07:00
break ;
2016-10-31 17:38:41 -07:00
case IPROC_PCIE_PAXB_V2 :
regs = iproc_pcie_reg_paxb_v2 ;
pcie - > has_apb_err_disable = true ;
if ( pcie - > need_ob_cfg ) {
pcie - > ob_map = paxb_v2_ob_map ;
pcie - > ob . nr_windows = ARRAY_SIZE ( paxb_v2_ob_map ) ;
}
pcie - > ib . nr_regions = ARRAY_SIZE ( paxb_v2_ib_map ) ;
pcie - > ib_map = paxb_v2_ib_map ;
pcie - > need_msi_steer = true ;
break ;
2016-10-31 17:38:30 -07:00
case IPROC_PCIE_PAXC :
regs = iproc_pcie_reg_paxc ;
pcie - > ep_is_internal = true ;
break ;
2016-10-31 17:38:35 -07:00
case IPROC_PCIE_PAXC_V2 :
regs = iproc_pcie_reg_paxc_v2 ;
pcie - > ep_is_internal = true ;
pcie - > need_msi_steer = true ;
break ;
2016-10-31 17:38:30 -07:00
default :
dev_err ( dev , " incompatible iProc PCIe interface \n " ) ;
return - EINVAL ;
}
pcie - > reg_offsets = devm_kcalloc ( dev , IPROC_PCIE_MAX_NUM_REG ,
sizeof ( * pcie - > reg_offsets ) ,
GFP_KERNEL ) ;
if ( ! pcie - > reg_offsets )
return - ENOMEM ;
/* go through the register table and populate all valid registers */
2016-10-31 17:38:35 -07:00
pcie - > reg_offsets [ 0 ] = ( pcie - > type = = IPROC_PCIE_PAXC_V2 ) ?
IPROC_PCIE_REG_INVALID : regs [ 0 ] ;
2016-10-31 17:38:30 -07:00
for ( reg_idx = 1 ; reg_idx < IPROC_PCIE_MAX_NUM_REG ; reg_idx + + )
pcie - > reg_offsets [ reg_idx ] = regs [ reg_idx ] ?
regs [ reg_idx ] : IPROC_PCIE_REG_INVALID ;
return 0 ;
}
2015-05-24 22:37:02 +02:00
int iproc_pcie_setup ( struct iproc_pcie * pcie , struct list_head * res )
2015-04-08 11:21:35 -07:00
{
2016-10-06 13:36:08 -05:00
struct device * dev ;
2015-04-08 11:21:35 -07:00
int ret ;
2015-07-21 18:29:40 -07:00
void * sysdata ;
2017-06-28 15:13:57 -05:00
struct pci_bus * child ;
struct pci_host_bridge * host = pci_host_bridge_from_priv ( pcie ) ;
2015-04-08 11:21:35 -07:00
2016-10-06 13:36:08 -05:00
dev = pcie - > dev ;
2016-10-31 17:38:30 -07:00
ret = iproc_pcie_rev_init ( pcie ) ;
if ( ret ) {
dev_err ( dev , " unable to initialize controller parameters \n " ) ;
return ret ;
}
2016-10-06 13:36:08 -05:00
ret = devm_request_pci_bus_resources ( dev , res ) ;
2016-05-28 18:22:24 -05:00
if ( ret )
return ret ;
2015-06-28 16:42:04 +02:00
ret = phy_init ( pcie - > phy ) ;
if ( ret ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev , " unable to initialize PCIe PHY \n " ) ;
2015-06-28 16:42:04 +02:00
return ret ;
}
2015-04-08 11:21:35 -07:00
2015-06-28 16:42:04 +02:00
ret = phy_power_on ( pcie - > phy ) ;
if ( ret ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev , " unable to power on PCIe PHY \n " ) ;
2015-06-28 16:42:04 +02:00
goto err_exit_phy ;
2015-04-08 11:21:35 -07:00
}
iproc_pcie_reset ( pcie ) ;
2015-10-16 08:18:24 -05:00
if ( pcie - > need_ob_cfg ) {
ret = iproc_pcie_map_ranges ( pcie , res ) ;
if ( ret ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev , " map failed \n " ) ;
2015-10-16 08:18:24 -05:00
goto err_power_off_phy ;
}
}
2016-10-31 17:38:39 -07:00
ret = iproc_pcie_map_dma_ranges ( pcie ) ;
if ( ret & & ret ! = - ENOENT )
goto err_power_off_phy ;
2015-07-21 18:29:40 -07:00
# ifdef CONFIG_ARM
2015-04-08 11:21:35 -07:00
pcie - > sysdata . private_data = pcie ;
2015-07-21 18:29:40 -07:00
sysdata = & pcie - > sysdata ;
# else
sysdata = pcie ;
# endif
2015-04-08 11:21:35 -07:00
2017-06-28 15:13:50 -05:00
ret = iproc_pcie_check_link ( pcie ) ;
2015-04-08 11:21:35 -07:00
if ( ret ) {
2016-10-06 13:36:08 -05:00
dev_err ( dev , " no PCIe EP device detected \n " ) ;
2017-06-28 15:13:57 -05:00
goto err_power_off_phy ;
2015-04-08 11:21:35 -07:00
}
iproc_pcie_enable ( pcie ) ;
2016-01-06 18:04:35 -06:00
if ( IS_ENABLED ( CONFIG_PCI_MSI ) )
if ( iproc_pcie_msi_enable ( pcie ) )
2016-10-06 13:36:08 -05:00
dev_info ( dev , " not using iProc MSI \n " ) ;
2016-01-06 18:04:35 -06:00
2017-06-28 15:13:57 -05:00
list_splice_init ( res , & host - > windows ) ;
host - > busnr = 0 ;
host - > dev . parent = dev ;
host - > ops = & iproc_pcie_ops ;
host - > sysdata = sysdata ;
ret = pci_scan_root_bus_bridge ( host ) ;
if ( ret < 0 ) {
dev_err ( dev , " failed to scan host: %d \n " , ret ) ;
goto err_power_off_phy ;
}
2016-12-01 15:34:52 -05:00
if ( pcie - > map_irq )
pci_fixup_irqs ( pci_common_swizzle , pcie - > map_irq ) ;
2017-06-28 15:13:57 -05:00
pci_assign_unassigned_bus_resources ( host - > bus ) ;
pcie - > root_bus = host - > bus ;
list_for_each_entry ( child , & host - > bus - > children , node )
2017-01-27 16:44:08 -05:00
pcie_bus_configure_settings ( child ) ;
2017-06-28 15:13:57 -05:00
pci_bus_add_devices ( host - > bus ) ;
2015-04-08 11:21:35 -07:00
return 0 ;
err_power_off_phy :
2015-06-28 16:42:04 +02:00
phy_power_off ( pcie - > phy ) ;
2015-04-08 11:21:35 -07:00
err_exit_phy :
2015-06-28 16:42:04 +02:00
phy_exit ( pcie - > phy ) ;
2015-04-08 11:21:35 -07:00
return ret ;
}
EXPORT_SYMBOL ( iproc_pcie_setup ) ;
int iproc_pcie_remove ( struct iproc_pcie * pcie )
{
pci_stop_root_bus ( pcie - > root_bus ) ;
pci_remove_root_bus ( pcie - > root_bus ) ;
2016-01-06 18:04:35 -06:00
iproc_pcie_msi_disable ( pcie ) ;
2015-06-28 16:42:04 +02:00
phy_power_off ( pcie - > phy ) ;
phy_exit ( pcie - > phy ) ;
2015-04-08 11:21:35 -07:00
return 0 ;
}
EXPORT_SYMBOL ( iproc_pcie_remove ) ;
MODULE_AUTHOR ( " Ray Jui <rjui@broadcom.com> " ) ;
MODULE_DESCRIPTION ( " Broadcom iPROC PCIe common driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;