aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb/driver_pcicore.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2007-09-18 15:12:50 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:51:36 -0400
commit61e115a56d1aafd6e6a8a9fee8ac099a6128ac7b (patch)
treeadd97bf6a1207a4caea3a86cf13495ad3dc477de /drivers/ssb/driver_pcicore.c
parent5ee3afba88f5a79d0bff07ddd87af45919259f91 (diff)
[SSB]: add Sonics Silicon Backplane bus support
SSB is an SoC bus used in a number of embedded devices. The most well-known of these devices is probably the Linksys WRT54G, but there are others as well. The bus is also used internally on the BCM43xx and BCM44xx devices from Broadcom. This patch also includes support for SSB ID tables in modules, so that SSB drivers can be loaded automatically. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/ssb/driver_pcicore.c')
-rw-r--r--drivers/ssb/driver_pcicore.c576
1 files changed, 576 insertions, 0 deletions
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
new file mode 100644
index 00000000000..2faaa906d5d
--- /dev/null
+++ b/drivers/ssb/driver_pcicore.c
@@ -0,0 +1,576 @@
1/*
2 * Sonics Silicon Backplane
3 * Broadcom PCI-core driver
4 *
5 * Copyright 2005, Broadcom Corporation
6 * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
7 *
8 * Licensed under the GNU/GPL. See COPYING for details.
9 */
10
11#include <linux/ssb/ssb.h>
12#include <linux/pci.h>
13#include <linux/delay.h>
14
15#include "ssb_private.h"
16
17
18static inline
19u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
20{
21 return ssb_read32(pc->dev, offset);
22}
23
24static inline
25void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value)
26{
27 ssb_write32(pc->dev, offset, value);
28}
29
30/**************************************************
31 * Code for hostmode operation.
32 **************************************************/
33
34#ifdef CONFIG_SSB_PCICORE_HOSTMODE
35
36#include <asm/paccess.h>
37/* Probe a 32bit value on the bus and catch bus exceptions.
38 * Returns nonzero on a bus exception.
39 * This is MIPS specific */
40#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
41
42/* Assume one-hot slot wiring */
43#define SSB_PCI_SLOT_MAX 16
44
45/* Global lock is OK, as we won't have more than one extpci anyway. */
46static DEFINE_SPINLOCK(cfgspace_lock);
47/* Core to access the external PCI config space. Can only have one. */
48static struct ssb_pcicore *extpci_core;
49
50static u32 ssb_pcicore_pcibus_iobase = 0x100;
51static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
52
53int pcibios_plat_dev_init(struct pci_dev *d)
54{
55 struct resource *res;
56 int pos, size;
57 u32 *base;
58
59 ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
60 pci_name(d));
61
62 /* Fix up resource bases */
63 for (pos = 0; pos < 6; pos++) {
64 res = &d->resource[pos];
65 if (res->flags & IORESOURCE_IO)
66 base = &ssb_pcicore_pcibus_iobase;
67 else
68 base = &ssb_pcicore_pcibus_membase;
69 if (res->end) {
70 size = res->end - res->start + 1;
71 if (*base & (size - 1))
72 *base = (*base + size) & ~(size - 1);
73 res->start = *base;
74 res->end = res->start + size - 1;
75 *base += size;
76 pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
77 }
78 /* Fix up PCI bridge BAR0 only */
79 if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
80 break;
81 }
82 /* Fix up interrupt lines */
83 d->irq = ssb_mips_irq(extpci_core->dev) + 2;
84 pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
85
86 return 0;
87}
88
89static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
90{
91 if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
92 return;
93
94 ssb_printk(KERN_INFO "PCI: fixing up bridge\n");
95
96 /* Enable PCI bridge bus mastering and memory space */
97 pci_set_master(dev);
98 pcibios_enable_device(dev, ~0);
99
100 /* Enable PCI bridge BAR1 prefetch and burst */
101 pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
102
103 /* Make sure our latency is high enough to handle the devices behind us */
104 pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
105}
106DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
107
108int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
109{
110 return ssb_mips_irq(extpci_core->dev) + 2;
111}
112
113static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
114 unsigned int bus, unsigned int dev,
115 unsigned int func, unsigned int off)
116{
117 u32 addr = 0;
118 u32 tmp;
119
120 if (unlikely(pc->cardbusmode && dev > 1))
121 goto out;
122 if (bus == 0) {
123 /* Type 0 transaction */
124 if (unlikely(dev >= SSB_PCI_SLOT_MAX))
125 goto out;
126 /* Slide the window */
127 tmp = SSB_PCICORE_SBTOPCI_CFG0;
128 tmp |= ((1 << (dev + 16)) & SSB_PCICORE_SBTOPCI1_MASK);
129 pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, tmp);
130 /* Calculate the address */
131 addr = SSB_PCI_CFG;
132 addr |= ((1 << (dev + 16)) & ~SSB_PCICORE_SBTOPCI1_MASK);
133 addr |= (func << 8);
134 addr |= (off & ~3);
135 } else {
136 /* Type 1 transaction */
137 pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
138 SSB_PCICORE_SBTOPCI_CFG1);
139 /* Calculate the address */
140 addr = SSB_PCI_CFG;
141 addr |= (bus << 16);
142 addr |= (dev << 11);
143 addr |= (func << 8);
144 addr |= (off & ~3);
145 }
146out:
147 return addr;
148}
149
150static int ssb_extpci_read_config(struct ssb_pcicore *pc,
151 unsigned int bus, unsigned int dev,
152 unsigned int func, unsigned int off,
153 void *buf, int len)
154{
155 int err = -EINVAL;
156 u32 addr, val;
157 void __iomem *mmio;
158
159 SSB_WARN_ON(!pc->hostmode);
160 if (unlikely(len != 1 && len != 2 && len != 4))
161 goto out;
162 addr = get_cfgspace_addr(pc, bus, dev, func, off);
163 if (unlikely(!addr))
164 goto out;
165 err = -ENOMEM;
166 mmio = ioremap_nocache(addr, len);
167 if (!mmio)
168 goto out;
169
170 if (mips_busprobe32(val, mmio)) {
171 val = 0xffffffff;
172 goto unmap;
173 }
174
175 val = readl(mmio);
176 val >>= (8 * (off & 3));
177
178 switch (len) {
179 case 1:
180 *((u8 *)buf) = (u8)val;
181 break;
182 case 2:
183 *((u16 *)buf) = (u16)val;
184 break;
185 case 4:
186 *((u32 *)buf) = (u32)val;
187 break;
188 }
189 err = 0;
190unmap:
191 iounmap(mmio);
192out:
193 return err;
194}
195
196static int ssb_extpci_write_config(struct ssb_pcicore *pc,
197 unsigned int bus, unsigned int dev,
198 unsigned int func, unsigned int off,
199 const void *buf, int len)
200{
201 int err = -EINVAL;
202 u32 addr, val = 0;
203 void __iomem *mmio;
204
205 SSB_WARN_ON(!pc->hostmode);
206 if (unlikely(len != 1 && len != 2 && len != 4))
207 goto out;
208 addr = get_cfgspace_addr(pc, bus, dev, func, off);
209 if (unlikely(!addr))
210 goto out;
211 err = -ENOMEM;
212 mmio = ioremap_nocache(addr, len);
213 if (!mmio)
214 goto out;
215
216 if (mips_busprobe32(val, mmio)) {
217 val = 0xffffffff;
218 goto unmap;
219 }
220
221 switch (len) {
222 case 1:
223 val = readl(mmio);
224 val &= ~(0xFF << (8 * (off & 3)));
225 val |= *((const u8 *)buf) << (8 * (off & 3));
226 break;
227 case 2:
228 val = readl(mmio);
229 val &= ~(0xFFFF << (8 * (off & 3)));
230 val |= *((const u16 *)buf) << (8 * (off & 3));
231 break;
232 case 4:
233 val = *((const u32 *)buf);
234 break;
235 }
236 writel(val, mmio);
237
238 err = 0;
239unmap:
240 iounmap(mmio);
241out:
242 return err;
243}
244
245static int ssb_pcicore_read_config(struct pci_bus *bus, unsigned int devfn,
246 int reg, int size, u32 *val)
247{
248 unsigned long flags;
249 int err;
250
251 spin_lock_irqsave(&cfgspace_lock, flags);
252 err = ssb_extpci_read_config(extpci_core, bus->number, PCI_SLOT(devfn),
253 PCI_FUNC(devfn), reg, val, size);
254 spin_unlock_irqrestore(&cfgspace_lock, flags);
255
256 return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
257}
258
259static int ssb_pcicore_write_config(struct pci_bus *bus, unsigned int devfn,
260 int reg, int size, u32 val)
261{
262 unsigned long flags;
263 int err;
264
265 spin_lock_irqsave(&cfgspace_lock, flags);
266 err = ssb_extpci_write_config(extpci_core, bus->number, PCI_SLOT(devfn),
267 PCI_FUNC(devfn), reg, &val, size);
268 spin_unlock_irqrestore(&cfgspace_lock, flags);
269
270 return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
271}
272
273static struct pci_ops ssb_pcicore_pciops = {
274 .read = ssb_pcicore_read_config,
275 .write = ssb_pcicore_write_config,
276};
277
278static struct resource ssb_pcicore_mem_resource = {
279 .name = "SSB PCIcore external memory",
280 .start = SSB_PCI_DMA,
281 .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1,
282 .flags = IORESOURCE_MEM,
283};
284
285static struct resource ssb_pcicore_io_resource = {
286 .name = "SSB PCIcore external I/O",
287 .start = 0x100,
288 .end = 0x7FF,
289 .flags = IORESOURCE_IO,
290};
291
292static struct pci_controller ssb_pcicore_controller = {
293 .pci_ops = &ssb_pcicore_pciops,
294 .io_resource = &ssb_pcicore_io_resource,
295 .mem_resource = &ssb_pcicore_mem_resource,
296 .mem_offset = 0x24000000,
297};
298
299static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
300{
301 u32 val;
302
303 if (WARN_ON(extpci_core))
304 return;
305 extpci_core = pc;
306
307 ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n");
308 /* Reset devices on the external PCI bus */
309 val = SSB_PCICORE_CTL_RST_OE;
310 val |= SSB_PCICORE_CTL_CLK_OE;
311 pcicore_write32(pc, SSB_PCICORE_CTL, val);
312 val |= SSB_PCICORE_CTL_CLK; /* Clock on */
313 pcicore_write32(pc, SSB_PCICORE_CTL, val);
314 udelay(150); /* Assertion time demanded by the PCI standard */
315 val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */
316 pcicore_write32(pc, SSB_PCICORE_CTL, val);
317 val = SSB_PCICORE_ARBCTL_INTERN;
318 pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
319 udelay(1); /* Assertion time demanded by the PCI standard */
320
321 /*TODO cardbus mode */
322
323 /* 64MB I/O window */
324 pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
325 SSB_PCICORE_SBTOPCI_IO);
326 /* 64MB config space */
327 pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
328 SSB_PCICORE_SBTOPCI_CFG0);
329 /* 1GB memory window */
330 pcicore_write32(pc, SSB_PCICORE_SBTOPCI2,
331 SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA);
332
333 /* Enable PCI bridge BAR0 prefetch and burst */
334 val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
335 ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2);
336 /* Clear error conditions */
337 val = 0;
338 ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2);
339
340 /* Enable PCI interrupts */
341 pcicore_write32(pc, SSB_PCICORE_IMASK,
342 SSB_PCICORE_IMASK_INTA);
343
344 /* Ok, ready to run, register it to the system.
345 * The following needs change, if we want to port hostmode
346 * to non-MIPS platform. */
347 set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
348 /* Give some time to the PCI controller to configure itself with the new
349 * values. Not waiting at this point causes crashes of the machine. */
350 mdelay(10);
351 register_pci_controller(&ssb_pcicore_controller);
352}
353
354static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
355{
356 struct ssb_bus *bus = pc->dev->bus;
357 u16 chipid_top;
358 u32 tmp;
359
360 chipid_top = (bus->chip_id & 0xFF00);
361 if (chipid_top != 0x4700 &&
362 chipid_top != 0x5300)
363 return 0;
364
365 if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
366 return 0;
367
368 /* The 200-pin BCM4712 package does not bond out PCI. Even when
369 * PCI is bonded out, some boards may leave the pins floating. */
370 if (bus->chip_id == 0x4712) {
371 if (bus->chip_package == SSB_CHIPPACK_BCM4712S)
372 return 0;
373 if (bus->chip_package == SSB_CHIPPACK_BCM4712M)
374 return 0;
375 }
376 if (bus->chip_id == 0x5350)
377 return 0;
378
379 return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE)));
380}
381#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
382
383
384/**************************************************
385 * Generic and Clientmode operation code.
386 **************************************************/
387
388static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
389{
390 /* Disable PCI interrupts. */
391 ssb_write32(pc->dev, SSB_INTVEC, 0);
392}
393
394void ssb_pcicore_init(struct ssb_pcicore *pc)
395{
396 struct ssb_device *dev = pc->dev;
397 struct ssb_bus *bus;
398
399 if (!dev)
400 return;
401 bus = dev->bus;
402 if (!ssb_device_is_enabled(dev))
403 ssb_device_enable(dev, 0);
404
405#ifdef CONFIG_SSB_PCICORE_HOSTMODE
406 pc->hostmode = pcicore_is_in_hostmode(pc);
407 if (pc->hostmode)
408 ssb_pcicore_init_hostmode(pc);
409#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
410 if (!pc->hostmode)
411 ssb_pcicore_init_clientmode(pc);
412}
413
414static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
415{
416 pcicore_write32(pc, 0x130, address);
417 return pcicore_read32(pc, 0x134);
418}
419
420static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data)
421{
422 pcicore_write32(pc, 0x130, address);
423 pcicore_write32(pc, 0x134, data);
424}
425
426static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
427 u8 address, u16 data)
428{
429 const u16 mdio_control = 0x128;
430 const u16 mdio_data = 0x12C;
431 u32 v;
432 int i;
433
434 v = 0x80; /* Enable Preamble Sequence */
435 v |= 0x2; /* MDIO Clock Divisor */
436 pcicore_write32(pc, mdio_control, v);
437
438 v = (1 << 30); /* Start of Transaction */
439 v |= (1 << 28); /* Write Transaction */
440 v |= (1 << 17); /* Turnaround */
441 v |= (u32)device << 22;
442 v |= (u32)address << 18;
443 v |= data;
444 pcicore_write32(pc, mdio_data, v);
445 /* Wait for the device to complete the transaction */
446 udelay(10);
447 for (i = 0; i < 10; i++) {
448 v = pcicore_read32(pc, mdio_control);
449 if (v & 0x100 /* Trans complete */)
450 break;
451 msleep(1);
452 }
453 pcicore_write32(pc, mdio_control, 0);
454}
455
456static void ssb_broadcast_value(struct ssb_device *dev,
457 u32 address, u32 data)
458{
459 /* This is used for both, PCI and ChipCommon core, so be careful. */
460 BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
461 BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
462
463 ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
464 ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
465 ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
466 ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
467}
468
469static void ssb_commit_settings(struct ssb_bus *bus)
470{
471 struct ssb_device *dev;
472
473 dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
474 if (WARN_ON(!dev))
475 return;
476 /* This forces an update of the cached registers. */
477 ssb_broadcast_value(dev, 0xFD8, 0);
478}
479
480int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
481 struct ssb_device *dev)
482{
483 struct ssb_device *pdev = pc->dev;
484 struct ssb_bus *bus;
485 int err = 0;
486 u32 tmp;
487
488 might_sleep();
489
490 if (!pdev)
491 goto out;
492 bus = pdev->bus;
493
494 /* Enable interrupts for this device. */
495 if (bus->host_pci &&
496 ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) {
497 u32 coremask;
498
499 /* Calculate the "coremask" for the device. */
500 coremask = (1 << dev->core_index);
501
502 err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
503 if (err)
504 goto out;
505 tmp |= coremask << 8;
506 err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp);
507 if (err)
508 goto out;
509 } else {
510 u32 intvec;
511
512 intvec = ssb_read32(pdev, SSB_INTVEC);
513 if ((bus->chip_id & 0xFF00) == 0x4400) {
514 /* Workaround: On the BCM44XX the BPFLAG routing
515 * bit is wrong. Use a hardcoded constant. */
516 intvec |= 0x00000002;
517 } else {
518 tmp = ssb_read32(dev, SSB_TPSFLAG);
519 tmp &= SSB_TPSFLAG_BPFLAG;
520 intvec |= tmp;
521 }
522 ssb_write32(pdev, SSB_INTVEC, intvec);
523 }
524
525 /* Setup PCIcore operation. */
526 if (pc->setup_done)
527 goto out;
528 if (pdev->id.coreid == SSB_DEV_PCI) {
529 tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
530 tmp |= SSB_PCICORE_SBTOPCI_PREF;
531 tmp |= SSB_PCICORE_SBTOPCI_BURST;
532 pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
533
534 if (pdev->id.revision < 5) {
535 tmp = ssb_read32(pdev, SSB_IMCFGLO);
536 tmp &= ~SSB_IMCFGLO_SERTO;
537 tmp |= 2;
538 tmp &= ~SSB_IMCFGLO_REQTO;
539 tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
540 ssb_write32(pdev, SSB_IMCFGLO, tmp);
541 ssb_commit_settings(bus);
542 } else if (pdev->id.revision >= 11) {
543 tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
544 tmp |= SSB_PCICORE_SBTOPCI_MRM;
545 pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
546 }
547 } else {
548 WARN_ON(pdev->id.coreid != SSB_DEV_PCIE);
549 //TODO: Better make defines for all these magic PCIE values.
550 if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) {
551 /* TLP Workaround register. */
552 tmp = ssb_pcie_read(pc, 0x4);
553 tmp |= 0x8;
554 ssb_pcie_write(pc, 0x4, tmp);
555 }
556 if (pdev->id.revision == 0) {
557 const u8 serdes_rx_device = 0x1F;
558
559 ssb_pcie_mdio_write(pc, serdes_rx_device,
560 2 /* Timer */, 0x8128);
561 ssb_pcie_mdio_write(pc, serdes_rx_device,
562 6 /* CDR */, 0x0100);
563 ssb_pcie_mdio_write(pc, serdes_rx_device,
564 7 /* CDR BW */, 0x1466);
565 } else if (pdev->id.revision == 1) {
566 /* DLLP Link Control register. */
567 tmp = ssb_pcie_read(pc, 0x100);
568 tmp |= 0x40;
569 ssb_pcie_write(pc, 0x100, tmp);
570 }
571 }
572 pc->setup_done = 1;
573out:
574 return err;
575}
576EXPORT_SYMBOL(ssb_pcicore_dev_irqvecs_enable);