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)
2021-12-22 19:10:49 -06:00
struct rcar_pci {
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 ;
int irq ;
} ;
/* PCI configuration space operations */
static void __iomem * rcar_pci_cfg_base ( struct pci_bus * bus , unsigned int devfn ,
int where )
{
2021-12-22 19:10:49 -06:00
struct rcar_pci * priv = bus - > sysdata ;
2013-10-29 20:12:51 +04:00
int slot , val ;
2020-07-21 20:25:12 -06:00
if ( ! pci_is_root_bus ( bus ) | | PCI_FUNC ( devfn ) )
2013-10-29 20:12:51 +04:00
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 ;
}
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 )
{
2021-12-22 19:10:49 -06:00
struct rcar_pci * 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 ;
}
2021-12-22 19:10:49 -06:00
static void rcar_pci_setup_errirq ( struct rcar_pci * priv )
2014-02-18 11:11:01 +09:00
{
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
2021-12-22 19:10:49 -06:00
static inline void rcar_pci_setup_errirq ( struct rcar_pci * priv ) { }
2014-02-18 11:11:01 +09:00
# endif
2013-10-29 20:12:51 +04:00
/* PCI host controller setup */
2021-12-22 19:10:49 -06:00
static void rcar_pci_setup ( struct rcar_pci * priv )
2013-10-29 20:12:51 +04:00
{
2020-07-21 20:25:12 -06:00
struct pci_host_bridge * bridge = pci_host_bridge_from_priv ( priv ) ;
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 ;
2020-07-21 20:25:12 -06:00
struct resource_entry * entry ;
unsigned long window_size ;
unsigned long window_addr ;
unsigned long window_pci ;
2013-10-29 20:12:51 +04:00
u32 val ;
2020-07-21 20:25:12 -06:00
entry = resource_list_first_type ( & bridge - > dma_ranges , IORESOURCE_MEM ) ;
if ( ! entry ) {
window_addr = 0x40000000 ;
window_pci = 0x40000000 ;
window_size = SZ_1G ;
} else {
window_addr = entry - > res - > start ;
window_pci = entry - > res - > start - entry - > offset ;
window_size = resource_size ( entry - > res ) ;
}
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 ) ;
2020-07-21 20:25:12 -06:00
dev_info ( dev , " PCI: revision %x \n " , 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 */
2020-07-21 20:25:12 -06:00
switch ( window_size ) {
2014-02-18 11:11:32 +09:00
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 " ,
2020-07-21 20:25:12 -06:00
window_size ) ;
window_size = SZ_256M ;
2020-08-23 17:36:59 -05:00
fallthrough ;
2014-02-18 11:11:32 +09:00
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 */
2020-07-21 20:25:12 -06:00
iowrite32 ( 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 */
2020-07-21 20:25:12 -06:00
iowrite32 ( 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 ) ;
2020-07-21 20:25:12 -06:00
rcar_pci_setup_errirq ( priv ) ;
2013-10-29 20:12:51 +04:00
}
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
} ;
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 ;
2021-12-22 19:10:49 -06:00
struct rcar_pci * priv ;
2020-07-21 20:25:12 -06:00
struct pci_host_bridge * bridge ;
2013-10-29 20:12:51 +04:00
void __iomem * reg ;
2020-07-21 20:25:12 -06:00
bridge = devm_pci_alloc_host_bridge ( dev , sizeof ( * priv ) ) ;
if ( ! bridge )
return - ENOMEM ;
priv = pci_host_bridge_priv ( bridge ) ;
bridge - > sysdata = priv ;
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 ;
2013-10-29 20:12:51 +04:00
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 ;
}
2020-07-21 20:25:12 -06:00
bridge - > ops = & rcar_pci_ops ;
pci_add_flags ( PCI_REASSIGN_ALL_BUS ) ;
rcar_pci_setup ( priv ) ;
2014-05-20 01:10:20 +04:00
2020-07-21 20:25:12 -06:00
return pci_host_probe ( bridge ) ;
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 ) ;