aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/pci/pci-xlp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/pci/pci-xlp.c')
-rw-r--r--arch/mips/pci/pci-xlp.c124
1 files changed, 80 insertions, 44 deletions
diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c
index ad55f2cfeec1..653d2db9e0c5 100644
--- a/arch/mips/pci/pci-xlp.c
+++ b/arch/mips/pci/pci-xlp.c
@@ -46,6 +46,7 @@
46 46
47#include <asm/netlogic/interrupt.h> 47#include <asm/netlogic/interrupt.h>
48#include <asm/netlogic/haldefs.h> 48#include <asm/netlogic/haldefs.h>
49#include <asm/netlogic/common.h>
49 50
50#include <asm/netlogic/xlp-hal/iomap.h> 51#include <asm/netlogic/xlp-hal/iomap.h>
51#include <asm/netlogic/xlp-hal/pic.h> 52#include <asm/netlogic/xlp-hal/pic.h>
@@ -64,8 +65,12 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
64 u32 data; 65 u32 data;
65 u32 *cfgaddr; 66 u32 *cfgaddr;
66 67
68 where &= ~3;
69 if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954)
70 return 0xffffffff;
71
67 cfgaddr = (u32 *)(pci_config_base + 72 cfgaddr = (u32 *)(pci_config_base +
68 pci_cfg_addr(bus->number, devfn, where & ~3)); 73 pci_cfg_addr(bus->number, devfn, where));
69 data = *cfgaddr; 74 data = *cfgaddr;
70 return data; 75 return data;
71} 76}
@@ -157,32 +162,38 @@ struct pci_controller nlm_pci_controller = {
157 .io_offset = 0x00000000UL, 162 .io_offset = 0x00000000UL,
158}; 163};
159 164
160static int get_irq_vector(const struct pci_dev *dev) 165static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)
161{ 166{
162 /* 167 struct pci_bus *bus, *p;
163 * For XLP PCIe, there is an IRQ per Link, find out which
164 * link the device is on to assign interrupts
165 */
166 if (dev->bus->self == NULL)
167 return 0;
168 168
169 switch (dev->bus->self->devfn) { 169 /* Find the bridge on bus 0 */
170 case 0x8: 170 bus = dev->bus;
171 return PIC_PCIE_LINK_0_IRQ; 171 for (p = bus->parent; p && p->number != 0; p = p->parent)
172 case 0x9: 172 bus = p;
173 return PIC_PCIE_LINK_1_IRQ; 173
174 case 0xa: 174 return p ? bus->self : NULL;
175 return PIC_PCIE_LINK_2_IRQ; 175}
176 case 0xb: 176
177 return PIC_PCIE_LINK_3_IRQ; 177static inline int nlm_pci_link_to_irq(int link)
178 } 178{
179 WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn); 179 return PIC_PCIE_LINK_0_IRQ + link;
180 return 0;
181} 180}
182 181
183int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) 182int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
184{ 183{
185 return get_irq_vector(dev); 184 struct pci_dev *lnkdev;
185 int lnkslot, lnkfunc;
186
187 /*
188 * For XLP PCIe, there is an IRQ per Link, find out which
189 * link the device is on to assign interrupts
190 */
191 lnkdev = xlp_get_pcie_link(dev);
192 if (lnkdev == NULL)
193 return 0;
194 lnkfunc = PCI_FUNC(lnkdev->devfn);
195 lnkslot = PCI_SLOT(lnkdev->devfn);
196 return nlm_irq_to_xirq(lnkslot / 8, nlm_pci_link_to_irq(lnkfunc));
186} 197}
187 198
188/* Do platform specific device initialization at pci_enable_device() time */ 199/* Do platform specific device initialization at pci_enable_device() time */
@@ -191,42 +202,48 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
191 return 0; 202 return 0;
192} 203}
193 204
194static int xlp_enable_pci_bswap(void) 205/*
206 * If big-endian, enable hardware byteswap on the PCIe bridges.
207 * This will make both the SoC and PCIe devices behave consistently with
208 * readl/writel.
209 */
210#ifdef __BIG_ENDIAN
211static void xlp_config_pci_bswap(int node, int link)
195{ 212{
196 uint64_t pciebase, sysbase; 213 uint64_t nbubase, lnkbase;
197 int node, i;
198 u32 reg; 214 u32 reg;
199 215
200 /* Chip-0 so node set to 0 */ 216 nbubase = nlm_get_bridge_regbase(node);
201 node = 0; 217 lnkbase = nlm_get_pcie_base(node, link);
202 sysbase = nlm_get_bridge_regbase(node); 218
203 /* 219 /*
204 * Enable byte swap in hardware. Program each link's PCIe SWAP regions 220 * Enable byte swap in hardware. Program each link's PCIe SWAP regions
205 * from the link's address ranges. 221 * from the link's address ranges.
206 */ 222 */
207 for (i = 0; i < 4; i++) { 223 reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link);
208 pciebase = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, i)); 224 nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg);
209 if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff)
210 continue;
211 225
212 reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_BASE0 + i); 226 reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link);
213 nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_BASE, reg); 227 nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff);
214 228
215 reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_LIMIT0 + i); 229 reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link);
216 nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_LIM, 230 nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg);
217 reg | 0xfff);
218 231
219 reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_BASE0 + i); 232 reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link);
220 nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_BASE, reg); 233 nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
221
222 reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_LIMIT0 + i);
223 nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
224 }
225 return 0;
226} 234}
235#else
236/* Swap configuration not needed in little-endian mode */
237static inline void xlp_config_pci_bswap(int node, int link) {}
238#endif /* __BIG_ENDIAN */
227 239
228static int __init pcibios_init(void) 240static int __init pcibios_init(void)
229{ 241{
242 struct nlm_soc_info *nodep;
243 uint64_t pciebase;
244 int link, n;
245 u32 reg;
246
230 /* Firmware assigns PCI resources */ 247 /* Firmware assigns PCI resources */
231 pci_set_flags(PCI_PROBE_ONLY); 248 pci_set_flags(PCI_PROBE_ONLY);
232 pci_config_base = ioremap(XLP_DEFAULT_PCI_ECFG_BASE, 64 << 20); 249 pci_config_base = ioremap(XLP_DEFAULT_PCI_ECFG_BASE, 64 << 20);
@@ -235,7 +252,26 @@ static int __init pcibios_init(void)
235 ioport_resource.start = 0; 252 ioport_resource.start = 0;
236 ioport_resource.end = ~0; 253 ioport_resource.end = ~0;
237 254
238 xlp_enable_pci_bswap(); 255 for (n = 0; n < NLM_NR_NODES; n++) {
256 nodep = nlm_get_node(n);
257 if (!nodep->coremask)
258 continue; /* node does not exist */
259
260 for (link = 0; link < 4; link++) {
261 pciebase = nlm_get_pcie_base(n, link);
262 if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff)
263 continue;
264 xlp_config_pci_bswap(n, link);
265
266 /* put in intpin and irq - u-boot does not */
267 reg = nlm_read_pci_reg(pciebase, 0xf);
268 reg &= ~0x1fu;
269 reg |= (1 << 8) | nlm_pci_link_to_irq(link);
270 nlm_write_pci_reg(pciebase, 0xf, reg);
271 pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link);
272 }
273 }
274
239 set_io_port_base(CKSEG1); 275 set_io_port_base(CKSEG1);
240 nlm_pci_controller.io_map_base = CKSEG1; 276 nlm_pci_controller.io_map_base = CKSEG1;
241 277