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