1/* 2 * Atheros AR71XX/AR724X specific PCI setup code 3 * 4 * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> 5 * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> 6 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 7 * 8 * Parts of this file are based on Atheros' 2.6.15 BSP 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License version 2 as published 12 * by the Free Software Foundation. 13 */ 14 15#include <linux/init.h> 16#include <linux/pci.h> 17#include <linux/resource.h> 18#include <linux/platform_device.h> 19#include <asm/mach-ath79/ar71xx_regs.h> 20#include <asm/mach-ath79/ath79.h> 21#include <asm/mach-ath79/irq.h> 22#include "pci.h" 23 24static int (*ath79_pci_plat_dev_init)(struct pci_dev *dev); 25static const struct ath79_pci_irq *ath79_pci_irq_map __initdata; 26static unsigned ath79_pci_nr_irqs __initdata; 27 28static const struct ath79_pci_irq ar71xx_pci_irq_map[] __initconst = { 29 { 30 .slot = 17, 31 .pin = 1, 32 .irq = ATH79_PCI_IRQ(0), 33 }, { 34 .slot = 18, 35 .pin = 1, 36 .irq = ATH79_PCI_IRQ(1), 37 }, { 38 .slot = 19, 39 .pin = 1, 40 .irq = ATH79_PCI_IRQ(2), 41 } 42}; 43 44static const struct ath79_pci_irq ar724x_pci_irq_map[] __initconst = { 45 { 46 .slot = 0, 47 .pin = 1, 48 .irq = ATH79_PCI_IRQ(0), 49 } 50}; 51 52static const struct ath79_pci_irq qca955x_pci_irq_map[] __initconst = { 53 { 54 .bus = 0, 55 .slot = 0, 56 .pin = 1, 57 .irq = ATH79_PCI_IRQ(0), 58 }, 59 { 60 .bus = 1, 61 .slot = 0, 62 .pin = 1, 63 .irq = ATH79_PCI_IRQ(1), 64 }, 65}; 66 67int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) 68{ 69 int irq = -1; 70 int i; 71 72 if (ath79_pci_nr_irqs == 0 || 73 ath79_pci_irq_map == NULL) { 74 if (soc_is_ar71xx()) { 75 ath79_pci_irq_map = ar71xx_pci_irq_map; 76 ath79_pci_nr_irqs = ARRAY_SIZE(ar71xx_pci_irq_map); 77 } else if (soc_is_ar724x() || 78 soc_is_ar9342() || 79 soc_is_ar9344()) { 80 ath79_pci_irq_map = ar724x_pci_irq_map; 81 ath79_pci_nr_irqs = ARRAY_SIZE(ar724x_pci_irq_map); 82 } else if (soc_is_qca955x()) { 83 ath79_pci_irq_map = qca955x_pci_irq_map; 84 ath79_pci_nr_irqs = ARRAY_SIZE(qca955x_pci_irq_map); 85 } else { 86 pr_crit("pci %s: invalid irq map\n", 87 pci_name((struct pci_dev *) dev)); 88 return irq; 89 } 90 } 91 92 for (i = 0; i < ath79_pci_nr_irqs; i++) { 93 const struct ath79_pci_irq *entry; 94 95 entry = &ath79_pci_irq_map[i]; 96 if (entry->bus == dev->bus->number && 97 entry->slot == slot && 98 entry->pin == pin) { 99 irq = entry->irq; 100 break; 101 } 102 } 103 104 if (irq < 0) 105 pr_crit("pci %s: no irq found for pin %u\n", 106 pci_name((struct pci_dev *) dev), pin); 107 else 108 pr_info("pci %s: using irq %d for pin %u\n", 109 pci_name((struct pci_dev *) dev), irq, pin); 110 111 return irq; 112} 113 114int pcibios_plat_dev_init(struct pci_dev *dev) 115{ 116 if (ath79_pci_plat_dev_init) 117 return ath79_pci_plat_dev_init(dev); 118 119 return 0; 120} 121 122void __init ath79_pci_set_irq_map(unsigned nr_irqs, 123 const struct ath79_pci_irq *map) 124{ 125 ath79_pci_nr_irqs = nr_irqs; 126 ath79_pci_irq_map = map; 127} 128 129void __init ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)) 130{ 131 ath79_pci_plat_dev_init = func; 132} 133 134static struct platform_device * 135ath79_register_pci_ar71xx(void) 136{ 137 struct platform_device *pdev; 138 struct resource res[4]; 139 140 memset(res, 0, sizeof(res)); 141 142 res[0].name = "cfg_base"; 143 res[0].flags = IORESOURCE_MEM; 144 res[0].start = AR71XX_PCI_CFG_BASE; 145 res[0].end = AR71XX_PCI_CFG_BASE + AR71XX_PCI_CFG_SIZE - 1; 146 147 res[1].flags = IORESOURCE_IRQ; 148 res[1].start = ATH79_CPU_IRQ(2); 149 res[1].end = ATH79_CPU_IRQ(2); 150 151 res[2].name = "io_base"; 152 res[2].flags = IORESOURCE_IO; 153 res[2].start = 0; 154 res[2].end = 0; 155 156 res[3].name = "mem_base"; 157 res[3].flags = IORESOURCE_MEM; 158 res[3].start = AR71XX_PCI_MEM_BASE; 159 res[3].end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1; 160 161 pdev = platform_device_register_simple("ar71xx-pci", -1, 162 res, ARRAY_SIZE(res)); 163 return pdev; 164} 165 166static struct platform_device * 167ath79_register_pci_ar724x(int id, 168 unsigned long cfg_base, 169 unsigned long ctrl_base, 170 unsigned long crp_base, 171 unsigned long mem_base, 172 unsigned long mem_size, 173 unsigned long io_base, 174 int irq) 175{ 176 struct platform_device *pdev; 177 struct resource res[6]; 178 179 memset(res, 0, sizeof(res)); 180 181 res[0].name = "cfg_base"; 182 res[0].flags = IORESOURCE_MEM; 183 res[0].start = cfg_base; 184 res[0].end = cfg_base + AR724X_PCI_CFG_SIZE - 1; 185 186 res[1].name = "ctrl_base"; 187 res[1].flags = IORESOURCE_MEM; 188 res[1].start = ctrl_base; 189 res[1].end = ctrl_base + AR724X_PCI_CTRL_SIZE - 1; 190 191 res[2].flags = IORESOURCE_IRQ; 192 res[2].start = irq; 193 res[2].end = irq; 194 195 res[3].name = "mem_base"; 196 res[3].flags = IORESOURCE_MEM; 197 res[3].start = mem_base; 198 res[3].end = mem_base + mem_size - 1; 199 200 res[4].name = "io_base"; 201 res[4].flags = IORESOURCE_IO; 202 res[4].start = io_base; 203 res[4].end = io_base; 204 205 res[5].name = "crp_base"; 206 res[5].flags = IORESOURCE_MEM; 207 res[5].start = crp_base; 208 res[5].end = crp_base + AR724X_PCI_CRP_SIZE - 1; 209 210 pdev = platform_device_register_simple("ar724x-pci", id, 211 res, ARRAY_SIZE(res)); 212 return pdev; 213} 214 215int __init ath79_register_pci(void) 216{ 217 struct platform_device *pdev = NULL; 218 219 if (soc_is_ar71xx()) { 220 pdev = ath79_register_pci_ar71xx(); 221 } else if (soc_is_ar724x()) { 222 pdev = ath79_register_pci_ar724x(-1, 223 AR724X_PCI_CFG_BASE, 224 AR724X_PCI_CTRL_BASE, 225 AR724X_PCI_CRP_BASE, 226 AR724X_PCI_MEM_BASE, 227 AR724X_PCI_MEM_SIZE, 228 0, 229 ATH79_CPU_IRQ(2)); 230 } else if (soc_is_ar9342() || 231 soc_is_ar9344()) { 232 u32 bootstrap; 233 234 bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); 235 if ((bootstrap & AR934X_BOOTSTRAP_PCIE_RC) == 0) 236 return -ENODEV; 237 238 pdev = ath79_register_pci_ar724x(-1, 239 AR724X_PCI_CFG_BASE, 240 AR724X_PCI_CTRL_BASE, 241 AR724X_PCI_CRP_BASE, 242 AR724X_PCI_MEM_BASE, 243 AR724X_PCI_MEM_SIZE, 244 0, 245 ATH79_IP2_IRQ(0)); 246 } else if (soc_is_qca9558()) { 247 pdev = ath79_register_pci_ar724x(0, 248 QCA955X_PCI_CFG_BASE0, 249 QCA955X_PCI_CTRL_BASE0, 250 QCA955X_PCI_CRP_BASE0, 251 QCA955X_PCI_MEM_BASE0, 252 QCA955X_PCI_MEM_SIZE, 253 0, 254 ATH79_IP2_IRQ(0)); 255 256 pdev = ath79_register_pci_ar724x(1, 257 QCA955X_PCI_CFG_BASE1, 258 QCA955X_PCI_CTRL_BASE1, 259 QCA955X_PCI_CRP_BASE1, 260 QCA955X_PCI_MEM_BASE1, 261 QCA955X_PCI_MEM_SIZE, 262 1, 263 ATH79_IP3_IRQ(2)); 264 } else { 265 /* No PCI support */ 266 return -ENODEV; 267 } 268 269 if (!pdev) 270 pr_err("unable to register PCI controller device\n"); 271 272 return pdev ? 0 : -ENODEV; 273} 274