| 1 | #include <linux/kernel.h> |
|---|
| 2 | #include <linux/init.h> |
|---|
| 3 | #include <linux/types.h> |
|---|
| 4 | #include <linux/irq.h> |
|---|
| 5 | #include <linux/interrupt.h> |
|---|
| 6 | #include <linux/pci.h> |
|---|
| 7 | #include <linux/cpumask.h> |
|---|
| 8 | #include <linux/delay.h> |
|---|
| 9 | #include <linux/ath9k_platform.h> |
|---|
| 10 | |
|---|
| 11 | #include <asm/delay.h> |
|---|
| 12 | |
|---|
| 13 | #define ag7100_delay1s() mdelay(1000); |
|---|
| 14 | |
|---|
| 15 | #include "ar7100.h" |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | static int ar71xx_pci_fixup_enable; |
|---|
| 19 | |
|---|
| 20 | /* |
|---|
| 21 | * Support for Ar7100 pci interrupt and core pci initialization |
|---|
| 22 | */ |
|---|
| 23 | /* |
|---|
| 24 | * PCI interrupts. |
|---|
| 25 | * roughly the interrupts flow is: |
|---|
| 26 | * |
|---|
| 27 | * - save flags |
|---|
| 28 | * - CLI (disable all) |
|---|
| 29 | * - IC->ack (mask out the source) |
|---|
| 30 | * - EI (enable all, except the source that was masked of course) |
|---|
| 31 | * - action (ISR) |
|---|
| 32 | * - IC->enable (unmask the source) |
|---|
| 33 | * |
|---|
| 34 | * The reason we have a separate PCI IC is beacause of the following: |
|---|
| 35 | * If we dont, then Throughout the "action" of a PCI slot, the |
|---|
| 36 | * entire PCI "IP" on the cpu will remain disabled. Which means that we cant |
|---|
| 37 | * prioritize between PCI interrupts. Normally this should be ok, if all PCI |
|---|
| 38 | * interrupts are considered equal. However, creating a PCI IC gives |
|---|
| 39 | * the flexibility to prioritize. |
|---|
| 40 | */ |
|---|
| 41 | |
|---|
| 42 | static void |
|---|
| 43 | ar7100_pci_irq_enable(unsigned int irq) |
|---|
| 44 | { |
|---|
| 45 | ar7100_reg_rmw_set(AR7100_PCI_INT_MASK, |
|---|
| 46 | (1 << (irq - AR7100_PCI_IRQ_BASE))); |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | static void |
|---|
| 50 | ar7100_pci_irq_disable(unsigned int irq) |
|---|
| 51 | { |
|---|
| 52 | ar7100_reg_rmw_clear(AR7100_PCI_INT_MASK, |
|---|
| 53 | (1 << (irq - AR7100_PCI_IRQ_BASE))); |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | static unsigned int |
|---|
| 57 | ar7100_pci_irq_startup(unsigned int irq) |
|---|
| 58 | { |
|---|
| 59 | ar7100_pci_irq_enable(irq); |
|---|
| 60 | return 0; |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | static void |
|---|
| 64 | ar7100_pci_irq_shutdown(unsigned int irq) |
|---|
| 65 | { |
|---|
| 66 | ar7100_pci_irq_disable(irq); |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | static void |
|---|
| 70 | ar7100_pci_irq_ack(unsigned int irq) |
|---|
| 71 | { |
|---|
| 72 | ar7100_pci_irq_disable(irq); |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | static void |
|---|
| 76 | ar7100_pci_irq_end(unsigned int irq) |
|---|
| 77 | { |
|---|
| 78 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) |
|---|
| 79 | ar7100_pci_irq_enable(irq); |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | static int |
|---|
| 83 | ar7100_pci_irq_set_affinity(unsigned int irq, const struct cpumask *mask) |
|---|
| 84 | { |
|---|
| 85 | /* |
|---|
| 86 | * Only 1 CPU; ignore affinity request |
|---|
| 87 | */ |
|---|
| 88 | return 0; |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | static struct irq_chip ar7100_pci_irq_chip = { |
|---|
| 92 | .name = "AR7100 PCI ", |
|---|
| 93 | .mask = ar7100_pci_irq_disable, |
|---|
| 94 | .unmask = ar7100_pci_irq_enable, |
|---|
| 95 | .mask_ack = ar7100_pci_irq_disable, |
|---|
| 96 | }; |
|---|
| 97 | |
|---|
| 98 | |
|---|
| 99 | void |
|---|
| 100 | ar7100_pci_irq_init(int irq_base) |
|---|
| 101 | { |
|---|
| 102 | int i; |
|---|
| 103 | |
|---|
| 104 | for (i = irq_base; i < irq_base + AR7100_PCI_IRQ_COUNT; i++) { |
|---|
| 105 | irq_desc[i].status = IRQ_DISABLED; |
|---|
| 106 | set_irq_chip_and_handler(i, &ar7100_pci_irq_chip, |
|---|
| 107 | handle_level_irq); |
|---|
| 108 | } |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | /* |
|---|
| 112 | * init the pci controller |
|---|
| 113 | */ |
|---|
| 114 | |
|---|
| 115 | static struct resource ar7100_io_resource = { |
|---|
| 116 | .name = "PCI IO space", |
|---|
| 117 | .start = 0x0000, |
|---|
| 118 | .end = 0, |
|---|
| 119 | .flags = IORESOURCE_IO, |
|---|
| 120 | }; |
|---|
| 121 | |
|---|
| 122 | static struct resource ar7100_mem_resource = { |
|---|
| 123 | .name = "PCI memory space", |
|---|
| 124 | .start = AR7100_PCI_MEM_BASE, |
|---|
| 125 | .end = AR7100_PCI_MEM_BASE + AR7100_PCI_WINDOW - 1, |
|---|
| 126 | .flags = IORESOURCE_MEM |
|---|
| 127 | }; |
|---|
| 128 | |
|---|
| 129 | extern struct pci_ops ar7100_pci_ops; |
|---|
| 130 | |
|---|
| 131 | static struct pci_controller ar7100_pci_controller = { |
|---|
| 132 | .pci_ops = &ar7100_pci_ops, |
|---|
| 133 | .mem_resource = &ar7100_mem_resource, |
|---|
| 134 | .io_resource = &ar7100_io_resource, |
|---|
| 135 | }; |
|---|
| 136 | |
|---|
| 137 | |
|---|
| 138 | irqreturn_t |
|---|
| 139 | ar7100_pci_core_intr(int cpl, void *dev_id) |
|---|
| 140 | { |
|---|
| 141 | printk("PCI error intr\n"); |
|---|
| 142 | ar7100_check_error(1); |
|---|
| 143 | |
|---|
| 144 | return IRQ_HANDLED; |
|---|
| 145 | } |
|---|
| 146 | |
|---|
| 147 | /* |
|---|
| 148 | * We want a 1:1 mapping between PCI and DDR for inbound and outbound. |
|---|
| 149 | * The PCI<---AHB decoding works as follows: |
|---|
| 150 | * |
|---|
| 151 | * 8 registers in the DDR unit provide software configurable 32 bit offsets |
|---|
| 152 | * for each of the eight 16MB PCI windows in the 128MB. The offsets will be |
|---|
| 153 | * added to any address in the 16MB segment before being sent to the PCI unit. |
|---|
| 154 | * |
|---|
| 155 | * Essentially for any AHB address generated by the CPU, |
|---|
| 156 | * 1. the MSB four bits are stripped off, [31:28], |
|---|
| 157 | * 2. Bit 27 is used to decide between the lower 128Mb (PCI) or the rest of |
|---|
| 158 | * the AHB space |
|---|
| 159 | * 3. Bits 26:24 are used to access one of the 8 window registers and are |
|---|
| 160 | * masked off. |
|---|
| 161 | * 4. If it is a PCI address, then the WINDOW offset in the WINDOW register |
|---|
| 162 | * corresponding to the next 3 bits (bit 26:24) is ADDED to the address, |
|---|
| 163 | * to generate the address to PCI unit. |
|---|
| 164 | * |
|---|
| 165 | * eg. CPU address = 0x100000ff |
|---|
| 166 | * window 0 offset = 0x10000000 |
|---|
| 167 | * This points to lowermost 16MB window in PCI space. |
|---|
| 168 | * So the resulting address would be 0x000000ff+0x10000000 |
|---|
| 169 | * = 0x100000ff |
|---|
| 170 | * |
|---|
| 171 | * eg2. CPU address = 0x120000ff |
|---|
| 172 | * WINDOW 2 offset = 0x12000000 |
|---|
| 173 | * resulting address would be 0x000000ff+0x12000000 |
|---|
| 174 | * = 0x120000ff |
|---|
| 175 | * |
|---|
| 176 | * There is no translation for inbound access (PCI device as a master) |
|---|
| 177 | */ |
|---|
| 178 | static void ar71xx_pci_fixup(struct pci_dev *dev) |
|---|
| 179 | { |
|---|
| 180 | u32 t; |
|---|
| 181 | |
|---|
| 182 | if (!ar71xx_pci_fixup_enable) |
|---|
| 183 | return; |
|---|
| 184 | |
|---|
| 185 | |
|---|
| 186 | if (dev->bus->number != 0 || dev->devfn != 0) |
|---|
| 187 | return; |
|---|
| 188 | |
|---|
| 189 | |
|---|
| 190 | /* setup COMMAND register */ |
|---|
| 191 | t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE |
|---|
| 192 | | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; |
|---|
| 193 | |
|---|
| 194 | pci_write_config_word(dev, PCI_COMMAND, t); |
|---|
| 195 | } |
|---|
| 196 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ar71xx_pci_fixup); |
|---|
| 197 | |
|---|
| 198 | static void *getCalData(int slot) |
|---|
| 199 | { |
|---|
| 200 | u8 *base; |
|---|
| 201 | for (base=(u8 *) KSEG1ADDR(0x1f000000);base<KSEG1ADDR (0x1fff0000);base+=0x1000) { |
|---|
| 202 | u32 *cal = (u32 *)base; |
|---|
| 203 | if (*cal==0xa55a0000 || *cal==0x5aa50000) { //protection bit is always zero on inflash devices, so we can use for match it |
|---|
| 204 | if (slot) { |
|---|
| 205 | base+=0x4000; |
|---|
| 206 | } |
|---|
| 207 | printk(KERN_INFO "found calibration data for slot %d on 0x%08X\n",slot,base); |
|---|
| 208 | return base; |
|---|
| 209 | } |
|---|
| 210 | } |
|---|
| 211 | return NULL; |
|---|
| 212 | } |
|---|
| 213 | static struct ath9k_platform_data wmac_data[2]; |
|---|
| 214 | |
|---|
| 215 | static void ath_pci_fixup(struct pci_dev *dev) |
|---|
| 216 | { |
|---|
| 217 | void __iomem *mem; |
|---|
| 218 | u16 *cal_data = NULL; |
|---|
| 219 | u16 cmd; |
|---|
| 220 | u32 bar0; |
|---|
| 221 | u32 val; |
|---|
| 222 | |
|---|
| 223 | if (!ar71xx_pci_fixup_enable) |
|---|
| 224 | return; |
|---|
| 225 | |
|---|
| 226 | switch (PCI_SLOT(dev->devfn)) { |
|---|
| 227 | case 0: |
|---|
| 228 | cal_data = (u16 *)getCalData(0); |
|---|
| 229 | if (cal_data) { |
|---|
| 230 | memcpy(wmac_data[0].eeprom_data,cal_data,sizeof(wmac_data[0].eeprom_data)); |
|---|
| 231 | dev->dev.platform_data = &wmac_data[0]; |
|---|
| 232 | } |
|---|
| 233 | break; |
|---|
| 234 | case 1: |
|---|
| 235 | cal_data = (u16 *)getCalData(1); |
|---|
| 236 | if (cal_data) { |
|---|
| 237 | memcpy(wmac_data[1].eeprom_data,cal_data,sizeof(wmac_data[1].eeprom_data)); |
|---|
| 238 | dev->dev.platform_data = &wmac_data[1]; |
|---|
| 239 | } |
|---|
| 240 | break; |
|---|
| 241 | default: |
|---|
| 242 | return; |
|---|
| 243 | } |
|---|
| 244 | if (!cal_data) { |
|---|
| 245 | printk(KERN_INFO "no in flash calibration fata found, no fix required\n"); |
|---|
| 246 | return; |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000); |
|---|
| 250 | if (!mem) { |
|---|
| 251 | printk(KERN_ERR "PCI: ioremap error for device %s\n", |
|---|
| 252 | pci_name(dev)); |
|---|
| 253 | return; |
|---|
| 254 | } |
|---|
| 255 | |
|---|
| 256 | printk(KERN_INFO "PCI: fixup device %s\n", pci_name(dev)); |
|---|
| 257 | |
|---|
| 258 | pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0); |
|---|
| 259 | |
|---|
| 260 | /* Setup the PCI device to allow access to the internal registers */ |
|---|
| 261 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, AR71XX_PCI_MEM_BASE); |
|---|
| 262 | pci_read_config_word(dev, PCI_COMMAND, &cmd); |
|---|
| 263 | cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; |
|---|
| 264 | pci_write_config_word(dev, PCI_COMMAND, cmd); |
|---|
| 265 | |
|---|
| 266 | /* set pointer to first reg address */ |
|---|
| 267 | cal_data += 3; |
|---|
| 268 | while (*cal_data != 0xffff) { |
|---|
| 269 | u32 reg; |
|---|
| 270 | reg = *cal_data++; |
|---|
| 271 | val = *cal_data++; |
|---|
| 272 | val |= (*cal_data++) << 16; |
|---|
| 273 | |
|---|
| 274 | __raw_writel(val, mem + reg); |
|---|
| 275 | udelay(100); |
|---|
| 276 | } |
|---|
| 277 | |
|---|
| 278 | pci_read_config_dword(dev, PCI_VENDOR_ID, &val); |
|---|
| 279 | dev->vendor = val & 0xffff; |
|---|
| 280 | dev->device = (val >> 16) & 0xffff; |
|---|
| 281 | |
|---|
| 282 | pci_read_config_dword(dev, PCI_CLASS_REVISION, &val); |
|---|
| 283 | dev->revision = val & 0xff; |
|---|
| 284 | dev->class = val >> 8; /* upper 3 bytes */ |
|---|
| 285 | |
|---|
| 286 | pci_read_config_word(dev, PCI_COMMAND, &cmd); |
|---|
| 287 | cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); |
|---|
| 288 | pci_write_config_word(dev, PCI_COMMAND, cmd); |
|---|
| 289 | |
|---|
| 290 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0); |
|---|
| 291 | |
|---|
| 292 | iounmap(mem); |
|---|
| 293 | return; |
|---|
| 294 | } |
|---|
| 295 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ath_pci_fixup); |
|---|
| 296 | |
|---|
| 297 | static int __init ar7100_pcibios_init(void) |
|---|
| 298 | { |
|---|
| 299 | uint32_t cmd; |
|---|
| 300 | |
|---|
| 301 | ar7100_reg_rmw_set(AR7100_RESET, |
|---|
| 302 | (AR7100_RESET_PCI_BUS|AR7100_RESET_PCI_CORE)); |
|---|
| 303 | ag7100_delay1s(); |
|---|
| 304 | |
|---|
| 305 | ar7100_reg_rmw_clear(AR7100_RESET, |
|---|
| 306 | (AR7100_RESET_PCI_BUS|AR7100_RESET_PCI_CORE)); |
|---|
| 307 | ag7100_delay1s(); |
|---|
| 308 | |
|---|
| 309 | ar7100_write_pci_window(0); |
|---|
| 310 | ar7100_write_pci_window(1); |
|---|
| 311 | ar7100_write_pci_window(2); |
|---|
| 312 | ar7100_write_pci_window(3); |
|---|
| 313 | ar7100_write_pci_window(4); |
|---|
| 314 | ar7100_write_pci_window(5); |
|---|
| 315 | ar7100_write_pci_window(6); |
|---|
| 316 | ar7100_write_pci_window(7); |
|---|
| 317 | |
|---|
| 318 | ag7100_delay1s(); |
|---|
| 319 | |
|---|
| 320 | |
|---|
| 321 | cmd = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | |
|---|
| 322 | PCI_COMMAND_PARITY|PCI_COMMAND_SERR|PCI_COMMAND_FAST_BACK; |
|---|
| 323 | |
|---|
| 324 | ar7100_local_write_config(PCI_COMMAND, 4, cmd); |
|---|
| 325 | |
|---|
| 326 | /* |
|---|
| 327 | * clear any lingering errors and register core error IRQ |
|---|
| 328 | */ |
|---|
| 329 | ar7100_check_error(0); |
|---|
| 330 | |
|---|
| 331 | ar71xx_pci_fixup_enable = 1; |
|---|
| 332 | register_pci_controller(&ar7100_pci_controller); |
|---|
| 333 | request_irq(AR7100_PCI_IRQ_CORE, ar7100_pci_core_intr, IRQ_DISABLED,"ar7100 pci core", NULL); |
|---|
| 334 | |
|---|
| 335 | return 0; |
|---|
| 336 | } |
|---|
| 337 | |
|---|
| 338 | arch_initcall(ar7100_pcibios_init); |
|---|