cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pci-rcar-gen2.c (9852B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  pci-rcar-gen2: internal PCI bus support
      4 *
      5 * Copyright (C) 2013 Renesas Solutions Corp.
      6 * Copyright (C) 2013 Cogent Embedded, Inc.
      7 *
      8 * Author: Valentine Barshak <valentine.barshak@cogentembedded.com>
      9 */
     10
     11#include <linux/delay.h>
     12#include <linux/init.h>
     13#include <linux/interrupt.h>
     14#include <linux/io.h>
     15#include <linux/kernel.h>
     16#include <linux/of_address.h>
     17#include <linux/of_pci.h>
     18#include <linux/pci.h>
     19#include <linux/platform_device.h>
     20#include <linux/pm_runtime.h>
     21#include <linux/sizes.h>
     22#include <linux/slab.h>
     23
     24#include "../pci.h"
     25
     26/* AHB-PCI Bridge PCI communication registers */
     27#define RCAR_AHBPCI_PCICOM_OFFSET	0x800
     28
     29#define RCAR_PCIAHB_WIN1_CTR_REG	(RCAR_AHBPCI_PCICOM_OFFSET + 0x00)
     30#define RCAR_PCIAHB_WIN2_CTR_REG	(RCAR_AHBPCI_PCICOM_OFFSET + 0x04)
     31#define RCAR_PCIAHB_PREFETCH0		0x0
     32#define RCAR_PCIAHB_PREFETCH4		0x1
     33#define RCAR_PCIAHB_PREFETCH8		0x2
     34#define RCAR_PCIAHB_PREFETCH16		0x3
     35
     36#define RCAR_AHBPCI_WIN1_CTR_REG	(RCAR_AHBPCI_PCICOM_OFFSET + 0x10)
     37#define RCAR_AHBPCI_WIN2_CTR_REG	(RCAR_AHBPCI_PCICOM_OFFSET + 0x14)
     38#define RCAR_AHBPCI_WIN_CTR_MEM		(3 << 1)
     39#define RCAR_AHBPCI_WIN_CTR_CFG		(5 << 1)
     40#define RCAR_AHBPCI_WIN1_HOST		(1 << 30)
     41#define RCAR_AHBPCI_WIN1_DEVICE		(1 << 31)
     42
     43#define RCAR_PCI_INT_ENABLE_REG		(RCAR_AHBPCI_PCICOM_OFFSET + 0x20)
     44#define RCAR_PCI_INT_STATUS_REG		(RCAR_AHBPCI_PCICOM_OFFSET + 0x24)
     45#define RCAR_PCI_INT_SIGTABORT		(1 << 0)
     46#define RCAR_PCI_INT_SIGRETABORT	(1 << 1)
     47#define RCAR_PCI_INT_REMABORT		(1 << 2)
     48#define RCAR_PCI_INT_PERR		(1 << 3)
     49#define RCAR_PCI_INT_SIGSERR		(1 << 4)
     50#define RCAR_PCI_INT_RESERR		(1 << 5)
     51#define RCAR_PCI_INT_WIN1ERR		(1 << 12)
     52#define RCAR_PCI_INT_WIN2ERR		(1 << 13)
     53#define RCAR_PCI_INT_A			(1 << 16)
     54#define RCAR_PCI_INT_B			(1 << 17)
     55#define RCAR_PCI_INT_PME		(1 << 19)
     56#define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT		| \
     57				RCAR_PCI_INT_SIGRETABORT	| \
     58				RCAR_PCI_INT_REMABORT		| \
     59				RCAR_PCI_INT_PERR		| \
     60				RCAR_PCI_INT_SIGSERR		| \
     61				RCAR_PCI_INT_RESERR		| \
     62				RCAR_PCI_INT_WIN1ERR		| \
     63				RCAR_PCI_INT_WIN2ERR)
     64
     65#define RCAR_AHB_BUS_CTR_REG		(RCAR_AHBPCI_PCICOM_OFFSET + 0x30)
     66#define RCAR_AHB_BUS_MMODE_HTRANS	(1 << 0)
     67#define RCAR_AHB_BUS_MMODE_BYTE_BURST	(1 << 1)
     68#define RCAR_AHB_BUS_MMODE_WR_INCR	(1 << 2)
     69#define RCAR_AHB_BUS_MMODE_HBUS_REQ	(1 << 7)
     70#define RCAR_AHB_BUS_SMODE_READYCTR	(1 << 17)
     71#define RCAR_AHB_BUS_MODE		(RCAR_AHB_BUS_MMODE_HTRANS |	\
     72					RCAR_AHB_BUS_MMODE_BYTE_BURST |	\
     73					RCAR_AHB_BUS_MMODE_WR_INCR |	\
     74					RCAR_AHB_BUS_MMODE_HBUS_REQ |	\
     75					RCAR_AHB_BUS_SMODE_READYCTR)
     76
     77#define RCAR_USBCTR_REG			(RCAR_AHBPCI_PCICOM_OFFSET + 0x34)
     78#define RCAR_USBCTR_USBH_RST		(1 << 0)
     79#define RCAR_USBCTR_PCICLK_MASK		(1 << 1)
     80#define RCAR_USBCTR_PLL_RST		(1 << 2)
     81#define RCAR_USBCTR_DIRPD		(1 << 8)
     82#define RCAR_USBCTR_PCIAHB_WIN2_EN	(1 << 9)
     83#define RCAR_USBCTR_PCIAHB_WIN1_256M	(0 << 10)
     84#define RCAR_USBCTR_PCIAHB_WIN1_512M	(1 << 10)
     85#define RCAR_USBCTR_PCIAHB_WIN1_1G	(2 << 10)
     86#define RCAR_USBCTR_PCIAHB_WIN1_2G	(3 << 10)
     87#define RCAR_USBCTR_PCIAHB_WIN1_MASK	(3 << 10)
     88
     89#define RCAR_PCI_ARBITER_CTR_REG	(RCAR_AHBPCI_PCICOM_OFFSET + 0x40)
     90#define RCAR_PCI_ARBITER_PCIREQ0	(1 << 0)
     91#define RCAR_PCI_ARBITER_PCIREQ1	(1 << 1)
     92#define RCAR_PCI_ARBITER_PCIBP_MODE	(1 << 12)
     93
     94#define RCAR_PCI_UNIT_REV_REG		(RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
     95
     96struct rcar_pci {
     97	struct device *dev;
     98	void __iomem *reg;
     99	struct resource mem_res;
    100	struct resource *cfg_res;
    101	int irq;
    102};
    103
    104/* PCI configuration space operations */
    105static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn,
    106				       int where)
    107{
    108	struct rcar_pci *priv = bus->sysdata;
    109	int slot, val;
    110
    111	if (!pci_is_root_bus(bus) || PCI_FUNC(devfn))
    112		return NULL;
    113
    114	/* Only one EHCI/OHCI device built-in */
    115	slot = PCI_SLOT(devfn);
    116	if (slot > 2)
    117		return NULL;
    118
    119	/* bridge logic only has registers to 0x40 */
    120	if (slot == 0x0 && where >= 0x40)
    121		return NULL;
    122
    123	val = slot ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
    124		     RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
    125
    126	iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
    127	return priv->reg + (slot >> 1) * 0x100 + where;
    128}
    129
    130#ifdef CONFIG_PCI_DEBUG
    131/* if debug enabled, then attach an error handler irq to the bridge */
    132
    133static irqreturn_t rcar_pci_err_irq(int irq, void *pw)
    134{
    135	struct rcar_pci *priv = pw;
    136	struct device *dev = priv->dev;
    137	u32 status = ioread32(priv->reg + RCAR_PCI_INT_STATUS_REG);
    138
    139	if (status & RCAR_PCI_INT_ALLERRORS) {
    140		dev_err(dev, "error irq: status %08x\n", status);
    141
    142		/* clear the error(s) */
    143		iowrite32(status & RCAR_PCI_INT_ALLERRORS,
    144			  priv->reg + RCAR_PCI_INT_STATUS_REG);
    145		return IRQ_HANDLED;
    146	}
    147
    148	return IRQ_NONE;
    149}
    150
    151static void rcar_pci_setup_errirq(struct rcar_pci *priv)
    152{
    153	struct device *dev = priv->dev;
    154	int ret;
    155	u32 val;
    156
    157	ret = devm_request_irq(dev, priv->irq, rcar_pci_err_irq,
    158			       IRQF_SHARED, "error irq", priv);
    159	if (ret) {
    160		dev_err(dev, "cannot claim IRQ for error handling\n");
    161		return;
    162	}
    163
    164	val = ioread32(priv->reg + RCAR_PCI_INT_ENABLE_REG);
    165	val |= RCAR_PCI_INT_ALLERRORS;
    166	iowrite32(val, priv->reg + RCAR_PCI_INT_ENABLE_REG);
    167}
    168#else
    169static inline void rcar_pci_setup_errirq(struct rcar_pci *priv) { }
    170#endif
    171
    172/* PCI host controller setup */
    173static void rcar_pci_setup(struct rcar_pci *priv)
    174{
    175	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(priv);
    176	struct device *dev = priv->dev;
    177	void __iomem *reg = priv->reg;
    178	struct resource_entry *entry;
    179	unsigned long window_size;
    180	unsigned long window_addr;
    181	unsigned long window_pci;
    182	u32 val;
    183
    184	entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM);
    185	if (!entry) {
    186		window_addr = 0x40000000;
    187		window_pci = 0x40000000;
    188		window_size = SZ_1G;
    189	} else {
    190		window_addr = entry->res->start;
    191		window_pci = entry->res->start - entry->offset;
    192		window_size = resource_size(entry->res);
    193	}
    194
    195	pm_runtime_enable(dev);
    196	pm_runtime_get_sync(dev);
    197
    198	val = ioread32(reg + RCAR_PCI_UNIT_REV_REG);
    199	dev_info(dev, "PCI: revision %x\n", val);
    200
    201	/* Disable Direct Power Down State and assert reset */
    202	val = ioread32(reg + RCAR_USBCTR_REG) & ~RCAR_USBCTR_DIRPD;
    203	val |= RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST;
    204	iowrite32(val, reg + RCAR_USBCTR_REG);
    205	udelay(4);
    206
    207	/* De-assert reset and reset PCIAHB window1 size */
    208	val &= ~(RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK |
    209		 RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST);
    210
    211	/* Setup PCIAHB window1 size */
    212	switch (window_size) {
    213	case SZ_2G:
    214		val |= RCAR_USBCTR_PCIAHB_WIN1_2G;
    215		break;
    216	case SZ_1G:
    217		val |= RCAR_USBCTR_PCIAHB_WIN1_1G;
    218		break;
    219	case SZ_512M:
    220		val |= RCAR_USBCTR_PCIAHB_WIN1_512M;
    221		break;
    222	default:
    223		pr_warn("unknown window size %ld - defaulting to 256M\n",
    224			window_size);
    225		window_size = SZ_256M;
    226		fallthrough;
    227	case SZ_256M:
    228		val |= RCAR_USBCTR_PCIAHB_WIN1_256M;
    229		break;
    230	}
    231	iowrite32(val, reg + RCAR_USBCTR_REG);
    232
    233	/* Configure AHB master and slave modes */
    234	iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
    235
    236	/* Configure PCI arbiter */
    237	val = ioread32(reg + RCAR_PCI_ARBITER_CTR_REG);
    238	val |= RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
    239	       RCAR_PCI_ARBITER_PCIBP_MODE;
    240	iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
    241
    242	/* PCI-AHB mapping */
    243	iowrite32(window_addr | RCAR_PCIAHB_PREFETCH16,
    244		  reg + RCAR_PCIAHB_WIN1_CTR_REG);
    245
    246	/* AHB-PCI mapping: OHCI/EHCI registers */
    247	val = priv->mem_res.start | RCAR_AHBPCI_WIN_CTR_MEM;
    248	iowrite32(val, reg + RCAR_AHBPCI_WIN2_CTR_REG);
    249
    250	/* Enable AHB-PCI bridge PCI configuration access */
    251	iowrite32(RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG,
    252		  reg + RCAR_AHBPCI_WIN1_CTR_REG);
    253	/* Set PCI-AHB Window1 address */
    254	iowrite32(window_pci | PCI_BASE_ADDRESS_MEM_PREFETCH,
    255		  reg + PCI_BASE_ADDRESS_1);
    256	/* Set AHB-PCI bridge PCI communication area address */
    257	val = priv->cfg_res->start + RCAR_AHBPCI_PCICOM_OFFSET;
    258	iowrite32(val, reg + PCI_BASE_ADDRESS_0);
    259
    260	val = ioread32(reg + PCI_COMMAND);
    261	val |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
    262	       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
    263	iowrite32(val, reg + PCI_COMMAND);
    264
    265	/* Enable PCI interrupts */
    266	iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
    267		  reg + RCAR_PCI_INT_ENABLE_REG);
    268
    269	rcar_pci_setup_errirq(priv);
    270}
    271
    272static struct pci_ops rcar_pci_ops = {
    273	.map_bus = rcar_pci_cfg_base,
    274	.read	= pci_generic_config_read,
    275	.write	= pci_generic_config_write,
    276};
    277
    278static int rcar_pci_probe(struct platform_device *pdev)
    279{
    280	struct device *dev = &pdev->dev;
    281	struct resource *cfg_res, *mem_res;
    282	struct rcar_pci *priv;
    283	struct pci_host_bridge *bridge;
    284	void __iomem *reg;
    285
    286	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*priv));
    287	if (!bridge)
    288		return -ENOMEM;
    289
    290	priv = pci_host_bridge_priv(bridge);
    291	bridge->sysdata = priv;
    292
    293	cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    294	reg = devm_ioremap_resource(dev, cfg_res);
    295	if (IS_ERR(reg))
    296		return PTR_ERR(reg);
    297
    298	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    299	if (!mem_res || !mem_res->start)
    300		return -ENODEV;
    301
    302	if (mem_res->start & 0xFFFF)
    303		return -EINVAL;
    304
    305	priv->mem_res = *mem_res;
    306	priv->cfg_res = cfg_res;
    307
    308	priv->irq = platform_get_irq(pdev, 0);
    309	priv->reg = reg;
    310	priv->dev = dev;
    311
    312	if (priv->irq < 0) {
    313		dev_err(dev, "no valid irq found\n");
    314		return priv->irq;
    315	}
    316
    317	bridge->ops = &rcar_pci_ops;
    318
    319	pci_add_flags(PCI_REASSIGN_ALL_BUS);
    320
    321	rcar_pci_setup(priv);
    322
    323	return pci_host_probe(bridge);
    324}
    325
    326static const struct of_device_id rcar_pci_of_match[] = {
    327	{ .compatible = "renesas,pci-r8a7790", },
    328	{ .compatible = "renesas,pci-r8a7791", },
    329	{ .compatible = "renesas,pci-r8a7794", },
    330	{ .compatible = "renesas,pci-rcar-gen2", },
    331	{ },
    332};
    333
    334static struct platform_driver rcar_pci_driver = {
    335	.driver = {
    336		.name = "pci-rcar-gen2",
    337		.suppress_bind_attrs = true,
    338		.of_match_table = rcar_pci_of_match,
    339	},
    340	.probe = rcar_pci_probe,
    341};
    342builtin_platform_driver(rcar_pci_driver);