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

pcie.c (7329B)


      1/*
      2 * arch/arm/plat-orion/pcie.c
      3 *
      4 * Marvell Orion SoC PCIe handling.
      5 *
      6 * This file is licensed under the terms of the GNU General Public
      7 * License version 2.  This program is licensed "as is" without any
      8 * warranty of any kind, whether express or implied.
      9 */
     10
     11#include <linux/kernel.h>
     12#include <linux/pci.h>
     13#include <linux/mbus.h>
     14#include <asm/mach/pci.h>
     15#include <plat/pcie.h>
     16#include <plat/addr-map.h>
     17#include <linux/delay.h>
     18
     19/*
     20 * PCIe unit register offsets.
     21 */
     22#define PCIE_DEV_ID_OFF		0x0000
     23#define PCIE_CMD_OFF		0x0004
     24#define PCIE_DEV_REV_OFF	0x0008
     25#define PCIE_BAR_LO_OFF(n)	(0x0010 + ((n) << 3))
     26#define PCIE_BAR_HI_OFF(n)	(0x0014 + ((n) << 3))
     27#define PCIE_HEADER_LOG_4_OFF	0x0128
     28#define PCIE_BAR_CTRL_OFF(n)	(0x1804 + ((n - 1) * 4))
     29#define PCIE_WIN04_CTRL_OFF(n)	(0x1820 + ((n) << 4))
     30#define PCIE_WIN04_BASE_OFF(n)	(0x1824 + ((n) << 4))
     31#define PCIE_WIN04_REMAP_OFF(n)	(0x182c + ((n) << 4))
     32#define PCIE_WIN5_CTRL_OFF	0x1880
     33#define PCIE_WIN5_BASE_OFF	0x1884
     34#define PCIE_WIN5_REMAP_OFF	0x188c
     35#define PCIE_CONF_ADDR_OFF	0x18f8
     36#define  PCIE_CONF_ADDR_EN		0x80000000
     37#define  PCIE_CONF_REG(r)		((((r) & 0xf00) << 16) | ((r) & 0xfc))
     38#define  PCIE_CONF_BUS(b)		(((b) & 0xff) << 16)
     39#define  PCIE_CONF_DEV(d)		(((d) & 0x1f) << 11)
     40#define  PCIE_CONF_FUNC(f)		(((f) & 0x7) << 8)
     41#define PCIE_CONF_DATA_OFF	0x18fc
     42#define PCIE_MASK_OFF		0x1910
     43#define PCIE_CTRL_OFF		0x1a00
     44#define  PCIE_CTRL_X1_MODE		0x0001
     45#define PCIE_STAT_OFF		0x1a04
     46#define  PCIE_STAT_DEV_OFFS		20
     47#define  PCIE_STAT_DEV_MASK		0x1f
     48#define  PCIE_STAT_BUS_OFFS		8
     49#define  PCIE_STAT_BUS_MASK		0xff
     50#define  PCIE_STAT_LINK_DOWN		1
     51#define PCIE_DEBUG_CTRL         0x1a60
     52#define  PCIE_DEBUG_SOFT_RESET		(1<<20)
     53
     54
     55u32 orion_pcie_dev_id(void __iomem *base)
     56{
     57	return readl(base + PCIE_DEV_ID_OFF) >> 16;
     58}
     59
     60u32 orion_pcie_rev(void __iomem *base)
     61{
     62	return readl(base + PCIE_DEV_REV_OFF) & 0xff;
     63}
     64
     65int orion_pcie_link_up(void __iomem *base)
     66{
     67	return !(readl(base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
     68}
     69
     70int __init orion_pcie_x4_mode(void __iomem *base)
     71{
     72	return !(readl(base + PCIE_CTRL_OFF) & PCIE_CTRL_X1_MODE);
     73}
     74
     75int orion_pcie_get_local_bus_nr(void __iomem *base)
     76{
     77	u32 stat = readl(base + PCIE_STAT_OFF);
     78
     79	return (stat >> PCIE_STAT_BUS_OFFS) & PCIE_STAT_BUS_MASK;
     80}
     81
     82void __init orion_pcie_set_local_bus_nr(void __iomem *base, int nr)
     83{
     84	u32 stat;
     85
     86	stat = readl(base + PCIE_STAT_OFF);
     87	stat &= ~(PCIE_STAT_BUS_MASK << PCIE_STAT_BUS_OFFS);
     88	stat |= nr << PCIE_STAT_BUS_OFFS;
     89	writel(stat, base + PCIE_STAT_OFF);
     90}
     91
     92void __init orion_pcie_reset(void __iomem *base)
     93{
     94	u32 reg;
     95	int i;
     96
     97	/*
     98	 * MV-S104860-U0, Rev. C:
     99	 * PCI Express Unit Soft Reset
    100	 * When set, generates an internal reset in the PCI Express unit.
    101	 * This bit should be cleared after the link is re-established.
    102	 */
    103	reg = readl(base + PCIE_DEBUG_CTRL);
    104	reg |= PCIE_DEBUG_SOFT_RESET;
    105	writel(reg, base + PCIE_DEBUG_CTRL);
    106
    107	for (i = 0; i < 20; i++) {
    108		mdelay(10);
    109
    110		if (orion_pcie_link_up(base))
    111			break;
    112	}
    113
    114	reg &= ~(PCIE_DEBUG_SOFT_RESET);
    115	writel(reg, base + PCIE_DEBUG_CTRL);
    116}
    117
    118/*
    119 * Setup PCIE BARs and Address Decode Wins:
    120 * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
    121 * WIN[0-3] -> DRAM bank[0-3]
    122 */
    123static void __init orion_pcie_setup_wins(void __iomem *base)
    124{
    125	const struct mbus_dram_target_info *dram;
    126	u32 size;
    127	int i;
    128
    129	dram = mv_mbus_dram_info();
    130
    131	/*
    132	 * First, disable and clear BARs and windows.
    133	 */
    134	for (i = 1; i <= 2; i++) {
    135		writel(0, base + PCIE_BAR_CTRL_OFF(i));
    136		writel(0, base + PCIE_BAR_LO_OFF(i));
    137		writel(0, base + PCIE_BAR_HI_OFF(i));
    138	}
    139
    140	for (i = 0; i < 5; i++) {
    141		writel(0, base + PCIE_WIN04_CTRL_OFF(i));
    142		writel(0, base + PCIE_WIN04_BASE_OFF(i));
    143		writel(0, base + PCIE_WIN04_REMAP_OFF(i));
    144	}
    145
    146	writel(0, base + PCIE_WIN5_CTRL_OFF);
    147	writel(0, base + PCIE_WIN5_BASE_OFF);
    148	writel(0, base + PCIE_WIN5_REMAP_OFF);
    149
    150	/*
    151	 * Setup windows for DDR banks.  Count total DDR size on the fly.
    152	 */
    153	size = 0;
    154	for (i = 0; i < dram->num_cs; i++) {
    155		const struct mbus_dram_window *cs = dram->cs + i;
    156
    157		writel(cs->base & 0xffff0000, base + PCIE_WIN04_BASE_OFF(i));
    158		writel(0, base + PCIE_WIN04_REMAP_OFF(i));
    159		writel(((cs->size - 1) & 0xffff0000) |
    160			(cs->mbus_attr << 8) |
    161			(dram->mbus_dram_target_id << 4) | 1,
    162				base + PCIE_WIN04_CTRL_OFF(i));
    163
    164		size += cs->size;
    165	}
    166
    167	/*
    168	 * Round up 'size' to the nearest power of two.
    169	 */
    170	if ((size & (size - 1)) != 0)
    171		size = 1 << fls(size);
    172
    173	/*
    174	 * Setup BAR[1] to all DRAM banks.
    175	 */
    176	writel(dram->cs[0].base, base + PCIE_BAR_LO_OFF(1));
    177	writel(0, base + PCIE_BAR_HI_OFF(1));
    178	writel(((size - 1) & 0xffff0000) | 1, base + PCIE_BAR_CTRL_OFF(1));
    179}
    180
    181void __init orion_pcie_setup(void __iomem *base)
    182{
    183	u16 cmd;
    184	u32 mask;
    185
    186	/*
    187	 * Point PCIe unit MBUS decode windows to DRAM space.
    188	 */
    189	orion_pcie_setup_wins(base);
    190
    191	/*
    192	 * Master + slave enable.
    193	 */
    194	cmd = readw(base + PCIE_CMD_OFF);
    195	cmd |= PCI_COMMAND_IO;
    196	cmd |= PCI_COMMAND_MEMORY;
    197	cmd |= PCI_COMMAND_MASTER;
    198	writew(cmd, base + PCIE_CMD_OFF);
    199
    200	/*
    201	 * Enable interrupt lines A-D.
    202	 */
    203	mask = readl(base + PCIE_MASK_OFF);
    204	mask |= 0x0f000000;
    205	writel(mask, base + PCIE_MASK_OFF);
    206}
    207
    208int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
    209		       u32 devfn, int where, int size, u32 *val)
    210{
    211	writel(PCIE_CONF_BUS(bus->number) |
    212		PCIE_CONF_DEV(PCI_SLOT(devfn)) |
    213		PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
    214		PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
    215			base + PCIE_CONF_ADDR_OFF);
    216
    217	*val = readl(base + PCIE_CONF_DATA_OFF);
    218
    219	if (size == 1)
    220		*val = (*val >> (8 * (where & 3))) & 0xff;
    221	else if (size == 2)
    222		*val = (*val >> (8 * (where & 3))) & 0xffff;
    223
    224	return PCIBIOS_SUCCESSFUL;
    225}
    226
    227int orion_pcie_rd_conf_tlp(void __iomem *base, struct pci_bus *bus,
    228			   u32 devfn, int where, int size, u32 *val)
    229{
    230	writel(PCIE_CONF_BUS(bus->number) |
    231		PCIE_CONF_DEV(PCI_SLOT(devfn)) |
    232		PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
    233		PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
    234			base + PCIE_CONF_ADDR_OFF);
    235
    236	*val = readl(base + PCIE_CONF_DATA_OFF);
    237
    238	if (bus->number != orion_pcie_get_local_bus_nr(base) ||
    239	    PCI_FUNC(devfn) != 0)
    240		*val = readl(base + PCIE_HEADER_LOG_4_OFF);
    241
    242	if (size == 1)
    243		*val = (*val >> (8 * (where & 3))) & 0xff;
    244	else if (size == 2)
    245		*val = (*val >> (8 * (where & 3))) & 0xffff;
    246
    247	return PCIBIOS_SUCCESSFUL;
    248}
    249
    250int orion_pcie_rd_conf_wa(void __iomem *wa_base, struct pci_bus *bus,
    251			  u32 devfn, int where, int size, u32 *val)
    252{
    253	*val = readl(wa_base + (PCIE_CONF_BUS(bus->number) |
    254				PCIE_CONF_DEV(PCI_SLOT(devfn)) |
    255				PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
    256				PCIE_CONF_REG(where)));
    257
    258	if (size == 1)
    259		*val = (*val >> (8 * (where & 3))) & 0xff;
    260	else if (size == 2)
    261		*val = (*val >> (8 * (where & 3))) & 0xffff;
    262
    263	return PCIBIOS_SUCCESSFUL;
    264}
    265
    266int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
    267		       u32 devfn, int where, int size, u32 val)
    268{
    269	int ret = PCIBIOS_SUCCESSFUL;
    270
    271	writel(PCIE_CONF_BUS(bus->number) |
    272		PCIE_CONF_DEV(PCI_SLOT(devfn)) |
    273		PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
    274		PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
    275			base + PCIE_CONF_ADDR_OFF);
    276
    277	if (size == 4) {
    278		writel(val, base + PCIE_CONF_DATA_OFF);
    279	} else if (size == 2) {
    280		writew(val, base + PCIE_CONF_DATA_OFF + (where & 3));
    281	} else if (size == 1) {
    282		writeb(val, base + PCIE_CONF_DATA_OFF + (where & 3));
    283	} else {
    284		ret = PCIBIOS_BAD_REGISTER_NUMBER;
    285	}
    286
    287	return ret;
    288}