Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 1 | /* |
| 2 | * PCI-E support for CNS3xxx |
| 3 | * |
| 4 | * Copyright 2008 Cavium Networks |
| 5 | * Richard Liu <richard.liu@caviumnetworks.com> |
| 6 | * Copyright 2010 MontaVista Software, LLC. |
| 7 | * Anton Vorontsov <avorontsov@mvista.com> |
| 8 | * |
| 9 | * This file is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License, Version 2, as |
| 11 | * published by the Free Software Foundation. |
| 12 | */ |
| 13 | |
| 14 | #include <linux/init.h> |
| 15 | #include <linux/kernel.h> |
| 16 | #include <linux/bug.h> |
| 17 | #include <linux/pci.h> |
| 18 | #include <linux/io.h> |
| 19 | #include <linux/ioport.h> |
| 20 | #include <linux/interrupt.h> |
| 21 | #include <linux/ptrace.h> |
| 22 | #include <asm/mach/map.h> |
Arnd Bergmann | 3f9fb2a | 2013-03-13 13:15:25 +0100 | [diff] [blame] | 23 | #include "cns3xxx.h" |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 24 | #include "core.h" |
| 25 | |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 26 | struct cns3xxx_pcie { |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 27 | void __iomem *host_regs; /* PCI config registers for host bridge */ |
| 28 | void __iomem *cfg0_regs; /* PCI Type 0 config registers */ |
| 29 | void __iomem *cfg1_regs; /* PCI Type 1 config registers */ |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 30 | unsigned int irqs[2]; |
| 31 | struct resource res_io; |
| 32 | struct resource res_mem; |
Lorenzo Pieralisi | c88d54b | 2014-11-21 11:29:25 +0000 | [diff] [blame] | 33 | int port; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 34 | bool linked; |
| 35 | }; |
| 36 | |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 37 | static struct cns3xxx_pcie *sysdata_to_cnspci(void *sysdata) |
| 38 | { |
| 39 | struct pci_sys_data *root = sysdata; |
| 40 | |
Lorenzo Pieralisi | c88d54b | 2014-11-21 11:29:25 +0000 | [diff] [blame] | 41 | return root->private_data; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 42 | } |
| 43 | |
Anton Vorontsov | 7caaf7e | 2011-09-09 23:18:00 +0400 | [diff] [blame] | 44 | static struct cns3xxx_pcie *pdev_to_cnspci(const struct pci_dev *dev) |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 45 | { |
| 46 | return sysdata_to_cnspci(dev->sysdata); |
| 47 | } |
| 48 | |
| 49 | static struct cns3xxx_pcie *pbus_to_cnspci(struct pci_bus *bus) |
| 50 | { |
| 51 | return sysdata_to_cnspci(bus->sysdata); |
| 52 | } |
| 53 | |
Rob Herring | 802b7c0 | 2015-01-09 20:34:40 -0600 | [diff] [blame] | 54 | static void __iomem *cns3xxx_pci_map_bus(struct pci_bus *bus, |
| 55 | unsigned int devfn, int where) |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 56 | { |
| 57 | struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus); |
| 58 | int busno = bus->number; |
| 59 | int slot = PCI_SLOT(devfn); |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 60 | void __iomem *base; |
| 61 | |
| 62 | /* If there is no link, just show the CNS PCI bridge. */ |
Krzysztof Hałasa | defaa4d | 2014-09-16 12:36:32 +0200 | [diff] [blame] | 63 | if (!cnspci->linked && busno > 0) |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 64 | return NULL; |
| 65 | |
| 66 | /* |
| 67 | * The CNS PCI bridge doesn't fit into the PCI hierarchy, though |
| 68 | * we still want to access it. For this to work, we must place |
| 69 | * the first device on the same bus as the CNS PCI bridge. |
| 70 | */ |
Krzysztof Hałasa | defaa4d | 2014-09-16 12:36:32 +0200 | [diff] [blame] | 71 | if (busno == 0) { /* internal PCIe bus, host bridge device */ |
| 72 | if (devfn == 0) /* device# and function# are ignored by hw */ |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 73 | base = cnspci->host_regs; |
Krzysztof Hałasa | defaa4d | 2014-09-16 12:36:32 +0200 | [diff] [blame] | 74 | else |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 75 | return NULL; /* no such device */ |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 76 | |
Krzysztof Hałasa | defaa4d | 2014-09-16 12:36:32 +0200 | [diff] [blame] | 77 | } else if (busno == 1) { /* directly connected PCIe device */ |
| 78 | if (slot == 0) /* device# is ignored by hw */ |
| 79 | base = cnspci->cfg0_regs; |
| 80 | else |
| 81 | return NULL; /* no such device */ |
| 82 | } else /* remote PCI bus */ |
| 83 | base = cnspci->cfg1_regs + ((busno & 0xf) << 20); |
| 84 | |
| 85 | return base + (where & 0xffc) + (devfn << 12); |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn, |
| 89 | int where, int size, u32 *val) |
| 90 | { |
Rob Herring | 802b7c0 | 2015-01-09 20:34:40 -0600 | [diff] [blame] | 91 | int ret; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 92 | u32 mask = (0x1ull << (size * 8)) - 1; |
| 93 | int shift = (where % 4) * 8; |
| 94 | |
Rob Herring | 802b7c0 | 2015-01-09 20:34:40 -0600 | [diff] [blame] | 95 | ret = pci_generic_config_read32(bus, devfn, where, size, val); |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 96 | |
Rob Herring | 802b7c0 | 2015-01-09 20:34:40 -0600 | [diff] [blame] | 97 | if (ret == PCIBIOS_SUCCESSFUL && !bus->number && !devfn && |
| 98 | (where & 0xffc) == PCI_CLASS_REVISION) |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 99 | /* |
| 100 | * RC's class is 0xb, but Linux PCI driver needs 0x604 |
| 101 | * for a PCIe bridge. So we must fixup the class code |
| 102 | * to 0x604 here. |
| 103 | */ |
Rob Herring | 802b7c0 | 2015-01-09 20:34:40 -0600 | [diff] [blame] | 104 | *val = ((((*val << shift) & 0xff) | (0x604 << 16)) >> shift) & mask; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 105 | |
Rob Herring | 802b7c0 | 2015-01-09 20:34:40 -0600 | [diff] [blame] | 106 | return ret; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys) |
| 110 | { |
| 111 | struct cns3xxx_pcie *cnspci = sysdata_to_cnspci(sys); |
| 112 | struct resource *res_io = &cnspci->res_io; |
| 113 | struct resource *res_mem = &cnspci->res_mem; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 114 | |
| 115 | BUG_ON(request_resource(&iomem_resource, res_io) || |
| 116 | request_resource(&iomem_resource, res_mem)); |
| 117 | |
Bjorn Helgaas | 9f786d0 | 2012-02-23 20:19:01 -0700 | [diff] [blame] | 118 | pci_add_resource_offset(&sys->resources, res_io, sys->io_offset); |
| 119 | pci_add_resource_offset(&sys->resources, res_mem, sys->mem_offset); |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 120 | |
| 121 | return 1; |
| 122 | } |
| 123 | |
| 124 | static struct pci_ops cns3xxx_pcie_ops = { |
Rob Herring | 802b7c0 | 2015-01-09 20:34:40 -0600 | [diff] [blame] | 125 | .map_bus = cns3xxx_pci_map_bus, |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 126 | .read = cns3xxx_pci_read_config, |
Rob Herring | 802b7c0 | 2015-01-09 20:34:40 -0600 | [diff] [blame] | 127 | .write = pci_generic_config_write, |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 128 | }; |
| 129 | |
Ralf Baechle | d534194 | 2011-06-10 15:30:21 +0100 | [diff] [blame] | 130 | static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 131 | { |
| 132 | struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev); |
Krzysztof Hałasa | defaa4d | 2014-09-16 12:36:32 +0200 | [diff] [blame] | 133 | int irq = cnspci->irqs[!!dev->bus->number]; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 134 | |
| 135 | pr_info("PCIe map irq: %04d:%02x:%02x.%02x slot %d, pin %d, irq: %d\n", |
| 136 | pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn), |
| 137 | PCI_FUNC(dev->devfn), slot, pin, irq); |
| 138 | |
| 139 | return irq; |
| 140 | } |
| 141 | |
| 142 | static struct cns3xxx_pcie cns3xxx_pcie[] = { |
| 143 | [0] = { |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 144 | .host_regs = (void __iomem *)CNS3XXX_PCIE0_HOST_BASE_VIRT, |
| 145 | .cfg0_regs = (void __iomem *)CNS3XXX_PCIE0_CFG0_BASE_VIRT, |
| 146 | .cfg1_regs = (void __iomem *)CNS3XXX_PCIE0_CFG1_BASE_VIRT, |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 147 | .res_io = { |
| 148 | .name = "PCIe0 I/O space", |
| 149 | .start = CNS3XXX_PCIE0_IO_BASE, |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 150 | .end = CNS3XXX_PCIE0_CFG0_BASE - 1, /* 16 MiB */ |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 151 | .flags = IORESOURCE_IO, |
| 152 | }, |
| 153 | .res_mem = { |
| 154 | .name = "PCIe0 non-prefetchable", |
| 155 | .start = CNS3XXX_PCIE0_MEM_BASE, |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 156 | .end = CNS3XXX_PCIE0_HOST_BASE - 1, /* 176 MiB */ |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 157 | .flags = IORESOURCE_MEM, |
| 158 | }, |
| 159 | .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, }, |
Lorenzo Pieralisi | c88d54b | 2014-11-21 11:29:25 +0000 | [diff] [blame] | 160 | .port = 0, |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 161 | }, |
| 162 | [1] = { |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 163 | .host_regs = (void __iomem *)CNS3XXX_PCIE1_HOST_BASE_VIRT, |
| 164 | .cfg0_regs = (void __iomem *)CNS3XXX_PCIE1_CFG0_BASE_VIRT, |
| 165 | .cfg1_regs = (void __iomem *)CNS3XXX_PCIE1_CFG1_BASE_VIRT, |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 166 | .res_io = { |
| 167 | .name = "PCIe1 I/O space", |
| 168 | .start = CNS3XXX_PCIE1_IO_BASE, |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 169 | .end = CNS3XXX_PCIE1_CFG0_BASE - 1, /* 16 MiB */ |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 170 | .flags = IORESOURCE_IO, |
| 171 | }, |
| 172 | .res_mem = { |
| 173 | .name = "PCIe1 non-prefetchable", |
| 174 | .start = CNS3XXX_PCIE1_MEM_BASE, |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 175 | .end = CNS3XXX_PCIE1_HOST_BASE - 1, /* 176 MiB */ |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 176 | .flags = IORESOURCE_MEM, |
| 177 | }, |
| 178 | .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, }, |
Lorenzo Pieralisi | c88d54b | 2014-11-21 11:29:25 +0000 | [diff] [blame] | 179 | .port = 1, |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 180 | }, |
| 181 | }; |
| 182 | |
| 183 | static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci) |
| 184 | { |
Lorenzo Pieralisi | c88d54b | 2014-11-21 11:29:25 +0000 | [diff] [blame] | 185 | int port = cnspci->port; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 186 | u32 reg; |
| 187 | unsigned long time; |
| 188 | |
| 189 | reg = __raw_readl(MISC_PCIE_CTRL(port)); |
| 190 | /* |
| 191 | * Enable Application Request to 1, it will exit L1 automatically, |
| 192 | * but when chip back, it will use another clock, still can use 0x1. |
| 193 | */ |
| 194 | reg |= 0x3; |
| 195 | __raw_writel(reg, MISC_PCIE_CTRL(port)); |
| 196 | |
| 197 | pr_info("PCIe: Port[%d] Enable PCIe LTSSM\n", port); |
| 198 | pr_info("PCIe: Port[%d] Check data link layer...", port); |
| 199 | |
| 200 | time = jiffies; |
| 201 | while (1) { |
| 202 | reg = __raw_readl(MISC_PCIE_PM_DEBUG(port)); |
| 203 | if (reg & 0x1) { |
| 204 | pr_info("Link up.\n"); |
| 205 | cnspci->linked = 1; |
| 206 | break; |
| 207 | } else if (time_after(jiffies, time + 50)) { |
| 208 | pr_info("Device not found.\n"); |
| 209 | break; |
| 210 | } |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci) |
| 215 | { |
Lorenzo Pieralisi | c88d54b | 2014-11-21 11:29:25 +0000 | [diff] [blame] | 216 | int port = cnspci->port; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 217 | struct pci_sys_data sd = { |
Lorenzo Pieralisi | c88d54b | 2014-11-21 11:29:25 +0000 | [diff] [blame] | 218 | .private_data = cnspci, |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 219 | }; |
| 220 | struct pci_bus bus = { |
| 221 | .number = 0, |
| 222 | .ops = &cns3xxx_pcie_ops, |
| 223 | .sysdata = &sd, |
| 224 | }; |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 225 | u16 mem_base = cnspci->res_mem.start >> 16; |
| 226 | u16 mem_limit = cnspci->res_mem.end >> 16; |
| 227 | u16 io_base = cnspci->res_io.start >> 16; |
| 228 | u16 io_limit = cnspci->res_io.end >> 16; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 229 | u32 devfn = 0; |
| 230 | u8 tmp8; |
| 231 | u16 pos; |
| 232 | u16 dc; |
| 233 | |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 234 | pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0); |
| 235 | pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1); |
| 236 | pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1); |
| 237 | |
| 238 | pci_bus_read_config_byte(&bus, devfn, PCI_PRIMARY_BUS, &tmp8); |
| 239 | pci_bus_read_config_byte(&bus, devfn, PCI_SECONDARY_BUS, &tmp8); |
| 240 | pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8); |
| 241 | |
| 242 | pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base); |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 243 | pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, mem_limit); |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 244 | pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base); |
Krzysztof Hałasa | 64cf9d0 | 2014-03-04 08:37:10 +0100 | [diff] [blame] | 245 | pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, io_limit); |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 246 | |
| 247 | if (!cnspci->linked) |
| 248 | return; |
| 249 | |
| 250 | /* Set Device Max_Read_Request_Size to 128 byte */ |
Krzysztof Hałasa | defaa4d | 2014-09-16 12:36:32 +0200 | [diff] [blame] | 251 | bus.number = 1; /* directly connected PCIe device */ |
| 252 | devfn = PCI_DEVFN(0, 0); |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 253 | pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP); |
| 254 | pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc); |
Krzysztof Hałasa | 367dc4b | 2014-09-16 12:37:16 +0200 | [diff] [blame] | 255 | if (dc & PCI_EXP_DEVCTL_READRQ) { |
| 256 | dc &= ~PCI_EXP_DEVCTL_READRQ; |
| 257 | pci_bus_write_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, dc); |
| 258 | pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc); |
| 259 | if (dc & PCI_EXP_DEVCTL_READRQ) |
| 260 | pr_warn("PCIe: Unable to set device Max_Read_Request_Size\n"); |
| 261 | else |
| 262 | pr_info("PCIe: Max_Read_Request_Size set to 128 bytes\n"); |
| 263 | } |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 264 | /* Disable PCIe0 Interrupt Mask INTA to INTD */ |
| 265 | __raw_writel(~0x3FFF, MISC_PCIE_INT_MASK(port)); |
| 266 | } |
| 267 | |
| 268 | static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr, |
| 269 | struct pt_regs *regs) |
| 270 | { |
| 271 | if (fsr & (1 << 10)) |
| 272 | regs->ARM_pc += 4; |
| 273 | return 0; |
| 274 | } |
| 275 | |
Xia Kaixu | 0a2e912 | 2014-09-03 21:18:12 +0800 | [diff] [blame] | 276 | void __init cns3xxx_pcie_init_late(void) |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 277 | { |
| 278 | int i; |
Lorenzo Pieralisi | c88d54b | 2014-11-21 11:29:25 +0000 | [diff] [blame] | 279 | void *private_data; |
| 280 | struct hw_pci hw_pci = { |
| 281 | .nr_controllers = 1, |
| 282 | .ops = &cns3xxx_pcie_ops, |
| 283 | .setup = cns3xxx_pci_setup, |
| 284 | .map_irq = cns3xxx_pcie_map_irq, |
| 285 | .private_data = &private_data, |
| 286 | }; |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 287 | |
Rob Herring | c9d95fb | 2011-06-28 21:16:13 -0500 | [diff] [blame] | 288 | pcibios_min_io = 0; |
| 289 | pcibios_min_mem = 0; |
| 290 | |
Anton Vorontsov | 4426641 | 2010-11-29 18:46:22 +0300 | [diff] [blame] | 291 | hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0, |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 292 | "imprecise external abort"); |
| 293 | |
| 294 | for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) { |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 295 | cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i)); |
| 296 | cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i)); |
| 297 | cns3xxx_pcie_check_link(&cns3xxx_pcie[i]); |
| 298 | cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]); |
Lorenzo Pieralisi | c88d54b | 2014-11-21 11:29:25 +0000 | [diff] [blame] | 299 | private_data = &cns3xxx_pcie[i]; |
| 300 | pci_common_init(&hw_pci); |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 301 | } |
| 302 | |
| 303 | pci_assign_unassigned_resources(); |
Anton Vorontsov | 5f32f7a | 2010-05-28 13:10:52 +0400 | [diff] [blame] | 304 | } |