2018-01-26 12:50:27 -06:00
// SPDX-License-Identifier: GPL-2.0
2013-10-29 20:12:51 +04:00
/*
* pci - rcar - gen2 : internal PCI bus support
*
* Copyright ( C ) 2013 Renesas Solutions Corp .
* Copyright ( C ) 2013 Cogent Embedded , Inc .
*
2016-07-02 19:13:30 -04:00
* Author : Valentine Barshak < valentine . barshak @ cogentembedded . com >
2013-10-29 20:12:51 +04:00
*/
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/kernel.h>
2015-11-03 16:19:26 +00:00
# include <linux/of_address.h>
2014-04-07 11:30:20 +02:00
# include <linux/of_pci.h>
2013-10-29 20:12:51 +04:00
# include <linux/pci.h>
# include <linux/platform_device.h>
2013-12-04 20:33:35 +04:00
# include <linux/pm_runtime.h>
2014-02-18 11:11:32 +09:00
# include <linux/sizes.h>
2013-10-29 20:12:51 +04:00
# include <linux/slab.h>
2018-05-11 12:15:30 -05:00
# include "../pci.h"
2013-10-29 20:12:51 +04:00
/* AHB-PCI Bridge PCI communication registers */
# define RCAR_AHBPCI_PCICOM_OFFSET 0x800
# define RCAR_PCIAHB_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x00)
# define RCAR_PCIAHB_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x04)
# define RCAR_PCIAHB_PREFETCH0 0x0
# define RCAR_PCIAHB_PREFETCH4 0x1
# define RCAR_PCIAHB_PREFETCH8 0x2
# define RCAR_PCIAHB_PREFETCH16 0x3
# define RCAR_AHBPCI_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x10)
# define RCAR_AHBPCI_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x14)
# define RCAR_AHBPCI_WIN_CTR_MEM (3 << 1)
# define RCAR_AHBPCI_WIN_CTR_CFG (5 << 1)
# define RCAR_AHBPCI_WIN1_HOST (1 << 30)
# define RCAR_AHBPCI_WIN1_DEVICE (1 << 31)
# define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20)
# define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24)
2014-02-18 11:11:01 +09:00
# define RCAR_PCI_INT_SIGTABORT (1 << 0)
# define RCAR_PCI_INT_SIGRETABORT (1 << 1)
# define RCAR_PCI_INT_REMABORT (1 << 2)
# define RCAR_PCI_INT_PERR (1 << 3)
# define RCAR_PCI_INT_SIGSERR (1 << 4)
# define RCAR_PCI_INT_RESERR (1 << 5)
# define RCAR_PCI_INT_WIN1ERR (1 << 12)
# define RCAR_PCI_INT_WIN2ERR (1 << 13)
2013-10-29 20:12:51 +04:00
# define RCAR_PCI_INT_A (1 << 16)
# define RCAR_PCI_INT_B (1 << 17)
# define RCAR_PCI_INT_PME (1 << 19)
2014-02-18 11:11:01 +09:00
# define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT | \
RCAR_PCI_INT_SIGRETABORT | \
RCAR_PCI_INT_REMABORT | \
RCAR_PCI_INT_PERR | \
RCAR_PCI_INT_SIGSERR | \
RCAR_PCI_INT_RESERR | \
RCAR_PCI_INT_WIN1ERR | \
RCAR_PCI_INT_WIN2ERR )
2013-10-29 20:12:51 +04:00
# define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30)
# define RCAR_AHB_BUS_MMODE_HTRANS (1 << 0)
# define RCAR_AHB_BUS_MMODE_BYTE_BURST (1 << 1)
# define RCAR_AHB_BUS_MMODE_WR_INCR (1 << 2)
# define RCAR_AHB_BUS_MMODE_HBUS_REQ (1 << 7)
# define RCAR_AHB_BUS_SMODE_READYCTR (1 << 17)
# define RCAR_AHB_BUS_MODE (RCAR_AHB_BUS_MMODE_HTRANS | \
RCAR_AHB_BUS_MMODE_BYTE_BURST | \
RCAR_AHB_BUS_MMODE_WR_INCR | \
RCAR_AHB_BUS_MMODE_HBUS_REQ | \
RCAR_AHB_BUS_SMODE_READYCTR )
# define RCAR_USBCTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x34)
# define RCAR_USBCTR_USBH_RST (1 << 0)
# define RCAR_USBCTR_PCICLK_MASK (1 << 1)
# define RCAR_USBCTR_PLL_RST (1 << 2)
# define RCAR_USBCTR_DIRPD (1 << 8)
# define RCAR_USBCTR_PCIAHB_WIN2_EN (1 << 9)
# define RCAR_USBCTR_PCIAHB_WIN1_256M (0 << 10)
# define RCAR_USBCTR_PCIAHB_WIN1_512M (1 << 10)
# define RCAR_USBCTR_PCIAHB_WIN1_1G (2 << 10)
# define RCAR_USBCTR_PCIAHB_WIN1_2G (3 << 10)
# define RCAR_USBCTR_PCIAHB_WIN1_MASK (3 << 10)
# define RCAR_PCI_ARBITER_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x40)
# define RCAR_PCI_ARBITER_PCIREQ0 (1 << 0)
# define RCAR_PCI_ARBITER_PCIREQ1 (1 << 1)
# define RCAR_PCI_ARBITER_PCIBP_MODE (1 << 12)
# define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
struct rcar_pci_priv {
2013-12-04 20:33:35 +04:00
struct device * dev ;
2013-10-29 20:12:51 +04:00
void __iomem * reg ;
struct resource mem_res ;
struct resource * cfg_res ;
2014-05-20 01:10:20 +04:00
unsigned busnr ;
2013-10-29 20:12:51 +04:00
int irq ;
2014-02-18 11:11:32 +09:00
unsigned long window_size ;
2015-11-03 16:19:26 +00:00
unsigned long window_addr ;
unsigned long window_pci ;
2013-10-29 20:12:51 +04:00
} ;
/* PCI configuration space operations */
static void __iomem * rcar_pci_cfg_base ( struct pci_bus * bus , unsigned int devfn ,
int where )
{
struct pci_sys_data * sys = bus - > sysdata ;
struct rcar_pci_priv * priv = sys - > private_data ;
int slot , val ;
if ( sys - > busnr ! = bus - > number | | PCI_FUNC ( devfn ) )
return NULL ;
/* Only one EHCI/OHCI device built-in */
slot = PCI_SLOT ( devfn ) ;
if ( slot > 2 )
return NULL ;
2014-02-18 11:11:11 +09:00
/* bridge logic only has registers to 0x40 */
if ( slot = = 0x0 & & where > = 0x40 )
return NULL ;
2013-10-29 20:12:51 +04:00
val = slot ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG ;
iowrite32 ( val , priv - > reg + RCAR_AHBPCI_WIN1_CTR_REG ) ;
return priv - > reg + ( slot > > 1 ) * 0x100 + where ;
}
/* PCI interrupt mapping */
2014-02-18 11:11:21 +09:00
static int rcar_pci_map_irq ( const struct pci_dev * dev , u8 slot , u8 pin )
2013-10-29 20:12:51 +04:00
{
struct pci_sys_data * sys = dev - > bus - > sysdata ;
struct rcar_pci_priv * priv = sys - > private_data ;
2014-04-07 11:30:20 +02:00
int irq ;
irq = of_irq_parse_and_map_pci ( dev , slot , pin ) ;
if ( ! irq )
irq = priv - > irq ;
2013-10-29 20:12:51 +04:00
2014-04-07 11:30:20 +02:00
return irq ;
2013-10-29 20:12:51 +04:00
}
2014-02-18 11:11:01 +09:00
# ifdef CONFIG_PCI_DEBUG
/* if debug enabled, then attach an error handler irq to the bridge */
static irqreturn_t rcar_pci_err_irq ( int irq , void * pw )
{
struct rcar_pci_priv * priv = pw ;
2016-10-10 15:04:14 -05:00
struct device * dev = priv - > dev ;
2014-02-18 11:11:01 +09:00
u32 status = ioread32 ( priv - > reg + RCAR_PCI_INT_STATUS_REG ) ;
if ( status & RCAR_PCI_INT_ALLERRORS ) {
2016-10-10 15:04:14 -05:00
dev_err ( dev , " error irq: status %08x \n " , status ) ;
2014-02-18 11:11:01 +09:00
/* clear the error(s) */
iowrite32 ( status & RCAR_PCI_INT_ALLERRORS ,
priv - > reg + RCAR_PCI_INT_STATUS_REG ) ;
return IRQ_HANDLED ;
}
return IRQ_NONE ;
}
static void rcar_pci_setup_errirq ( struct rcar_pci_priv * priv )
{
2016-10-10 15:04:14 -05:00
struct device * dev = priv - > dev ;
2014-02-18 11:11:01 +09:00
int ret ;
u32 val ;
2016-10-10 15:04:14 -05:00
ret = devm_request_irq ( dev , priv - > irq , rcar_pci_err_irq ,
2014-02-18 11:11:01 +09:00
IRQF_SHARED , " error irq " , priv ) ;
if ( ret ) {
2016-10-10 15:04:14 -05:00
dev_err ( dev , " cannot claim IRQ for error handling \n " ) ;
2014-02-18 11:11:01 +09:00
return ;
}
val = ioread32 ( priv - > reg + RCAR_PCI_INT_ENABLE_REG ) ;
val | = RCAR_PCI_INT_ALLERRORS ;
iowrite32 ( val , priv - > reg + RCAR_PCI_INT_ENABLE_REG ) ;
}
# else
static inline void rcar_pci_setup_errirq ( struct rcar_pci_priv * priv ) { }
# endif
2013-10-29 20:12:51 +04:00
/* PCI host controller setup */
2014-02-18 11:11:21 +09:00
static int rcar_pci_setup ( int nr , struct pci_sys_data * sys )
2013-10-29 20:12:51 +04:00
{
struct rcar_pci_priv * priv = sys - > private_data ;
2016-10-10 15:04:14 -05:00
struct device * dev = priv - > dev ;
2013-10-29 20:12:51 +04:00
void __iomem * reg = priv - > reg ;
u32 val ;
2016-06-06 17:26:31 -05:00
int ret ;
2013-10-29 20:12:51 +04:00
2016-10-10 15:04:14 -05:00
pm_runtime_enable ( dev ) ;
pm_runtime_get_sync ( dev ) ;
2013-12-04 20:33:35 +04:00
2013-10-29 20:12:51 +04:00
val = ioread32 ( reg + RCAR_PCI_UNIT_REV_REG ) ;
2016-10-10 15:04:14 -05:00
dev_info ( dev , " PCI: bus%u revision %x \n " , sys - > busnr , val ) ;
2013-10-29 20:12:51 +04:00
/* Disable Direct Power Down State and assert reset */
val = ioread32 ( reg + RCAR_USBCTR_REG ) & ~ RCAR_USBCTR_DIRPD ;
val | = RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST ;
iowrite32 ( val , reg + RCAR_USBCTR_REG ) ;
udelay ( 4 ) ;
2014-02-18 11:11:32 +09:00
/* De-assert reset and reset PCIAHB window1 size */
2013-10-29 20:12:51 +04:00
val & = ~ ( RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK |
RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST ) ;
2014-02-18 11:11:32 +09:00
/* Setup PCIAHB window1 size */
switch ( priv - > window_size ) {
case SZ_2G :
val | = RCAR_USBCTR_PCIAHB_WIN1_2G ;
break ;
case SZ_1G :
val | = RCAR_USBCTR_PCIAHB_WIN1_1G ;
break ;
case SZ_512M :
val | = RCAR_USBCTR_PCIAHB_WIN1_512M ;
break ;
default :
pr_warn ( " unknown window size %ld - defaulting to 256M \n " ,
priv - > window_size ) ;
priv - > window_size = SZ_256M ;
/* fall-through */
case SZ_256M :
val | = RCAR_USBCTR_PCIAHB_WIN1_256M ;
break ;
}
iowrite32 ( val , reg + RCAR_USBCTR_REG ) ;
2013-10-29 20:12:51 +04:00
/* Configure AHB master and slave modes */
iowrite32 ( RCAR_AHB_BUS_MODE , reg + RCAR_AHB_BUS_CTR_REG ) ;
/* Configure PCI arbiter */
val = ioread32 ( reg + RCAR_PCI_ARBITER_CTR_REG ) ;
val | = RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
RCAR_PCI_ARBITER_PCIBP_MODE ;
iowrite32 ( val , reg + RCAR_PCI_ARBITER_CTR_REG ) ;
2015-11-03 16:19:26 +00:00
/* PCI-AHB mapping */
iowrite32 ( priv - > window_addr | RCAR_PCIAHB_PREFETCH16 ,
2013-10-29 20:12:51 +04:00
reg + RCAR_PCIAHB_WIN1_CTR_REG ) ;
/* AHB-PCI mapping: OHCI/EHCI registers */
val = priv - > mem_res . start | RCAR_AHBPCI_WIN_CTR_MEM ;
iowrite32 ( val , reg + RCAR_AHBPCI_WIN2_CTR_REG ) ;
/* Enable AHB-PCI bridge PCI configuration access */
iowrite32 ( RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG ,
reg + RCAR_AHBPCI_WIN1_CTR_REG ) ;
/* Set PCI-AHB Window1 address */
2015-11-03 16:19:26 +00:00
iowrite32 ( priv - > window_pci | PCI_BASE_ADDRESS_MEM_PREFETCH ,
2013-10-29 20:12:51 +04:00
reg + PCI_BASE_ADDRESS_1 ) ;
/* Set AHB-PCI bridge PCI communication area address */
val = priv - > cfg_res - > start + RCAR_AHBPCI_PCICOM_OFFSET ;
iowrite32 ( val , reg + PCI_BASE_ADDRESS_0 ) ;
val = ioread32 ( reg + PCI_COMMAND ) ;
val | = PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER ;
iowrite32 ( val , reg + PCI_COMMAND ) ;
/* Enable PCI interrupts */
iowrite32 ( RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME ,
reg + RCAR_PCI_INT_ENABLE_REG ) ;
2014-02-18 11:11:01 +09:00
if ( priv - > irq > 0 )
rcar_pci_setup_errirq ( priv ) ;
2013-10-29 20:12:51 +04:00
/* Add PCI resources */
pci_add_resource ( & sys - > resources , & priv - > mem_res ) ;
2016-10-10 15:04:14 -05:00
ret = devm_request_pci_bus_resources ( dev , & sys - > resources ) ;
2016-06-06 17:26:31 -05:00
if ( ret < 0 )
return ret ;
2013-10-29 20:12:51 +04:00
2014-05-20 01:10:20 +04:00
/* Setup bus number based on platform device id / of bus-range */
sys - > busnr = priv - > busnr ;
2013-10-29 20:12:51 +04:00
return 1 ;
}
static struct pci_ops rcar_pci_ops = {
2015-01-09 20:34:47 -06:00
. map_bus = rcar_pci_cfg_base ,
. read = pci_generic_config_read ,
. write = pci_generic_config_write ,
2013-10-29 20:12:51 +04:00
} ;
2015-11-03 16:19:26 +00:00
static int rcar_pci_parse_map_dma_ranges ( struct rcar_pci_priv * pci ,
struct device_node * np )
{
2016-10-10 15:04:14 -05:00
struct device * dev = pci - > dev ;
2015-11-03 16:19:26 +00:00
struct of_pci_range range ;
struct of_pci_range_parser parser ;
int index = 0 ;
/* Failure to parse is ok as we fall back to defaults */
2017-09-26 12:26:55 +02:00
if ( of_pci_dma_range_parser_init ( & parser , np ) )
2015-11-03 16:19:26 +00:00
return 0 ;
/* Get the dma-ranges from DT */
for_each_of_pci_range ( & parser , & range ) {
/* Hardware only allows one inbound 32-bit range */
if ( index )
return - EINVAL ;
pci - > window_addr = ( unsigned long ) range . cpu_addr ;
pci - > window_pci = ( unsigned long ) range . pci_addr ;
pci - > window_size = ( unsigned long ) range . size ;
/* Catch HW limitations */
if ( ! ( range . flags & IORESOURCE_PREFETCH ) ) {
2016-10-10 15:04:14 -05:00
dev_err ( dev , " window must be prefetchable \n " ) ;
2015-11-03 16:19:26 +00:00
return - EINVAL ;
}
if ( pci - > window_addr ) {
u32 lowaddr = 1 < < ( ffs ( pci - > window_addr ) - 1 ) ;
if ( lowaddr < pci - > window_size ) {
2016-10-10 15:04:14 -05:00
dev_err ( dev , " invalid window size/addr \n " ) ;
2015-11-03 16:19:26 +00:00
return - EINVAL ;
}
}
index + + ;
}
return 0 ;
}
2014-02-18 11:11:21 +09:00
static int rcar_pci_probe ( struct platform_device * pdev )
2013-10-29 20:12:51 +04:00
{
2016-10-10 15:04:14 -05:00
struct device * dev = & pdev - > dev ;
2013-10-29 20:12:51 +04:00
struct resource * cfg_res , * mem_res ;
struct rcar_pci_priv * priv ;
void __iomem * reg ;
2014-02-18 11:11:21 +09:00
struct hw_pci hw ;
void * hw_private [ 1 ] ;
2013-10-29 20:12:51 +04:00
cfg_res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2016-10-10 15:04:14 -05:00
reg = devm_ioremap_resource ( dev , cfg_res ) ;
2013-11-19 11:40:28 +08:00
if ( IS_ERR ( reg ) )
return PTR_ERR ( reg ) ;
2013-10-29 20:12:51 +04:00
mem_res = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
if ( ! mem_res | | ! mem_res - > start )
return - ENODEV ;
2015-02-16 10:54:08 +09:00
if ( mem_res - > start & 0xFFFF )
return - EINVAL ;
2016-10-10 15:04:14 -05:00
priv = devm_kzalloc ( dev , sizeof ( struct rcar_pci_priv ) , GFP_KERNEL ) ;
2013-10-29 20:12:51 +04:00
if ( ! priv )
return - ENOMEM ;
priv - > mem_res = * mem_res ;
priv - > cfg_res = cfg_res ;
priv - > irq = platform_get_irq ( pdev , 0 ) ;
priv - > reg = reg ;
2016-10-10 15:04:14 -05:00
priv - > dev = dev ;
2013-10-29 20:12:51 +04:00
2014-02-18 11:10:51 +09:00
if ( priv - > irq < 0 ) {
2016-10-10 15:04:14 -05:00
dev_err ( dev , " no valid irq found \n " ) ;
2014-02-18 11:10:51 +09:00
return priv - > irq ;
}
2015-11-03 16:19:26 +00:00
/* default window addr and size if not specified in DT */
priv - > window_addr = 0x40000000 ;
priv - > window_pci = 0x40000000 ;
2014-02-18 11:11:32 +09:00
priv - > window_size = SZ_1G ;
2016-10-10 15:04:14 -05:00
if ( dev - > of_node ) {
2014-05-20 01:10:20 +04:00
struct resource busnr ;
int ret ;
2016-10-10 15:04:14 -05:00
ret = of_pci_parse_bus_range ( dev - > of_node , & busnr ) ;
2014-05-20 01:10:20 +04:00
if ( ret < 0 ) {
2016-10-10 15:04:14 -05:00
dev_err ( dev , " failed to parse bus-range \n " ) ;
2014-05-20 01:10:20 +04:00
return ret ;
}
priv - > busnr = busnr . start ;
if ( busnr . end ! = busnr . start )
2016-10-10 15:04:14 -05:00
dev_warn ( dev , " only one bus number supported \n " ) ;
2015-11-03 16:19:26 +00:00
2016-10-10 15:04:14 -05:00
ret = rcar_pci_parse_map_dma_ranges ( priv , dev - > of_node ) ;
2015-11-03 16:19:26 +00:00
if ( ret < 0 ) {
2016-10-10 15:04:14 -05:00
dev_err ( dev , " failed to parse dma-range \n " ) ;
2015-11-03 16:19:26 +00:00
return ret ;
}
2014-05-20 01:10:20 +04:00
} else {
priv - > busnr = pdev - > id ;
}
2014-02-18 11:11:21 +09:00
hw_private [ 0 ] = priv ;
memset ( & hw , 0 , sizeof ( hw ) ) ;
hw . nr_controllers = ARRAY_SIZE ( hw_private ) ;
2016-06-21 09:19:34 -05:00
hw . io_optional = 1 ;
2014-02-18 11:11:21 +09:00
hw . private_data = hw_private ;
hw . map_irq = rcar_pci_map_irq ;
hw . ops = & rcar_pci_ops ;
hw . setup = rcar_pci_setup ;
2016-10-10 15:04:14 -05:00
pci_common_init_dev ( dev , & hw ) ;
2014-02-18 11:11:21 +09:00
return 0 ;
2013-10-29 20:12:51 +04:00
}
2017-06-23 14:59:52 +05:30
static const struct of_device_id rcar_pci_of_match [ ] = {
2014-05-20 01:10:20 +04:00
{ . compatible = " renesas,pci-r8a7790 " , } ,
{ . compatible = " renesas,pci-r8a7791 " , } ,
2015-09-12 02:06:09 +03:00
{ . compatible = " renesas,pci-r8a7794 " , } ,
2016-12-06 16:51:29 +01:00
{ . compatible = " renesas,pci-rcar-gen2 " , } ,
2014-05-20 01:10:20 +04:00
{ } ,
} ;
2013-10-29 20:12:51 +04:00
static struct platform_driver rcar_pci_driver = {
. driver = {
. name = " pci-rcar-gen2 " ,
2014-02-18 11:11:21 +09:00
. suppress_bind_attrs = true ,
2014-05-20 01:10:20 +04:00
. of_match_table = rcar_pci_of_match ,
2013-10-29 20:12:51 +04:00
} ,
2014-02-18 11:11:21 +09:00
. probe = rcar_pci_probe ,
2013-10-29 20:12:51 +04:00
} ;
2016-07-02 19:13:30 -04:00
builtin_platform_driver ( rcar_pci_driver ) ;