Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: ath79: add support for the PCI host controller of the AR71XX SoCs

The Atheros AR71XX SoCs have a built-in PCI Host Controller.
This patch adds a driver for that, and modifies the relevant
files in order to allow to register the PCI controller from
board specific setup.

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/3498/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Gabor Juhos and committed by
Ralf Baechle
f8365ec4 a68ad4d8

+383
+1
arch/mips/ath79/Kconfig
··· 52 52 config SOC_AR71XX 53 53 select USB_ARCH_HAS_EHCI 54 54 select USB_ARCH_HAS_OHCI 55 + select HW_HAS_PCI 55 56 def_bool n 56 57 57 58 config SOC_AR724X
+6
arch/mips/include/asm/mach-ath79/pci.h
··· 11 11 #ifndef __ASM_MACH_ATH79_PCI_H 12 12 #define __ASM_MACH_ATH79_PCI_H 13 13 14 + #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR71XX) 15 + int ar71xx_pcibios_init(void); 16 + #else 17 + static inline int ar71xx_pcibios_init(void) { return 0; } 18 + #endif 19 + 14 20 #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) 15 21 int ar724x_pcibios_init(int irq); 16 22 #else
+1
arch/mips/pci/Makefile
··· 19 19 obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ 20 20 ops-bcm63xx.o 21 21 obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o 22 + obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o 22 23 obj-$(CONFIG_SOC_AR724X) += pci-ar724x.o 23 24 24 25 #
+375
arch/mips/pci/pci-ar71xx.c
··· 1 + /* 2 + * Atheros AR71xx PCI host controller driver 3 + * 4 + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> 5 + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 6 + * 7 + * Parts of this file are based on Atheros' 2.6.15 BSP 8 + * 9 + * This program is free software; you can redistribute it and/or modify it 10 + * under the terms of the GNU General Public License version 2 as published 11 + * by the Free Software Foundation. 12 + */ 13 + 14 + #include <linux/resource.h> 15 + #include <linux/types.h> 16 + #include <linux/delay.h> 17 + #include <linux/bitops.h> 18 + #include <linux/pci.h> 19 + #include <linux/pci_regs.h> 20 + #include <linux/interrupt.h> 21 + 22 + #include <asm/mach-ath79/ar71xx_regs.h> 23 + #include <asm/mach-ath79/ath79.h> 24 + #include <asm/mach-ath79/pci.h> 25 + 26 + #define AR71XX_PCI_MEM_BASE 0x10000000 27 + #define AR71XX_PCI_MEM_SIZE 0x08000000 28 + 29 + #define AR71XX_PCI_WIN0_OFFS 0x10000000 30 + #define AR71XX_PCI_WIN1_OFFS 0x11000000 31 + #define AR71XX_PCI_WIN2_OFFS 0x12000000 32 + #define AR71XX_PCI_WIN3_OFFS 0x13000000 33 + #define AR71XX_PCI_WIN4_OFFS 0x14000000 34 + #define AR71XX_PCI_WIN5_OFFS 0x15000000 35 + #define AR71XX_PCI_WIN6_OFFS 0x16000000 36 + #define AR71XX_PCI_WIN7_OFFS 0x07000000 37 + 38 + #define AR71XX_PCI_CFG_BASE \ 39 + (AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000) 40 + #define AR71XX_PCI_CFG_SIZE 0x100 41 + 42 + #define AR71XX_PCI_REG_CRP_AD_CBE 0x00 43 + #define AR71XX_PCI_REG_CRP_WRDATA 0x04 44 + #define AR71XX_PCI_REG_CRP_RDDATA 0x08 45 + #define AR71XX_PCI_REG_CFG_AD 0x0c 46 + #define AR71XX_PCI_REG_CFG_CBE 0x10 47 + #define AR71XX_PCI_REG_CFG_WRDATA 0x14 48 + #define AR71XX_PCI_REG_CFG_RDDATA 0x18 49 + #define AR71XX_PCI_REG_PCI_ERR 0x1c 50 + #define AR71XX_PCI_REG_PCI_ERR_ADDR 0x20 51 + #define AR71XX_PCI_REG_AHB_ERR 0x24 52 + #define AR71XX_PCI_REG_AHB_ERR_ADDR 0x28 53 + 54 + #define AR71XX_PCI_CRP_CMD_WRITE 0x00010000 55 + #define AR71XX_PCI_CRP_CMD_READ 0x00000000 56 + #define AR71XX_PCI_CFG_CMD_READ 0x0000000a 57 + #define AR71XX_PCI_CFG_CMD_WRITE 0x0000000b 58 + 59 + #define AR71XX_PCI_INT_CORE BIT(4) 60 + #define AR71XX_PCI_INT_DEV2 BIT(2) 61 + #define AR71XX_PCI_INT_DEV1 BIT(1) 62 + #define AR71XX_PCI_INT_DEV0 BIT(0) 63 + 64 + #define AR71XX_PCI_IRQ_COUNT 5 65 + 66 + static DEFINE_SPINLOCK(ar71xx_pci_lock); 67 + static void __iomem *ar71xx_pcicfg_base; 68 + 69 + /* Byte lane enable bits */ 70 + static const u8 ar71xx_pci_ble_table[4][4] = { 71 + {0x0, 0xf, 0xf, 0xf}, 72 + {0xe, 0xd, 0xb, 0x7}, 73 + {0xc, 0xf, 0x3, 0xf}, 74 + {0xf, 0xf, 0xf, 0xf}, 75 + }; 76 + 77 + static const u32 ar71xx_pci_read_mask[8] = { 78 + 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0 79 + }; 80 + 81 + static inline u32 ar71xx_pci_get_ble(int where, int size, int local) 82 + { 83 + u32 t; 84 + 85 + t = ar71xx_pci_ble_table[size & 3][where & 3]; 86 + BUG_ON(t == 0xf); 87 + t <<= (local) ? 20 : 4; 88 + 89 + return t; 90 + } 91 + 92 + static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn, 93 + int where) 94 + { 95 + u32 ret; 96 + 97 + if (!bus->number) { 98 + /* type 0 */ 99 + ret = (1 << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) | 100 + (where & ~3); 101 + } else { 102 + /* type 1 */ 103 + ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11) | 104 + (PCI_FUNC(devfn) << 8) | (where & ~3) | 1; 105 + } 106 + 107 + return ret; 108 + } 109 + 110 + static int ar71xx_pci_check_error(int quiet) 111 + { 112 + void __iomem *base = ar71xx_pcicfg_base; 113 + u32 pci_err; 114 + u32 ahb_err; 115 + 116 + pci_err = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR) & 3; 117 + if (pci_err) { 118 + if (!quiet) { 119 + u32 addr; 120 + 121 + addr = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR_ADDR); 122 + pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", 123 + "PCI", pci_err, addr); 124 + } 125 + 126 + /* clear PCI error status */ 127 + __raw_writel(pci_err, base + AR71XX_PCI_REG_PCI_ERR); 128 + } 129 + 130 + ahb_err = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR) & 1; 131 + if (ahb_err) { 132 + if (!quiet) { 133 + u32 addr; 134 + 135 + addr = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR_ADDR); 136 + pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", 137 + "AHB", ahb_err, addr); 138 + } 139 + 140 + /* clear AHB error status */ 141 + __raw_writel(ahb_err, base + AR71XX_PCI_REG_AHB_ERR); 142 + } 143 + 144 + return !!(ahb_err | pci_err); 145 + } 146 + 147 + static inline void ar71xx_pci_local_write(int where, int size, u32 value) 148 + { 149 + void __iomem *base = ar71xx_pcicfg_base; 150 + u32 ad_cbe; 151 + 152 + value = value << (8 * (where & 3)); 153 + 154 + ad_cbe = AR71XX_PCI_CRP_CMD_WRITE | (where & ~3); 155 + ad_cbe |= ar71xx_pci_get_ble(where, size, 1); 156 + 157 + __raw_writel(ad_cbe, base + AR71XX_PCI_REG_CRP_AD_CBE); 158 + __raw_writel(value, base + AR71XX_PCI_REG_CRP_WRDATA); 159 + } 160 + 161 + static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, 162 + unsigned int devfn, 163 + int where, int size, u32 cmd) 164 + { 165 + void __iomem *base = ar71xx_pcicfg_base; 166 + u32 addr; 167 + 168 + addr = ar71xx_pci_bus_addr(bus, devfn, where); 169 + 170 + __raw_writel(addr, base + AR71XX_PCI_REG_CFG_AD); 171 + __raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0), 172 + base + AR71XX_PCI_REG_CFG_CBE); 173 + 174 + return ar71xx_pci_check_error(1); 175 + } 176 + 177 + static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, 178 + int where, int size, u32 *value) 179 + { 180 + void __iomem *base = ar71xx_pcicfg_base; 181 + unsigned long flags; 182 + u32 data; 183 + int err; 184 + int ret; 185 + 186 + ret = PCIBIOS_SUCCESSFUL; 187 + data = ~0; 188 + 189 + spin_lock_irqsave(&ar71xx_pci_lock, flags); 190 + 191 + err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, 192 + AR71XX_PCI_CFG_CMD_READ); 193 + if (err) 194 + ret = PCIBIOS_DEVICE_NOT_FOUND; 195 + else 196 + data = __raw_readl(base + AR71XX_PCI_REG_CFG_RDDATA); 197 + 198 + spin_unlock_irqrestore(&ar71xx_pci_lock, flags); 199 + 200 + *value = (data >> (8 * (where & 3))) & ar71xx_pci_read_mask[size & 7]; 201 + 202 + return ret; 203 + } 204 + 205 + static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, 206 + int where, int size, u32 value) 207 + { 208 + void __iomem *base = ar71xx_pcicfg_base; 209 + unsigned long flags; 210 + int err; 211 + int ret; 212 + 213 + value = value << (8 * (where & 3)); 214 + ret = PCIBIOS_SUCCESSFUL; 215 + 216 + spin_lock_irqsave(&ar71xx_pci_lock, flags); 217 + 218 + err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, 219 + AR71XX_PCI_CFG_CMD_WRITE); 220 + if (err) 221 + ret = PCIBIOS_DEVICE_NOT_FOUND; 222 + else 223 + __raw_writel(value, base + AR71XX_PCI_REG_CFG_WRDATA); 224 + 225 + spin_unlock_irqrestore(&ar71xx_pci_lock, flags); 226 + 227 + return ret; 228 + } 229 + 230 + static struct pci_ops ar71xx_pci_ops = { 231 + .read = ar71xx_pci_read_config, 232 + .write = ar71xx_pci_write_config, 233 + }; 234 + 235 + static struct resource ar71xx_pci_io_resource = { 236 + .name = "PCI IO space", 237 + .start = 0, 238 + .end = 0, 239 + .flags = IORESOURCE_IO, 240 + }; 241 + 242 + static struct resource ar71xx_pci_mem_resource = { 243 + .name = "PCI memory space", 244 + .start = AR71XX_PCI_MEM_BASE, 245 + .end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1, 246 + .flags = IORESOURCE_MEM 247 + }; 248 + 249 + static struct pci_controller ar71xx_pci_controller = { 250 + .pci_ops = &ar71xx_pci_ops, 251 + .mem_resource = &ar71xx_pci_mem_resource, 252 + .io_resource = &ar71xx_pci_io_resource, 253 + }; 254 + 255 + static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) 256 + { 257 + void __iomem *base = ath79_reset_base; 258 + u32 pending; 259 + 260 + pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) & 261 + __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); 262 + 263 + if (pending & AR71XX_PCI_INT_DEV0) 264 + generic_handle_irq(ATH79_PCI_IRQ(0)); 265 + 266 + else if (pending & AR71XX_PCI_INT_DEV1) 267 + generic_handle_irq(ATH79_PCI_IRQ(1)); 268 + 269 + else if (pending & AR71XX_PCI_INT_DEV2) 270 + generic_handle_irq(ATH79_PCI_IRQ(2)); 271 + 272 + else if (pending & AR71XX_PCI_INT_CORE) 273 + generic_handle_irq(ATH79_PCI_IRQ(4)); 274 + 275 + else 276 + spurious_interrupt(); 277 + } 278 + 279 + static void ar71xx_pci_irq_unmask(struct irq_data *d) 280 + { 281 + unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; 282 + void __iomem *base = ath79_reset_base; 283 + u32 t; 284 + 285 + t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); 286 + __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); 287 + 288 + /* flush write */ 289 + __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); 290 + } 291 + 292 + static void ar71xx_pci_irq_mask(struct irq_data *d) 293 + { 294 + unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; 295 + void __iomem *base = ath79_reset_base; 296 + u32 t; 297 + 298 + t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); 299 + __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); 300 + 301 + /* flush write */ 302 + __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); 303 + } 304 + 305 + static struct irq_chip ar71xx_pci_irq_chip = { 306 + .name = "AR71XX PCI", 307 + .irq_mask = ar71xx_pci_irq_mask, 308 + .irq_unmask = ar71xx_pci_irq_unmask, 309 + .irq_mask_ack = ar71xx_pci_irq_mask, 310 + }; 311 + 312 + static __init void ar71xx_pci_irq_init(void) 313 + { 314 + void __iomem *base = ath79_reset_base; 315 + int i; 316 + 317 + __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE); 318 + __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS); 319 + 320 + BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT); 321 + 322 + for (i = ATH79_PCI_IRQ_BASE; 323 + i < ATH79_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) 324 + irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, 325 + handle_level_irq); 326 + 327 + irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar71xx_pci_irq_handler); 328 + } 329 + 330 + static __init void ar71xx_pci_reset(void) 331 + { 332 + void __iomem *ddr_base = ath79_ddr_base; 333 + 334 + ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); 335 + mdelay(100); 336 + 337 + ath79_device_reset_clear(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); 338 + mdelay(100); 339 + 340 + __raw_writel(AR71XX_PCI_WIN0_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN0); 341 + __raw_writel(AR71XX_PCI_WIN1_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN1); 342 + __raw_writel(AR71XX_PCI_WIN2_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN2); 343 + __raw_writel(AR71XX_PCI_WIN3_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN3); 344 + __raw_writel(AR71XX_PCI_WIN4_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN4); 345 + __raw_writel(AR71XX_PCI_WIN5_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN5); 346 + __raw_writel(AR71XX_PCI_WIN6_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN6); 347 + __raw_writel(AR71XX_PCI_WIN7_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN7); 348 + 349 + mdelay(100); 350 + } 351 + 352 + __init int ar71xx_pcibios_init(void) 353 + { 354 + u32 t; 355 + 356 + ar71xx_pcicfg_base = ioremap(AR71XX_PCI_CFG_BASE, AR71XX_PCI_CFG_SIZE); 357 + if (ar71xx_pcicfg_base == NULL) 358 + return -ENOMEM; 359 + 360 + ar71xx_pci_reset(); 361 + 362 + /* setup COMMAND register */ 363 + t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE 364 + | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; 365 + ar71xx_pci_local_write(PCI_COMMAND, 4, t); 366 + 367 + /* clear bus errors */ 368 + ar71xx_pci_check_error(1); 369 + 370 + ar71xx_pci_irq_init(); 371 + 372 + register_pci_controller(&ar71xx_pci_controller); 373 + 374 + return 0; 375 + }