summaryrefslogtreecommitdiff
path: root/target/linux/brcm47xx-2.6/patches
diff options
context:
space:
mode:
authornoz <noz@3c298f89-4303-0410-b956-a3cf2f4a3e73>2007-06-21 20:10:50 +0000
committernoz <noz@3c298f89-4303-0410-b956-a3cf2f4a3e73>2007-06-21 20:10:50 +0000
commit6546ee2d5f04d335314782ca0577901b7c2d83b0 (patch)
treeb8c2124cfa4e97458937733d65bfac60ff625457 /target/linux/brcm47xx-2.6/patches
parentebd093f2fa1855b10efdc70772e1024dd37b1a4a (diff)
brcm43xx: update SSB driver
* files/ now contains the wireless-dev tree version * patches/210-ssb_merge is nbd's subsequent changes git-svn-id: svn://svn.openwrt.org/openwrt/trunk@7691 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/brcm47xx-2.6/patches')
-rw-r--r--target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch256
-rw-r--r--target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch78
-rw-r--r--target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch421
3 files changed, 755 insertions, 0 deletions
diff --git a/target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch b/target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch
new file mode 100644
index 0000000000..816d7e18b6
--- /dev/null
+++ b/target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch
@@ -0,0 +1,256 @@
+Index: linux-2.6.22-rc4/drivers/net/b44.c
+===================================================================
+--- linux-2.6.22-rc4.orig/drivers/net/b44.c 2007-06-10 21:33:15.000000000 +0100
++++ linux-2.6.22-rc4/drivers/net/b44.c 2007-06-10 21:33:23.000000000 +0100
+@@ -128,7 +128,7 @@
+ unsigned long offset,
+ enum dma_data_direction dir)
+ {
+- dma_sync_single_range_for_device(&sdev->dev, dma_base,
++ dma_sync_single_range_for_device(sdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
+ }
+@@ -138,7 +138,7 @@
+ unsigned long offset,
+ enum dma_data_direction dir)
+ {
+- dma_sync_single_range_for_cpu(&sdev->dev, dma_base,
++ dma_sync_single_range_for_cpu(sdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
+ }
+@@ -563,7 +563,7 @@
+
+ BUG_ON(skb == NULL);
+
+- dma_unmap_single(&bp->sdev->dev,
++ dma_unmap_single(bp->sdev->dev,
+ pci_unmap_addr(rp, mapping),
+ skb->len,
+ DMA_TO_DEVICE);
+@@ -603,7 +603,7 @@
+ if (skb == NULL)
+ return -ENOMEM;
+
+- mapping = dma_map_single(&bp->sdev->dev, skb->data,
++ mapping = dma_map_single(bp->sdev->dev, skb->data,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+
+@@ -613,18 +613,18 @@
+ mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
+ /* Sigh... */
+ if (!dma_mapping_error(mapping))
+- dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
++ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
+ skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA);
+ if (skb == NULL)
+ return -ENOMEM;
+- mapping = dma_map_single(&bp->sdev->dev, skb->data,
++ mapping = dma_map_single(bp->sdev->dev, skb->data,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(mapping) ||
+ mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
+ if (!dma_mapping_error(mapping))
+- dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
++ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
+ return -ENOMEM;
+ }
+@@ -702,7 +702,7 @@
+ dest_idx * sizeof(dest_desc),
+ DMA_BIDIRECTIONAL);
+
+- dma_sync_single_for_device(&bp->sdev->dev, le32_to_cpu(src_desc->addr),
++ dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr),
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+ }
+@@ -724,7 +724,7 @@
+ struct rx_header *rh;
+ u16 len;
+
+- dma_sync_single_for_cpu(&bp->sdev->dev, map,
++ dma_sync_single_for_cpu(bp->sdev->dev, map,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+ rh = (struct rx_header *) skb->data;
+@@ -758,7 +758,7 @@
+ skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
+ if (skb_size < 0)
+ goto drop_it;
+- dma_unmap_single(&bp->sdev->dev, map,
++ dma_unmap_single(bp->sdev->dev, map,
+ skb_size, DMA_FROM_DEVICE);
+ /* Leave out rx_header */
+ skb_put(skb, len+bp->rx_offset);
+@@ -931,22 +931,22 @@
+ goto err_out;
+ }
+
+- mapping = dma_map_single(&bp->sdev->dev, skb->data, len, DMA_TO_DEVICE);
++ mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE);
+ if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
+ /* Chip can't handle DMA to/from >1GB, use bounce buffer */
+ if (!dma_mapping_error(mapping))
+- dma_unmap_single(&bp->sdev->dev, mapping, len, DMA_TO_DEVICE);
++ dma_unmap_single(bp->sdev->dev, mapping, len, DMA_TO_DEVICE);
+
+ bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ,
+ GFP_ATOMIC|GFP_DMA);
+ if (!bounce_skb)
+ goto err_out;
+
+- mapping = dma_map_single(&bp->sdev->dev, bounce_skb->data,
++ mapping = dma_map_single(bp->sdev->dev, bounce_skb->data,
+ len, DMA_TO_DEVICE);
+ if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
+ if (!dma_mapping_error(mapping))
+- dma_unmap_single(&bp->sdev->dev, mapping,
++ dma_unmap_single(bp->sdev->dev, mapping,
+ len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(bounce_skb);
+ goto err_out;
+@@ -1046,7 +1046,7 @@
+
+ if (rp->skb == NULL)
+ continue;
+- dma_unmap_single(&bp->sdev->dev,
++ dma_unmap_single(bp->sdev->dev,
+ pci_unmap_addr(rp, mapping),
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+@@ -1060,7 +1060,7 @@
+
+ if (rp->skb == NULL)
+ continue;
+- dma_unmap_single(&bp->sdev->dev,
++ dma_unmap_single(bp->sdev->dev,
+ pci_unmap_addr(rp, mapping),
+ rp->skb->len,
+ DMA_TO_DEVICE);
+@@ -1085,12 +1085,12 @@
+ memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
+
+ if (bp->flags & B44_FLAG_RX_RING_HACK)
+- dma_sync_single_for_device(&bp->sdev->dev, bp->rx_ring_dma,
++ dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
+
+ if (bp->flags & B44_FLAG_TX_RING_HACK)
+- dma_sync_single_for_device(&bp->sdev->dev, bp->tx_ring_dma,
++ dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
+
+@@ -1112,24 +1112,24 @@
+ bp->tx_buffers = NULL;
+ if (bp->rx_ring) {
+ if (bp->flags & B44_FLAG_RX_RING_HACK) {
+- dma_unmap_single(&bp->sdev->dev, bp->rx_ring_dma,
++ dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
+ kfree(bp->rx_ring);
+ } else
+- dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES,
++ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
+ bp->rx_ring, bp->rx_ring_dma);
+ bp->rx_ring = NULL;
+ bp->flags &= ~B44_FLAG_RX_RING_HACK;
+ }
+ if (bp->tx_ring) {
+ if (bp->flags & B44_FLAG_TX_RING_HACK) {
+- dma_unmap_single(&bp->sdev->dev, bp->tx_ring_dma,
++ dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
+ kfree(bp->tx_ring);
+ } else
+- dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES,
++ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
+ bp->tx_ring, bp->tx_ring_dma);
+ bp->tx_ring = NULL;
+ bp->flags &= ~B44_FLAG_TX_RING_HACK;
+@@ -1155,7 +1155,7 @@
+ goto out_err;
+
+ size = DMA_TABLE_BYTES;
+- bp->rx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC);
++ bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC);
+ if (!bp->rx_ring) {
+ /* Allocation may have failed due to pci_alloc_consistent
+ insisting on use of GFP_DMA, which is more restrictive
+@@ -1167,7 +1167,7 @@
+ if (!rx_ring)
+ goto out_err;
+
+- rx_ring_dma = dma_map_single(&bp->sdev->dev, rx_ring,
++ rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
+
+@@ -1182,7 +1182,7 @@
+ bp->flags |= B44_FLAG_RX_RING_HACK;
+ }
+
+- bp->tx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC);
++ bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC);
+ if (!bp->tx_ring) {
+ /* Allocation may have failed due to dma_alloc_coherent
+ insisting on use of GFP_DMA, which is more restrictive
+@@ -1194,7 +1194,7 @@
+ if (!tx_ring)
+ goto out_err;
+
+- tx_ring_dma = dma_map_single(&bp->sdev->dev, tx_ring,
++ tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
+
+@@ -2314,13 +2314,13 @@
+
+ dev = alloc_etherdev(sizeof(*bp));
+ if (!dev) {
+- dev_err(&sdev->dev, "Etherdev alloc failed, aborting.\n");
++ dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ SET_MODULE_OWNER(dev);
+- SET_NETDEV_DEV(dev,&sdev->dev);
++ SET_NETDEV_DEV(dev,sdev->dev);
+
+ /* No interesting netdevice features in this card... */
+ dev->features |= 0;
+@@ -2358,7 +2358,7 @@
+
+ err = b44_get_invariants(bp);
+ if (err) {
+- dev_err(&sdev->dev,
++ dev_err(sdev->dev,
+ "Problem fetching invariants of chip, aborting.\n");
+ goto err_out_free_dev;
+ }
+@@ -2379,7 +2379,7 @@
+
+ err = register_netdev(dev);
+ if (err) {
+- dev_err(&sdev->dev, "Cannot register net device, aborting.\n");
++ dev_err(sdev->dev, "Cannot register net device, aborting.\n");
+ goto out;
+ }
+
+@@ -2458,7 +2458,6 @@
+ rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
+ if (rc) {
+ printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name);
+- pci_disable_device(pdev);
+ return rc;
+ }
+
diff --git a/target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch b/target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch
new file mode 100644
index 0000000000..67882454d8
--- /dev/null
+++ b/target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch
@@ -0,0 +1,78 @@
+Index: linux-2.6.22-rc4/drivers/usb/host/Kconfig
+===================================================================
+--- linux-2.6.22-rc4.orig/drivers/usb/host/Kconfig 2007-06-10 21:32:11.000000000 +0100
++++ linux-2.6.22-rc4/drivers/usb/host/Kconfig 2007-06-10 21:33:24.000000000 +0100
+@@ -142,6 +142,19 @@
+ Enables support for PCI-bus plug-in USB controller cards.
+ If unsure, say Y.
+
++config USB_OHCI_HCD_SSB
++ bool "OHCI support for the Broadcom SSB OHCI core (embedded systems only)"
++ depends on USB_OHCI_HCD && ((USB_OHCI_HCD=m && SSB) || (USB_OHCI_HCD=y && SSB=y)) && EXPERIMENTAL
++ default n
++ ---help---
++ Support for the Sonics Silicon Backplane (SSB) attached
++ Broadcom USB OHCI core.
++
++ This device is only present in some embedded devices with
++ Broadcom based SSB bus.
++
++ If unsure, say N.
++
+ config USB_OHCI_BIG_ENDIAN_DESC
+ bool
+ depends on USB_OHCI_HCD
+Index: linux-2.6.22-rc4/drivers/usb/host/ohci-hcd.c
+===================================================================
+--- linux-2.6.22-rc4.orig/drivers/usb/host/ohci-hcd.c 2007-06-10 21:32:11.000000000 +0100
++++ linux-2.6.22-rc4/drivers/usb/host/ohci-hcd.c 2007-06-10 21:33:24.000000000 +0100
+@@ -920,11 +920,17 @@
+ #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver
+ #endif
+
++#ifdef CONFIG_USB_OHCI_HCD_SSB
++#include "ohci-ssb.c"
++#define SSB_OHCI_DRIVER ssb_ohci_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && \
+ !defined(PLATFORM_DRIVER) && \
+ !defined(OF_PLATFORM_DRIVER) && \
+ !defined(SA1111_DRIVER) && \
+- !defined(PS3_SYSTEM_BUS_DRIVER)
++ !defined(PS3_SYSTEM_BUS_DRIVER) && \
++ !defined(SSB_OHCI_DRIVER)
+ #error "missing bus glue for ohci-hcd"
+ #endif
+
+@@ -972,10 +978,20 @@
+ goto error_pci;
+ #endif
+
++#ifdef SSB_OHCI_DRIVER
++ retval = ssb_driver_register(&SSB_OHCI_DRIVER);
++ if (retval)
++ goto error_ssb;
++#endif
++
+ return retval;
+
+ /* Error path */
++#ifdef SSB_OHCI_DRIVER
++ error_ssb:
++#endif
+ #ifdef PCI_DRIVER
++ pci_unregister_driver(&PCI_DRIVER);
+ error_pci:
+ #endif
+ #ifdef SA1111_DRIVER
+@@ -1001,6 +1017,9 @@
+
+ static void __exit ohci_hcd_mod_exit(void)
+ {
++#ifdef SSB_OHCI_DRIVER
++ ssb_driver_unregister(&SSB_OHCI_DRIVER);
++#endif
+ #ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
+ #endif
diff --git a/target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch b/target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch
new file mode 100644
index 0000000000..21986b3426
--- /dev/null
+++ b/target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch
@@ -0,0 +1,421 @@
+Index: linux-2.6.22-rc4/drivers/ssb/driver_chipcommon.c
+===================================================================
+--- linux-2.6.22-rc4.orig/drivers/ssb/driver_chipcommon.c 2007-06-10 21:32:11.000000000 +0100
++++ linux-2.6.22-rc4/drivers/ssb/driver_chipcommon.c 2007-06-10 21:33:25.000000000 +0100
+@@ -264,6 +264,31 @@
+ ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
+ }
+
++/* TODO: These two functions are a clear candidate for merging, but one gets
++ * the processor clock, and the other gets the bus clock.
++ */
++void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
++ u32 *plltype, u32 *n, u32 *m)
++{
++ *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
++ *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
++ switch (*plltype) {
++ case SSB_PLLTYPE_2:
++ case SSB_PLLTYPE_4:
++ case SSB_PLLTYPE_6:
++ case SSB_PLLTYPE_7:
++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
++ break;
++ case SSB_PLLTYPE_3:
++ /* 5350 uses m2 to control mips */
++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
++ break;
++ default:
++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
++ break;
++ }
++}
++
+ void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
+ u32 *plltype, u32 *n, u32 *m)
+ {
+@@ -400,3 +425,13 @@
+ return nr_ports;
+ }
+ #endif /* CONFIG_SSB_SERIAL */
++
++/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
++int
++ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks)
++{
++ /* instant NMI */
++ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
++ return 0;
++}
++EXPORT_SYMBOL(ssb_chipco_watchdog);
+Index: linux-2.6.22-rc4/drivers/ssb/driver_mipscore.c
+===================================================================
+--- linux-2.6.22-rc4.orig/drivers/ssb/driver_mipscore.c 2007-06-10 21:32:11.000000000 +0100
++++ linux-2.6.22-rc4/drivers/ssb/driver_mipscore.c 2007-06-10 21:33:25.000000000 +0100
+@@ -4,6 +4,7 @@
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+@@ -31,6 +32,16 @@
+ ssb_write32(mcore->dev, offset, value);
+ }
+
++static inline u32 extif_read32(struct ssb_extif *extif, u16 offset)
++{
++ return ssb_read32(extif->dev, offset);
++}
++
++static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value)
++{
++ ssb_write32(extif->dev, offset, value);
++}
++
+ static const u32 ipsflag_irq_mask[] = {
+ 0,
+ SSB_IPSFLAG_IRQ1,
+@@ -118,9 +129,9 @@
+ }
+
+ /* XXX: leave here or move into separate extif driver? */
+-static int ssb_extif_serial_init(struct ssb_device *dev, struct ssb_serial_ports *ports)
++static int ssb_extif_serial_init(struct ssb_extif *dev, struct ssb_serial_port *ports)
+ {
+-
++ return 0;
+ }
+
+
+@@ -174,23 +185,76 @@
+ {
+ struct ssb_bus *bus = mcore->dev->bus;
+
++ mcore->flash_buswidth = 2;
+ if (bus->chipco.dev) {
+ mcore->flash_window = 0x1c000000;
+- mcore->flash_window_size = 0x800000;
++ mcore->flash_window_size = 0x02000000;
++ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
++ & SSB_CHIPCO_CFG_DS16) == 0)
++ mcore->flash_buswidth = 1;
+ } else {
+ mcore->flash_window = 0x1fc00000;
+- mcore->flash_window_size = 0x400000;
++ mcore->flash_window_size = 0x00400000;
+ }
+ }
+
++static void ssb_extif_timing_init(struct ssb_extif *extif, u32 ns)
++{
++ u32 tmp;
++
++ /* Initialize extif so we can get to the LEDs and external UART */
++ extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN);
++
++ /* Set timing for the flash */
++ tmp = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT;
++ tmp |= ceildiv(40, ns) << SSB_PROG_WCNT_1_SHIFT;
++ tmp |= ceildiv(120, ns);
++ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
++
++ /* Set programmable interface timing for external uart */
++ tmp = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT;
++ tmp |= ceildiv(20, ns) << SSB_PROG_WCNT_2_SHIFT;
++ tmp |= ceildiv(100, ns) << SSB_PROG_WCNT_1_SHIFT;
++ tmp |= ceildiv(120, ns);
++ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
++}
+
+-static void ssb_cpu_clock(struct ssb_mipscore *mcore)
++static inline void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
++ u32 *pll_type, u32 *n, u32 *m)
+ {
++ *pll_type = SSB_PLLTYPE_1;
++ *n = extif_read32(extif, SSB_EXTIF_CLOCK_N);
++ *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
+ }
+
+-void ssb_mipscore_init(struct ssb_mipscore *mcore)
++u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
+ {
+ struct ssb_bus *bus = mcore->dev->bus;
++ u32 pll_type, n, m, rate = 0;
++
++ if (bus->extif.dev) {
++ ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
++ } else if (bus->chipco.dev) {
++ ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
++ } else
++ return 0;
++
++ if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
++ rate = 200000000;
++ } else {
++ rate = ssb_calc_clock_rate(pll_type, n, m);
++ }
++
++ if (pll_type == SSB_PLLTYPE_6) {
++ rate *= 2;
++ }
++
++ return rate;
++}
++
++void ssb_mipscore_init(struct ssb_mipscore *mcore)
++{
++ struct ssb_bus *bus;
+ struct ssb_device *dev;
+ unsigned long hz, ns;
+ unsigned int irq, i;
+@@ -198,6 +262,8 @@
+ if (!mcore->dev)
+ return; /* We don't have a MIPS core */
+
++ bus = mcore->dev->bus;
++
+ ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
+
+ hz = ssb_clockspeed(bus);
+@@ -205,28 +271,9 @@
+ hz = 100000000;
+ ns = 1000000000 / hz;
+
+-//TODO
+-#if 0
+- if (have EXTIF) {
+- /* Initialize extif so we can get to the LEDs and external UART */
+- W_REG(&eir->prog_config, CF_EN);
+-
+- /* Set timing for the flash */
+- tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
+- tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */
+- tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
+- W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
+-
+- /* Set programmable interface timing for external uart */
+- tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
+- tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */
+- tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */
+- tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
+- W_REG(&eir->prog_waitcount, tmp);
+- }
+- else... chipcommon
+-#endif
+- if (bus->chipco.dev)
++ if (bus->extif.dev)
++ ssb_extif_timing_init(&bus->extif, ns);
++ else if (bus->chipco.dev)
+ ssb_chipco_timing_init(&bus->chipco, ns);
+
+ /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
+@@ -256,3 +303,5 @@
+ ssb_mips_serial_init(mcore);
+ ssb_mips_flash_detect(mcore);
+ }
++
++EXPORT_SYMBOL(ssb_mips_irq);
+Index: linux-2.6.22-rc4/drivers/ssb/driver_pcicore.c
+===================================================================
+--- linux-2.6.22-rc4.orig/drivers/ssb/driver_pcicore.c 2007-06-10 21:32:11.000000000 +0100
++++ linux-2.6.22-rc4/drivers/ssb/driver_pcicore.c 2007-06-10 21:33:25.000000000 +0100
+@@ -93,6 +93,9 @@
+
+ /* Enable PCI bridge BAR1 prefetch and burst */
+ pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
++
++ /* Make sure our latency is high enough to handle the devices behind us */
++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
+ }
+ DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
+
+@@ -110,7 +113,7 @@
+
+ if (unlikely(pc->cardbusmode && dev > 1))
+ goto out;
+- if (bus == 0) {
++ if (bus == 0) {//FIXME busnumber ok?
+ /* Type 0 transaction */
+ if (unlikely(dev >= SSB_PCI_SLOT_MAX))
+ goto out;
+@@ -224,7 +227,7 @@
+ val = *((const u32 *)buf);
+ break;
+ }
+- writel(*((const u32 *)buf), mmio);
++ writel(val, mmio);
+
+ err = 0;
+ unmap:
+@@ -307,6 +310,8 @@
+ udelay(150);
+ val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */
+ pcicore_write32(pc, SSB_PCICORE_CTL, val);
++ val = SSB_PCICORE_ARBCTL_INTERN;
++ pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
+ udelay(1);
+
+ //TODO cardbus mode
+@@ -336,6 +341,7 @@
+ * The following needs change, if we want to port hostmode
+ * to non-MIPS platform. */
+ set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
++ mdelay(300);
+ register_pci_controller(&ssb_pcicore_controller);
+ }
+
+Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_chipcommon.h
+===================================================================
+--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-10 21:32:11.000000000 +0100
++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-10 21:33:25.000000000 +0100
+@@ -364,6 +364,8 @@
+ extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state);
+ extern void ssb_chipco_resume(struct ssb_chipcommon *cc);
+
++extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
++ u32 *plltype, u32 *n, u32 *m);
+ extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
+ u32 *plltype, u32 *n, u32 *m);
+ extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc,
+@@ -378,6 +380,46 @@
+ extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
+ enum ssb_clkmode mode);
+
++/* GPIO functions */
++static inline u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc,
++ u32 mask)
++{
++ return ssb_read32(cc->dev, SSB_CHIPCO_GPIOIN) & mask;
++}
++
++static inline u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc,
++ u32 mask, u32 value)
++{
++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUT, mask, value);
++}
++
++static inline u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc,
++ u32 mask, u32 value)
++{
++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUTEN, mask, value);
++}
++
++static inline u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc,
++ u32 mask, u32 value)
++{
++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOCTL, mask, value);
++}
++
++static inline u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc,
++ u32 mask, u32 value)
++{
++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOIRQ, mask, value);
++}
++
++static inline u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc,
++ u32 mask, u32 value)
++{
++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOPOL, mask, value);
++}
++/* TODO: GPIO reservation */
++
++extern int ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks);
++
+ #ifdef CONFIG_SSB_SERIAL
+ extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
+ struct ssb_serial_port *ports);
+Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_extif.h
+===================================================================
+--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_extif.h 2007-06-10 21:32:11.000000000 +0100
++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_extif.h 2007-06-10 21:33:25.000000000 +0100
+@@ -158,6 +158,36 @@
+ /* watchdog */
+ #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */
+
++/* GPIO functions */
++static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif,
++ u32 mask)
++{
++ return ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN) & mask;
++}
++
++static inline u32 ssb_extif_gpio_out(struct ssb_extif *extif,
++ u32 mask, u32 value)
++{
++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUT(0), mask, value);
++}
++
++static inline u32 ssb_extif_gpio_outen(struct ssb_extif *extif,
++ u32 mask, u32 value)
++{
++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUTEN(0), mask, value);
++}
++
++static inline u32 ssb_extif_gpio_polarity(struct ssb_extif *extif,
++ u32 mask, u32 value)
++{
++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTPOL, mask, value);
++}
++
++static inline u32 ssb_extif_gpio_intmask(struct ssb_extif *extif,
++ u32 mask, u32 value)
++{
++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTMASK, mask, value);
++}
+
+ #endif /* __KERNEL__ */
+ #endif /* LINUX_SSB_EXTIFCORE_H_ */
+Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_mips.h
+===================================================================
+--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_mips.h 2007-06-10 21:32:11.000000000 +0100
++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_mips.h 2007-06-10 21:33:25.000000000 +0100
+@@ -22,11 +22,13 @@
+ int nr_serial_ports;
+ struct ssb_serial_port serial_ports[4];
+
++ int flash_buswidth;
+ u32 flash_window;
+ u32 flash_window_size;
+ };
+
+ extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
++extern u32 ssb_cpu_clock(struct ssb_mipscore *mcore);
+
+ extern unsigned int ssb_mips_irq(struct ssb_device *dev);
+
+Index: linux-2.6.22-rc4/include/linux/ssb/ssb.h
+===================================================================
+--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb.h 2007-06-10 21:32:11.000000000 +0100
++++ linux-2.6.22-rc4/include/linux/ssb/ssb.h 2007-06-10 21:33:25.000000000 +0100
+@@ -263,6 +263,12 @@
+ #define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */
+ #define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */
+
++static inline u16 ssb_read16(struct ssb_device *dev, u16 offset);
++static inline u32 ssb_read32(struct ssb_device *dev, u16 offset);
++static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value);
++static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value);
++static inline u32 ssb_write32_masked(struct ssb_device *dev, u16 offset, u32 mask, u32 value);
++
+ #include <linux/ssb/ssb_driver_chipcommon.h>
+ #include <linux/ssb/ssb_driver_mips.h>
+ #include <linux/ssb/ssb_driver_extif.h>
+@@ -369,6 +375,16 @@
+ dev->ops->write32(dev, offset, value);
+ }
+
++static inline u32 ssb_write32_masked(struct ssb_device *dev,
++ u16 offset,
++ u32 mask,
++ u32 value)
++{
++ value &= mask;
++ value |= ssb_read32(dev, offset) & ~mask;
++ ssb_write32(dev, offset, value);
++ return value;
++}
+
+ /* Translation (routing) bits that need to be ORed to DMA
+ * addresses before they are given to a device. */