kernel: update bcma and ssb to wireless-testing/master master-2013-07-03
authorhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 11 Jul 2013 22:20:26 +0000 (22:20 +0000)
committerhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 11 Jul 2013 22:20:26 +0000 (22:20 +0000)
This updates 025-bcma_backport.patch and 020-ssb_update.patch to a
version of ssb and bcma used in recent wireless-testing. I removed all
patches adding serial and nand flash support before doing so to not
conflict with the existing flash support in the brcm47xx target. This
update was done to easily update the wireless drivers afterwards.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
git-svn-id: svn://svn.openwrt.org/openwrt/branches/attitude_adjustment@37261 3c298f89-4303-0410-b956-a3cf2f4a3e73

22 files changed:
package/mac80211/patches/835-b43-brcmsmac-use-pcie-core-arry.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.3/020-bcma-move-parallel-flash-into-a-union.patch
target/linux/brcm47xx/patches-3.3/021-bcma-add-serial-flash-support-to-bcma.patch
target/linux/brcm47xx/patches-3.3/022-ssb-move-flash-to-chipcommon.patch
target/linux/brcm47xx/patches-3.3/023-ssb-add-serial-flash-support.patch
target/linux/brcm47xx/patches-3.3/030-bcm47xx-bcma-nandflash.patch
target/linux/brcm47xx/patches-3.3/201-bcma-just-do-the-necessary-things-in-early-register.patch [deleted file]
target/linux/brcm47xx/patches-3.3/202-bcma-init-sprom-struct-earlier.patch [deleted file]
target/linux/brcm47xx/patches-3.3/203-bcma-use-fallback-sprom-if-sprom-on-card-was-not-val.patch [deleted file]
target/linux/brcm47xx/patches-3.3/204-bcma-do-not-initialize-deactivated-PCIe-cores.patch [deleted file]
target/linux/brcm47xx/patches-3.3/240-bcma-pcie-config-access.patch [deleted file]
target/linux/brcm47xx/patches-3.3/280-activate_ssb_support_in_usb.patch
target/linux/brcm47xx/patches-3.3/500-ssb-add-function-to-return-number-of-gpio-lines.patch
target/linux/brcm47xx/patches-3.3/501-bcma-add-gpio-driver.patch
target/linux/brcm47xx/patches-3.3/700-ssb-gigabit-ethernet-driver.patch
target/linux/brcm47xx/patches-3.3/976-ssb_increase_pci_delay.patch
target/linux/generic/config-3.3
target/linux/generic/patches-3.3/020-ssb_update.patch
target/linux/generic/patches-3.3/025-bcma_backport.patch
target/linux/generic/patches-3.3/026-bcma_pmu_regression.patch [deleted file]
target/linux/generic/patches-3.3/027-bcma-add-missing-iounmap-on-error-path.patch [deleted file]
target/linux/generic/patches-3.3/028-bcma-fix-regression-in-interrupt-assignment-on-mips.patch [deleted file]

diff --git a/package/mac80211/patches/835-b43-brcmsmac-use-pcie-core-arry.patch b/package/mac80211/patches/835-b43-brcmsmac-use-pcie-core-arry.patch
new file mode 100644 (file)
index 0000000..0810a42
--- /dev/null
@@ -0,0 +1,42 @@
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -4701,7 +4701,7 @@ static int b43_wireless_core_init(struct
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+-              bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci,
++              bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0],
+                                     dev->dev->bdev, true);
+               break;
+ #endif
+--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
+@@ -694,7 +694,7 @@ void ai_pci_up(struct si_pub *sih)
+       sii = container_of(sih, struct si_info, pub);
+       if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI)
+-              bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true);
++              bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], true);
+ }
+ /* Unconfigure and/or apply various WARs when going down */
+@@ -705,7 +705,7 @@ void ai_pci_down(struct si_pub *sih)
+       sii = container_of(sih, struct si_info, pub);
+       if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI)
+-              bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false);
++              bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], false);
+ }
+ /* Enable BT-COEX & Ex-PA for 4313 */
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -4979,7 +4979,7 @@ static int brcms_b_up_prep(struct brcms_
+        * Configure pci/pcmcia here instead of in brcms_c_attach()
+        * to allow mfg hotswap:  down, hotswap (chip power cycle), up.
+        */
+-      bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci, wlc_hw->d11core,
++      bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core,
+                             true);
+       /*
index 98c855f..a82577c 100644 (file)
@@ -12,7 +12,7 @@
                break;
 --- a/drivers/bcma/driver_mips.c
 +++ b/drivers/bcma/driver_mips.c
-@@ -189,6 +189,7 @@ static void bcma_core_mips_flash_detect(
+@@ -218,6 +218,7 @@ static void bcma_core_mips_flash_detect(
                break;
        case BCMA_CC_FLASHT_PARA:
                bcma_info(bus, "found parallel flash.\n");
  
 --- a/include/linux/bcma/bcma_driver_chipcommon.h
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -122,10 +122,68 @@
- #define  BCMA_CC_JCTL_EXT_EN          2               /* Enable external targets */
- #define  BCMA_CC_JCTL_EN              1               /* Enable Jtag master */
- #define BCMA_CC_FLASHCTL              0x0040
-+
-+/* Start/busy bit in flashcontrol */
-+#define  BCMA_CC_FLASHCTL_OPCODE      0x000000ff
-+#define  BCMA_CC_FLASHCTL_ACTION      0x00000700
-+#define  BCMA_CC_FLASHCTL_CS_ACTIVE   0x00001000      /* Chip Select Active, rev >= 20 */
- #define  BCMA_CC_FLASHCTL_START               0x80000000
- #define  BCMA_CC_FLASHCTL_BUSY                BCMA_CC_FLASHCTL_START
-+
-+/* flashcontrol action+opcodes for ST flashes */
-+#define  BCMA_CC_FLASHCTL_ST_WREN     0x0006          /* Write Enable */
-+#define  BCMA_CC_FLASHCTL_ST_WRDIS    0x0004          /* Write Disable */
-+#define  BCMA_CC_FLASHCTL_ST_RDSR     0x0105          /* Read Status Register */
-+#define  BCMA_CC_FLASHCTL_ST_WRSR     0x0101          /* Write Status Register */
-+#define  BCMA_CC_FLASHCTL_ST_READ     0x0303          /* Read Data Bytes */
-+#define  BCMA_CC_FLASHCTL_ST_PP               0x0302          /* Page Program */
-+#define  BCMA_CC_FLASHCTL_ST_SE               0x02d8          /* Sector Erase */
-+#define  BCMA_CC_FLASHCTL_ST_BE               0x00c7          /* Bulk Erase */
-+#define  BCMA_CC_FLASHCTL_ST_DP               0x00b9          /* Deep Power-down */
-+#define  BCMA_CC_FLASHCTL_ST_RES      0x03ab          /* Read Electronic Signature */
-+#define  BCMA_CC_FLASHCTL_ST_CSA      0x1000          /* Keep chip select asserted */
-+#define  BCMA_CC_FLASHCTL_ST_SSE      0x0220          /* Sub-sector Erase */
-+
-+
-+/* flashcontrol action+opcodes for Atmel flashes */
-+#define  BCMA_CC_FLASHCTL_AT_READ                     0x07e8
-+#define  BCMA_CC_FLASHCTL_AT_PAGE_READ                        0x07d2
-+#define  BCMA_CC_FLASHCTL_AT_BUF1_READ
-+#define  BCMA_CC_FLASHCTL_AT_BUF2_READ
-+#define  BCMA_CC_FLASHCTL_AT_STATUS                   0x01d7
-+#define  BCMA_CC_FLASHCTL_AT_BUF1_WRITE                       0x0384
-+#define  BCMA_CC_FLASHCTL_AT_BUF2_WRITE                       0x0387
-+#define  BCMA_CC_FLASHCTL_AT_BUF1_ERASE_PROGRAM               0x0283
-+#define  BCMA_CC_FLASHCTL_AT_BUF2_ERASE_PROGRAM               0x0286
-+#define  BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM             0x0288
-+#define  BCMA_CC_FLASHCTL_AT_BUF2_PROGRAM             0x0289
-+#define  BCMA_CC_FLASHCTL_AT_PAGE_ERASE                       0x0281
-+#define  BCMA_CC_FLASHCTL_AT_BLOCK_ERASE              0x0250
-+#define  BCMA_CC_FLASHCTL_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
-+#define  BCMA_CC_FLASHCTL_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
-+#define  BCMA_CC_FLASHCTL_AT_BUF1_LOAD                        0x0253
-+#define  BCMA_CC_FLASHCTL_AT_BUF2_LOAD                        0x0255
-+#define  BCMA_CC_FLASHCTL_AT_BUF1_COMPARE             0x0260
-+#define  BCMA_CC_FLASHCTL_AT_BUF2_COMPARE             0x0261
-+#define  BCMA_CC_FLASHCTL_AT_BUF1_REPROGRAM           0x0258
-+#define  BCMA_CC_FLASHCTL_AT_BUF2_REPROGRAM           0x0259
-+
- #define BCMA_CC_FLASHADDR             0x0044
- #define BCMA_CC_FLASHDATA             0x0048
-+
-+/* Status register bits for ST flashes */
-+#define  BCMA_CC_FLASHDATA_ST_WIP     0x01            /* Write In Progress */
-+#define  BCMA_CC_FLASHDATA_ST_WEL     0x02            /* Write Enable Latch */
-+#define  BCMA_CC_FLASHDATA_ST_BP_MASK 0x1c            /* Block Protect */
-+#define  BCMA_CC_FLASHDATA_ST_BP_SHIFT        2
-+#define  BCMA_CC_FLASHDATA_ST_SRWD    0x80            /* Status Register Write Disable */
-+
-+/* Status register bits for Atmel flashes */
-+#define  BCMA_CC_FLASHDATA_AT_READY   0x80
-+#define  BCMA_CC_FLASHDATA_AT_MISMATCH        0x40
-+#define  BCMA_CC_FLASHDATA_AT_ID_MASK 0x38
-+#define  BCMA_CC_FLASHDATA_AT_ID_SHIFT        3
-+
- #define BCMA_CC_BCAST_ADDR            0x0050
- #define BCMA_CC_BCAST_DATA            0x0054
- #define BCMA_CC_GPIOPULLUP            0x0058          /* Rev >= 20 only */
-@@ -360,6 +418,12 @@
- /* 4313 Chip specific ChipControl register bits */
- #define BCMA_CCTRL_4313_12MA_LED_DRIVE                0x00000007      /* 12 mA drive strengh for later 4313 */
+@@ -562,6 +562,12 @@
+ #define BCMA_RES_4314_HT_AVAIL                        BIT(28)
+ #define BCMA_RES_4314_MACPHY_CLK_AVAIL                BIT(29)
  
 +#define       BCMA_FLASH2                     0x1c000000      /* Flash Region 2 (region 1 shadowed here) */
 +#define       BCMA_FLASH2_SZ                  0x02000000      /* Size of Flash Region 2 */
  /* Data for the PMU, if available.
   * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
   */
-@@ -369,6 +433,10 @@ struct bcma_chipcommon_pmu {
+@@ -571,6 +577,10 @@ struct bcma_chipcommon_pmu {
  };
  
  #ifdef CONFIG_BCMA_DRIVER_MIPS
  struct bcma_pflash {
        u8 buswidth;
        u32 window;
-@@ -394,7 +462,10 @@ struct bcma_drv_cc {
+@@ -597,7 +607,10 @@ struct bcma_drv_cc {
        u16 fast_pwrup_delay;
        struct bcma_chipcommon_pmu pmu;
  #ifdef CONFIG_BCMA_DRIVER_MIPS
index 7382636..9c0ce68 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/bcma/Kconfig
 +++ b/drivers/bcma/Kconfig
-@@ -38,6 +38,11 @@ config BCMA_HOST_SOC
+@@ -39,6 +39,11 @@ config BCMA_HOST_SOC
        bool
        depends on BCMA_DRIVER_MIPS
  
@@ -23,9 +23,9 @@
  bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 --- a/drivers/bcma/bcma_private.h
 +++ b/drivers/bcma/bcma_private.h
-@@ -51,6 +51,11 @@ void bcma_chipco_serial_init(struct bcma
- u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
- u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
+@@ -55,6 +55,11 @@ void bcma_chipco_serial_init(struct bcma
+ u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
+ u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
  
 +#ifdef CONFIG_BCMA_SFLASH
 +/* driver_chipcommon_sflash.c */
 +}
 --- a/drivers/bcma/driver_mips.c
 +++ b/drivers/bcma/driver_mips.c
-@@ -185,7 +185,13 @@ static void bcma_core_mips_flash_detect(
+@@ -214,7 +214,13 @@ static void bcma_core_mips_flash_detect(
        switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
        case BCMA_CC_FLASHT_STSER:
        case BCMA_CC_FLASHT_ATSER:
                bcma_info(bus, "found parallel flash.\n");
 --- a/include/linux/bcma/bcma_driver_chipcommon.h
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -435,6 +435,7 @@ struct bcma_chipcommon_pmu {
+@@ -579,6 +579,7 @@ struct bcma_chipcommon_pmu {
  #ifdef CONFIG_BCMA_DRIVER_MIPS
  enum bcma_flash_type {
        BCMA_PFLASH,
  };
  
  struct bcma_pflash {
-@@ -443,6 +444,14 @@ struct bcma_pflash {
+@@ -587,6 +588,14 @@ struct bcma_pflash {
        u32 window_size;
  };
  
  struct bcma_serial_port {
        void *regs;
        unsigned long clockspeed;
-@@ -465,6 +474,9 @@ struct bcma_drv_cc {
+@@ -610,6 +619,9 @@ struct bcma_drv_cc {
        enum bcma_flash_type flash_type;
        union {
                struct bcma_pflash pflash;
        };
  
        int nr_serial_ports;
-@@ -520,4 +532,14 @@ extern void bcma_chipco_regctl_maskset(s
-                                      u32 offset, u32 mask, u32 set);
- extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
+@@ -680,4 +692,14 @@ extern void bcma_pmu_spuravoid_pllupdate
+ extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc);
  
 +#ifdef CONFIG_BCMA_SFLASH
 +/* Chipcommon sflash support. */
index 12055bf..4fa76e1 100644 (file)
        struct ssb_bus *bus = mcore->dev->bus;
  
 -      mcore->flash_buswidth = 2;
--      if (bus->chipco.dev) {
+-      if (ssb_chipco_available(&bus->chipco)) {
 -              mcore->flash_window = 0x1c000000;
 -              mcore->flash_window_size = 0x02000000;
 +      /* When there is no chipcommon on the bus there is 4MB flash */
-+      if (!bus->chipco.dev) {
++      if (!ssb_chipco_available(&bus->chipco)) {
 +              pr_info("found parallel flash.\n");
 +              bus->chipco.flash_type = SSB_PFLASH;
 +              bus->chipco.pflash.window = SSB_FLASH1;
  
 --- a/include/linux/ssb/ssb_driver_chipcommon.h
 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
-@@ -582,6 +582,18 @@ struct ssb_chipcommon_pmu {
+@@ -583,6 +583,18 @@ struct ssb_chipcommon_pmu {
        u32 crystalfreq;        /* The active crystal frequency (in kHz) */
  };
  
  struct ssb_chipcommon {
        struct ssb_device *dev;
        u32 capabilities;
-@@ -589,6 +601,12 @@ struct ssb_chipcommon {
-       /* Fast Powerup Delay constant */
-       u16 fast_pwrup_delay;
+@@ -593,6 +605,12 @@ struct ssb_chipcommon {
        struct ssb_chipcommon_pmu pmu;
+       u32 ticks_per_ms;
+       u32 max_timer_ms;
 +#ifdef CONFIG_SSB_DRIVER_MIPS
 +      enum ssb_flash_type flash_type;
 +      union {
index ba5a5c2..7be794d 100644 (file)
                pr_info("found parallel flash.\n");
 --- a/drivers/ssb/ssb_private.h
 +++ b/drivers/ssb/ssb_private.h
-@@ -192,6 +192,10 @@ extern int ssb_devices_freeze(struct ssb
+@@ -204,6 +204,10 @@ extern int ssb_devices_freeze(struct ssb
  extern int ssb_devices_thaw(struct ssb_freeze_context *ctx);
  
  
  #ifdef CONFIG_SSB_B43_PCI_BRIDGE
 --- a/include/linux/ssb/ssb_driver_chipcommon.h
 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
-@@ -503,8 +503,10 @@
+@@ -504,8 +504,10 @@
  #define SSB_CHIPCO_FLASHCTL_ST_PP     0x0302          /* Page Program */
  #define SSB_CHIPCO_FLASHCTL_ST_SE     0x02D8          /* Sector Erase */
  #define SSB_CHIPCO_FLASHCTL_ST_BE     0x00C7          /* Bulk Erase */
  
  /* Status register bits for ST flashes */
  #define SSB_CHIPCO_FLASHSTA_ST_WIP    0x01            /* Write In Progress */
-@@ -585,6 +587,7 @@ struct ssb_chipcommon_pmu {
+@@ -586,6 +588,7 @@ struct ssb_chipcommon_pmu {
  #ifdef CONFIG_SSB_DRIVER_MIPS
  enum ssb_flash_type {
        SSB_PFLASH,
  };
  
  struct ssb_pflash {
-@@ -592,6 +595,14 @@ struct ssb_pflash {
+@@ -593,6 +596,14 @@ struct ssb_pflash {
        u32 window;
        u32 window_size;
  };
  #endif /* CONFIG_SSB_DRIVER_MIPS */
  
  struct ssb_chipcommon {
-@@ -605,6 +616,9 @@ struct ssb_chipcommon {
+@@ -609,6 +620,9 @@ struct ssb_chipcommon {
        enum ssb_flash_type flash_type;
        union {
                struct ssb_pflash pflash;
        };
  #endif /* CONFIG_SSB_DRIVER_MIPS */
  };
-@@ -666,6 +680,16 @@ extern int ssb_chipco_serial_init(struct
+@@ -671,6 +685,16 @@ extern int ssb_chipco_serial_init(struct
                                  struct ssb_serial_port *ports);
  #endif /* CONFIG_SSB_SERIAL */
  
index 53f6e98..88f1fe0 100644 (file)
 +extern struct bcm47xx_nflash bcm47xx_nflash;
 --- a/drivers/bcma/Kconfig
 +++ b/drivers/bcma/Kconfig
-@@ -43,6 +43,11 @@ config BCMA_SFLASH
+@@ -44,6 +44,11 @@ config BCMA_SFLASH
        depends on BCMA_DRIVER_MIPS
        default y
  
  bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 --- a/drivers/bcma/bcma_private.h
 +++ b/drivers/bcma/bcma_private.h
-@@ -56,6 +56,11 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
+@@ -60,6 +60,11 @@ u32 bcma_pmu_get_cpu_clock(struct bcma_d
  int bcma_sflash_init(struct bcma_drv_cc *cc);
  #endif /* CONFIG_BCMA_SFLASH */
  
   *
   * Licensed under the GNU/GPL. See COPYING for details.
   */
-@@ -182,6 +183,17 @@ static void bcma_core_mips_flash_detect(
+@@ -211,6 +212,17 @@ static void bcma_core_mips_flash_detect(
  {
        struct bcma_bus *bus = mcore->core->bus;
  
 +MODULE_DESCRIPTION("BCM47XX NAND flash driver");
 --- a/include/linux/bcma/bcma_driver_chipcommon.h
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -436,6 +436,7 @@ struct bcma_chipcommon_pmu {
+@@ -580,6 +580,7 @@ struct bcma_chipcommon_pmu {
  enum bcma_flash_type {
        BCMA_PFLASH,
        BCMA_SFLASH,
  };
  
  struct bcma_pflash {
-@@ -452,6 +453,14 @@ struct bcma_sflash {
+@@ -596,6 +597,14 @@ struct bcma_sflash {
  };
  #endif /* CONFIG_BCMA_SFLASH */
  
  struct bcma_serial_port {
        void *regs;
        unsigned long clockspeed;
-@@ -477,6 +486,9 @@ struct bcma_drv_cc {
+@@ -622,6 +631,9 @@ struct bcma_drv_cc {
  #ifdef CONFIG_BCMA_SFLASH
                struct bcma_sflash sflash;
  #endif /* CONFIG_BCMA_SFLASH */
        };
  
        int nr_serial_ports;
-@@ -542,4 +554,13 @@ int bcma_sflash_write(struct bcma_drv_cc
+@@ -702,4 +714,13 @@ int bcma_sflash_write(struct bcma_drv_cc
  int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset);
  #endif /* CONFIG_BCMA_SFLASH */
  
diff --git a/target/linux/brcm47xx/patches-3.3/201-bcma-just-do-the-necessary-things-in-early-register.patch b/target/linux/brcm47xx/patches-3.3/201-bcma-just-do-the-necessary-things-in-early-register.patch
deleted file mode 100644 (file)
index 6ef5ecd..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
---- a/drivers/bcma/driver_chipcommon.c
-+++ b/drivers/bcma/driver_chipcommon.c
-@@ -22,12 +22,9 @@ static inline u32 bcma_cc_write32_masked
-       return value;
- }
--void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
-+void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
- {
--      u32 leddc_on = 10;
--      u32 leddc_off = 90;
--
--      if (cc->setup_done)
-+      if (cc->early_setup_done)
-               return;
-       if (cc->core->id.rev >= 11)
-@@ -36,6 +33,22 @@ void bcma_core_chipcommon_init(struct bc
-       if (cc->core->id.rev >= 35)
-               cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
-+      if (cc->capabilities & BCMA_CC_CAP_PMU)
-+              bcma_pmu_early_init(cc);
-+
-+      cc->early_setup_done = true;
-+}
-+
-+void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
-+{
-+      u32 leddc_on = 10;
-+      u32 leddc_off = 90;
-+
-+      if (cc->setup_done)
-+              return;
-+
-+      bcma_core_chipcommon_early_init(cc);
-+
-       if (cc->core->id.rev >= 20) {
-               bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
-               bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
---- a/drivers/bcma/driver_chipcommon_pmu.c
-+++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -141,7 +141,7 @@ void bcma_pmu_workarounds(struct bcma_dr
-       }
- }
--void bcma_pmu_init(struct bcma_drv_cc *cc)
-+void bcma_pmu_early_init(struct bcma_drv_cc *cc)
- {
-       u32 pmucap;
-@@ -150,7 +150,10 @@ void bcma_pmu_init(struct bcma_drv_cc *c
-       bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
-                  cc->pmu.rev, pmucap);
-+}
-+void bcma_pmu_init(struct bcma_drv_cc *cc)
-+{
-       if (cc->pmu.rev == 1)
-               bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
-                             ~BCMA_CC_PMU_CTL_NOILPONW);
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -222,16 +222,33 @@ static void bcma_core_mips_flash_detect(
-       }
- }
-+void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
-+{
-+      struct bcma_bus *bus = mcore->core->bus;
-+
-+      if (mcore->early_setup_done)
-+              return;
-+
-+      bcma_chipco_serial_init(&bus->drv_cc);
-+      bcma_core_mips_flash_detect(mcore);
-+
-+      mcore->early_setup_done = true;
-+}
-+
- void bcma_core_mips_init(struct bcma_drv_mips *mcore)
- {
-       struct bcma_bus *bus;
-       struct bcma_device *core;
-       bus = mcore->core->bus;
-+      if (mcore->setup_done)
-+              return;
-+
-       bcma_info(bus, "Initializing MIPS core...\n");
--      if (!mcore->setup_done)
--              mcore->assigned_irqs = 1;
-+      bcma_core_mips_early_init(mcore);
-+
-+      mcore->assigned_irqs = 1;
-       /* Assign IRQs to all cores on the bus */
-       list_for_each_entry(core, &bus->cores, list) {
-@@ -266,10 +283,5 @@ void bcma_core_mips_init(struct bcma_drv
-       bcma_info(bus, "IRQ reconfiguration done\n");
-       bcma_core_mips_dump_irq(bus);
--      if (mcore->setup_done)
--              return;
--
--      bcma_chipco_serial_init(&bus->drv_cc);
--      bcma_core_mips_flash_detect(mcore);
-       mcore->setup_done = true;
- }
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -247,18 +247,18 @@ int __init bcma_bus_early_register(struc
-               return -1;
-       }
--      /* Init CC core */
-+      /* Early init CC core */
-       core = bcma_find_core(bus, bcma_cc_core_id(bus));
-       if (core) {
-               bus->drv_cc.core = core;
--              bcma_core_chipcommon_init(&bus->drv_cc);
-+              bcma_core_chipcommon_early_init(&bus->drv_cc);
-       }
--      /* Init MIPS core */
-+      /* Early init MIPS core */
-       core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
-       if (core) {
-               bus->drv_mips.core = core;
--              bcma_core_mips_init(&bus->drv_mips);
-+              bcma_core_mips_early_init(&bus->drv_mips);
-       }
-       bcma_info(bus, "Early bus registered\n");
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -476,6 +476,7 @@ struct bcma_drv_cc {
-       u32 capabilities;
-       u32 capabilities_ext;
-       u8 setup_done:1;
-+      u8 early_setup_done:1;
-       /* Fast Powerup Delay constant */
-       u16 fast_pwrup_delay;
-       struct bcma_chipcommon_pmu pmu;
-@@ -510,6 +511,7 @@ struct bcma_drv_cc {
-       bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
- extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
-+extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
- extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
- extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
-@@ -533,6 +535,7 @@ u32 bcma_chipco_gpio_polarity(struct bcm
- /* PMU support */
- extern void bcma_pmu_init(struct bcma_drv_cc *cc);
-+extern void bcma_pmu_early_init(struct bcma_drv_cc *cc);
- extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
-                                 u32 value);
---- a/include/linux/bcma/bcma_driver_mips.h
-+++ b/include/linux/bcma/bcma_driver_mips.h
-@@ -35,13 +35,16 @@ struct bcma_device;
- struct bcma_drv_mips {
-       struct bcma_device *core;
-       u8 setup_done:1;
-+      u8 early_setup_done:1;
-       unsigned int assigned_irqs;
- };
- #ifdef CONFIG_BCMA_DRIVER_MIPS
- extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
-+extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
- #else
- static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
-+static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
- #endif
- extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
diff --git a/target/linux/brcm47xx/patches-3.3/202-bcma-init-sprom-struct-earlier.patch b/target/linux/brcm47xx/patches-3.3/202-bcma-init-sprom-struct-earlier.patch
deleted file mode 100644 (file)
index 03540f0..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -165,6 +165,20 @@ int __devinit bcma_bus_register(struct b
-               return -1;
-       }
-+      /* Early init CC core */
-+      core = bcma_find_core(bus, bcma_cc_core_id(bus));
-+      if (core) {
-+              bus->drv_cc.core = core;
-+              bcma_core_chipcommon_early_init(&bus->drv_cc);
-+      }
-+
-+      /* Try to get SPROM */
-+      err = bcma_sprom_get(bus);
-+      if (err == -ENOENT) {
-+              bcma_err(bus, "No SPROM available\n");
-+      } else if (err)
-+              bcma_err(bus, "Failed to get SPROM: %d\n", err);
-+
-       /* Init CC core */
-       core = bcma_find_core(bus, bcma_cc_core_id(bus));
-       if (core) {
-@@ -193,13 +207,6 @@ int __devinit bcma_bus_register(struct b
-               bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
-       }
--      /* Try to get SPROM */
--      err = bcma_sprom_get(bus);
--      if (err == -ENOENT) {
--              bcma_err(bus, "No SPROM available\n");
--      } else if (err)
--              bcma_err(bus, "Failed to get SPROM: %d\n", err);
--
-       /* Register found cores */
-       bcma_register_cores(bus);
diff --git a/target/linux/brcm47xx/patches-3.3/203-bcma-use-fallback-sprom-if-sprom-on-card-was-not-val.patch b/target/linux/brcm47xx/patches-3.3/203-bcma-use-fallback-sprom-if-sprom-on-card-was-not-val.patch
deleted file mode 100644 (file)
index b6e6480..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
---- a/drivers/bcma/sprom.c
-+++ b/drivers/bcma/sprom.c
-@@ -591,8 +591,11 @@ int bcma_sprom_get(struct bcma_bus *bus)
-               bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
-       err = bcma_sprom_valid(sprom);
--      if (err)
-+      if (err) {
-+              bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
-+              err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
-               goto out;
-+      }
-       bcma_sprom_extract_r8(bus, sprom);
diff --git a/target/linux/brcm47xx/patches-3.3/204-bcma-do-not-initialize-deactivated-PCIe-cores.patch b/target/linux/brcm47xx/patches-3.3/204-bcma-do-not-initialize-deactivated-PCIe-cores.patch
deleted file mode 100644 (file)
index 302ac8d..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
---- a/drivers/bcma/driver_pci_host.c
-+++ b/drivers/bcma/driver_pci_host.c
-@@ -35,11 +35,6 @@ bool __devinit bcma_core_pci_is_in_hostm
-           chipid_top != 0x5300)
-               return false;
--      if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
--              bcma_info(bus, "This PCI core is disabled and not working\n");
--              return false;
--      }
--
-       bcma_core_enable(pc->core, 0);
-       return !mips_busprobe32(tmp, pc->core->io_addr);
-@@ -396,6 +391,11 @@ void __devinit bcma_core_pci_hostmode_in
-       bcma_info(bus, "PCIEcore in host mode found\n");
-+      if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
-+              bcma_info(bus, "This PCIE core is disabled and not working\n");
-+              return;
-+      }
-+
-       pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
-       if (!pc_host)  {
-               bcma_err(bus, "can not allocate memory");
diff --git a/target/linux/brcm47xx/patches-3.3/240-bcma-pcie-config-access.patch b/target/linux/brcm47xx/patches-3.3/240-bcma-pcie-config-access.patch
deleted file mode 100644 (file)
index 91b8a41..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
---- a/drivers/bcma/driver_pci_host.c
-+++ b/drivers/bcma/driver_pci_host.c
-@@ -94,19 +94,19 @@ static int bcma_extpci_read_config(struc
-       if (dev == 0) {
-               /* we support only two functions on device 0 */
-               if (func > 1)
--                      return -EINVAL;
-+                      goto out;
-               /* accesses to config registers with offsets >= 256
-                * requires indirect access.
-                */
-               if (off >= PCI_CONFIG_SPACE_SIZE) {
-                       addr = (func << 12);
--                      addr |= (off & 0x0FFF);
-+                      addr |= (off & 0x0FFC);
-                       val = bcma_pcie_read_config(pc, addr);
-               } else {
-                       addr = BCMA_CORE_PCI_PCICFG0;
-                       addr |= (func << 8);
--                      addr |= (off & 0xfc);
-+                      addr |= (off & 0xFC);
-                       val = pcicore_read32(pc, addr);
-               }
-       } else {
-@@ -122,8 +122,6 @@ static int bcma_extpci_read_config(struc
-                       val = 0xffffffff;
-                       goto unmap;
-               }
--
--              val = readl(mmio);
-       }
-       val >>= (8 * (off & 3));
-@@ -151,7 +149,7 @@ static int bcma_extpci_write_config(stru
-                                  const void *buf, int len)
- {
-       int err = -EINVAL;
--      u32 addr = 0, val = 0;
-+      u32 addr, val;
-       void __iomem *mmio = 0;
-       u16 chipid = pc->core->bus->chipinfo.id;
-@@ -159,16 +157,22 @@ static int bcma_extpci_write_config(stru
-       if (unlikely(len != 1 && len != 2 && len != 4))
-               goto out;
-       if (dev == 0) {
-+              /* we support only two functions on device 0 */
-+              if (func > 1)
-+                      goto out;
-+
-               /* accesses to config registers with offsets >= 256
-                * requires indirect access.
-                */
--              if (off < PCI_CONFIG_SPACE_SIZE) {
--                      addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
-+              if (off >= PCI_CONFIG_SPACE_SIZE) {
-+                      addr = (func << 12);
-+                      addr |= (off & 0x0FFC);
-+                      val = bcma_pcie_read_config(pc, addr);
-+              } else {
-+                      addr = BCMA_CORE_PCI_PCICFG0;
-                       addr |= (func << 8);
--                      addr |= (off & 0xfc);
--                      mmio = ioremap_nocache(addr, sizeof(val));
--                      if (!mmio)
--                              goto out;
-+                      addr |= (off & 0xFC);
-+                      val = pcicore_read32(pc, addr);
-               }
-       } else {
-               addr = bcma_get_cfgspace_addr(pc, dev, func, off);
-@@ -187,12 +191,10 @@ static int bcma_extpci_write_config(stru
-       switch (len) {
-       case 1:
--              val = readl(mmio);
-               val &= ~(0xFF << (8 * (off & 3)));
-               val |= *((const u8 *)buf) << (8 * (off & 3));
-               break;
-       case 2:
--              val = readl(mmio);
-               val &= ~(0xFFFF << (8 * (off & 3)));
-               val |= *((const u16 *)buf) << (8 * (off & 3));
-               break;
-@@ -200,13 +202,14 @@ static int bcma_extpci_write_config(stru
-               val = *((const u32 *)buf);
-               break;
-       }
--      if (dev == 0 && !addr) {
-+      if (dev == 0) {
-               /* accesses to config registers with offsets >= 256
-                * requires indirect access.
-                */
--              addr = (func << 12);
--              addr |= (off & 0x0FFF);
--              bcma_pcie_write_config(pc, addr, val);
-+              if (off >= PCI_CONFIG_SPACE_SIZE)
-+                      bcma_pcie_write_config(pc, addr, val);
-+              else
-+                      pcicore_write32(pc, addr, val);
-       } else {
-               writel(val, mmio);
index c535c05..8741109 100644 (file)
@@ -5,7 +5,7 @@ This prevents the options from being delete with make kernel_oldconfig.
 
 --- a/drivers/bcma/Kconfig
 +++ b/drivers/bcma/Kconfig
-@@ -37,6 +37,7 @@ config BCMA_DRIVER_PCI_HOSTMODE
+@@ -38,6 +38,7 @@ config BCMA_DRIVER_PCI_HOSTMODE
  config BCMA_HOST_SOC
        bool
        depends on BCMA_DRIVER_MIPS
index f1b483e..5013351 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/ssb/embedded.c
 +++ b/drivers/ssb/embedded.c
-@@ -136,6 +136,18 @@ u32 ssb_gpio_polarity(struct ssb_bus *bu
+@@ -170,6 +170,18 @@ u32 ssb_gpio_polarity(struct ssb_bus *bu
  }
  EXPORT_SYMBOL(ssb_gpio_polarity);
  
index 951c6d4..7c4323e 100644 (file)
---- a/drivers/bcma/driver_chipcommon.c
-+++ b/drivers/bcma/driver_chipcommon.c
-@@ -70,6 +70,8 @@ void bcma_core_chipcommon_init(struct bc
-                        (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
-       }
-+      spin_lock_init(&cc->gpio_lock);
-+
-       cc->setup_done = true;
- }
-@@ -92,34 +94,81 @@ u32 bcma_chipco_irq_status(struct bcma_d
- u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask)
- {
--      return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask;
-+      unsigned long flags;
-+      u32 res;
-+
-+      spin_lock_irqsave(&cc->gpio_lock, flags);
-+      res = bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask;
-+      spin_unlock_irqrestore(&cc->gpio_lock, flags);
-+
-+      return res;
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_in);
- u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
- {
--      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
-+      unsigned long flags;
-+      u32 res;
-+
-+      spin_lock_irqsave(&cc->gpio_lock, flags);
-+      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
-+      spin_unlock_irqrestore(&cc->gpio_lock, flags);
-+
-+      return res;
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_out);
- u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
- {
--      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
-+      unsigned long flags;
-+      u32 res;
-+
-+      spin_lock_irqsave(&cc->gpio_lock, flags);
-+      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
-+      spin_unlock_irqrestore(&cc->gpio_lock, flags);
-+
-+      return res;
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen);
- u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
- {
--      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
-+      unsigned long flags;
-+      u32 res;
-+
-+      spin_lock_irqsave(&cc->gpio_lock, flags);
-+      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
-+      spin_unlock_irqrestore(&cc->gpio_lock, flags);
-+
-+      return res;
- }
- EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control);
- u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value)
- {
--      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
-+      unsigned long flags;
-+      u32 res;
-+
-+      spin_lock_irqsave(&cc->gpio_lock, flags);
-+      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
-+      spin_unlock_irqrestore(&cc->gpio_lock, flags);
-+
-+      return res;
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_intmask);
- u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
- {
--      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
-+      unsigned long flags;
-+      u32 res;
-+
-+      spin_lock_irqsave(&cc->gpio_lock, flags);
-+      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
-+      spin_unlock_irqrestore(&cc->gpio_lock, flags);
-+
-+      return res;
- }
-+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_polarity);
- #ifdef CONFIG_BCMA_DRIVER_MIPS
- void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
 --- a/include/linux/bcma/bcma_driver_chipcommon.h
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -495,6 +495,9 @@ struct bcma_drv_cc {
-       int nr_serial_ports;
-       struct bcma_serial_port serial_ports[4];
- #endif /* CONFIG_BCMA_DRIVER_MIPS */
-+
-+      /* Lock for GPIO register access. */
-+      spinlock_t gpio_lock;
- };
- /* Register access */
-@@ -525,13 +528,22 @@ void bcma_chipco_irq_mask(struct bcma_dr
+@@ -678,6 +678,8 @@ void bcma_chipco_irq_mask(struct bcma_dr
  
  u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask);
  
 +#define BCMA_CC_GPIO_LINES    16
 +
  /* Chipcommon GPIO pin access. */
--u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask);
--u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value);
--u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value);
--u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value);
--u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value);
--u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value);
-+extern u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask);
-+extern u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value);
-+extern u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value);
-+extern u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask,
-+                                  u32 value);
-+extern u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask,
-+                                  u32 value);
-+extern u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask,
-+                                   u32 value);
+ u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask);
+ u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value);
+@@ -687,6 +689,10 @@ u32 bcma_chipco_gpio_intmask(struct bcma
+ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value);
+ u32 bcma_chipco_gpio_pullup(struct bcma_drv_cc *cc, u32 mask, u32 value);
+ u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value);
 +static inline int bcma_chipco_gpio_count(void)
 +{
 +      return BCMA_CC_GPIO_LINES;
index e40a621..d9968d2 100644 (file)
  #define PCI_DEVICE_ID_TIGON3_5751     0x1677
  #define PCI_DEVICE_ID_TIGON3_5715     0x1678
  #define PCI_DEVICE_ID_TIGON3_5715S    0x1679
---- a/include/linux/ssb/ssb_driver_gige.h
-+++ b/include/linux/ssb/ssb_driver_gige.h
-@@ -97,21 +97,12 @@ static inline bool ssb_gige_must_flush_p
-       return 0;
- }
--#ifdef CONFIG_BCM47XX
--#include <asm/mach-bcm47xx/nvram.h>
--/* Get the device MAC address */
--static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
--{
--      char buf[20];
--      if (nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0)
--              return;
--      nvram_parse_macaddr(buf, macaddr);
--}
--#else
- static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
- {
-+      struct ssb_gige *dev = pdev_to_ssb_gige(pdev);
-+
-+      memcpy(macaddr, dev->dev->bus->sprom.et0mac, 6);
- }
--#endif
- extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
-                                         struct pci_dev *pdev);
-@@ -175,6 +166,9 @@ static inline bool ssb_gige_must_flush_p
- {
-       return 0;
- }
-+static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
-+{
-+}
- #endif /* CONFIG_SSB_DRIVER_GIGE */
- #endif /* LINUX_SSB_DRIVER_GIGE_H_ */
index eb70c81..0650c25 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/ssb/driver_pcicore.c
 +++ b/drivers/ssb/driver_pcicore.c
-@@ -376,7 +376,7 @@ static void __devinit ssb_pcicore_init_h
+@@ -375,7 +375,7 @@ static void __devinit ssb_pcicore_init_h
        set_io_port_base(ssb_pcicore_controller.io_map_base);
        /* Give some time to the PCI controller to configure itself with the new
         * values. Not waiting at this point causes crashes of the machine. */
index 9c7d946..4f18587 100644 (file)
@@ -193,6 +193,7 @@ CONFIG_BASE_SMALL=0
 # CONFIG_BCM63XX is not set
 # CONFIG_BCM63XX_PHY is not set
 # CONFIG_BCMA is not set
+# CONFIG_BCMA_DRIVER_GPIO is not set
 # CONFIG_BCM_WIMAX is not set
 # CONFIG_BDI_SWITCH is not set
 # CONFIG_BE2ISCSI is not set
@@ -2842,6 +2843,7 @@ CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
 CONFIG_SQUASHFS_XZ=y
 # CONFIG_SQUASHFS_ZLIB is not set
 # CONFIG_SSB is not set
+# CONFIG_SSB_DRIVER_GPIO is not set
 # CONFIG_SSB_DEBUG is not set
 # CONFIG_SSB_PCMCIAHOST is not set
 CONFIG_SSB_POSSIBLE=y
index e427574..8499e81 100644 (file)
@@ -1,6 +1,31 @@
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -160,4 +160,12 @@ config SSB_DRIVER_GIGE
+         If unsure, say N
++config SSB_DRIVER_GPIO
++      bool "SSB GPIO driver"
++      depends on SSB && GPIOLIB
++      help
++        Driver to provide access to the GPIO pins on the bus.
++
++        If unsure, say N
++
+ endmenu
+--- a/drivers/ssb/Makefile
++++ b/drivers/ssb/Makefile
+@@ -15,6 +15,7 @@ ssb-$(CONFIG_SSB_DRIVER_MIPS)                += driver
+ ssb-$(CONFIG_SSB_DRIVER_EXTIF)                += driver_extif.o
+ ssb-$(CONFIG_SSB_DRIVER_PCICORE)      += driver_pcicore.o
+ ssb-$(CONFIG_SSB_DRIVER_GIGE)         += driver_gige.o
++ssb-$(CONFIG_SSB_DRIVER_GPIO)         += driver_gpio.o
+ # b43 pci-ssb-bridge driver
+ # Not strictly a part of SSB, but kept here for convenience
 --- a/drivers/ssb/b43_pci_bridge.c
 +++ b/drivers/ssb/b43_pci_bridge.c
-@@ -29,11 +29,14 @@ static const struct pci_device_id b43_pc
+@@ -29,11 +29,15 @@ static const struct pci_device_id b43_pc
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432b) },
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432c) },
++      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4350) },
        { 0, },
  };
  MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
+--- a/drivers/ssb/driver_chipcommon.c
++++ b/drivers/ssb/driver_chipcommon.c
+@@ -4,6 +4,7 @@
+  *
+  * Copyright 2005, Broadcom Corporation
+  * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
++ * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -12,6 +13,7 @@
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/export.h>
+ #include <linux/pci.h>
++#include <linux/bcm47xx_wdt.h>
+ #include "ssb_private.h"
+@@ -280,13 +282,79 @@ static void calc_fast_powerup_delay(stru
+       cc->fast_pwrup_delay = tmp;
+ }
++static u32 ssb_chipco_alp_clock(struct ssb_chipcommon *cc)
++{
++      if (cc->capabilities & SSB_CHIPCO_CAP_PMU)
++              return ssb_pmu_get_alp_clock(cc);
++
++      return 20000000;
++}
++
++static u32 ssb_chipco_watchdog_get_max_timer(struct ssb_chipcommon *cc)
++{
++      u32 nb;
++
++      if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
++              if (cc->dev->id.revision < 26)
++                      nb = 16;
++              else
++                      nb = (cc->dev->id.revision >= 37) ? 32 : 24;
++      } else {
++              nb = 28;
++      }
++      if (nb == 32)
++              return 0xffffffff;
++      else
++              return (1 << nb) - 1;
++}
++
++u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks)
++{
++      struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt);
++
++      if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB)
++              return 0;
++
++      return ssb_chipco_watchdog_timer_set(cc, ticks);
++}
++
++u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms)
++{
++      struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt);
++      u32 ticks;
++
++      if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB)
++              return 0;
++
++      ticks = ssb_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms);
++      return ticks / cc->ticks_per_ms;
++}
++
++static int ssb_chipco_watchdog_ticks_per_ms(struct ssb_chipcommon *cc)
++{
++      struct ssb_bus *bus = cc->dev->bus;
++
++      if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
++                      /* based on 32KHz ILP clock */
++                      return 32;
++      } else {
++              if (cc->dev->id.revision < 18)
++                      return ssb_clockspeed(bus) / 1000;
++              else
++                      return ssb_chipco_alp_clock(cc) / 1000;
++      }
++}
++
+ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
+ {
+       if (!cc->dev)
+               return; /* We don't have a ChipCommon */
++
++      spin_lock_init(&cc->gpio_lock);
++
+       if (cc->dev->id.revision >= 11)
+               cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
+-      ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
++      ssb_dbg("chipcommon status is 0x%x\n", cc->status);
+       if (cc->dev->id.revision >= 20) {
+               chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0);
+@@ -297,6 +365,11 @@ void ssb_chipcommon_init(struct ssb_chip
+       chipco_powercontrol_init(cc);
+       ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
+       calc_fast_powerup_delay(cc);
++
++      if (cc->dev->bus->bustype == SSB_BUSTYPE_SSB) {
++              cc->ticks_per_ms = ssb_chipco_watchdog_ticks_per_ms(cc);
++              cc->max_timer_ms = ssb_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
++      }
+ }
+ void ssb_chipco_suspend(struct ssb_chipcommon *cc)
+@@ -395,10 +468,27 @@ void ssb_chipco_timing_init(struct ssb_c
+ }
+ /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+-void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
++u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
+ {
+-      /* instant NMI */
+-      chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
++      u32 maxt;
++      enum ssb_clkmode clkmode;
++
++      maxt = ssb_chipco_watchdog_get_max_timer(cc);
++      if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
++              if (ticks == 1)
++                      ticks = 2;
++              else if (ticks > maxt)
++                      ticks = maxt;
++              chipco_write32(cc, SSB_CHIPCO_PMU_WATCHDOG, ticks);
++      } else {
++              clkmode = ticks ? SSB_CLKMODE_FAST : SSB_CLKMODE_DYNAMIC;
++              ssb_chipco_set_clockmode(cc, clkmode);
++              if (ticks > maxt)
++                      ticks = maxt;
++              /* instant NMI */
++              chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
++      }
++      return ticks;
+ }
+ void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value)
+@@ -418,28 +508,93 @@ u32 ssb_chipco_gpio_in(struct ssb_chipco
+ u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
+ {
+-      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
++      unsigned long flags;
++      u32 res = 0;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
+ u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
+ {
+-      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
++      unsigned long flags;
++      u32 res = 0;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
+ u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
+ {
+-      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
++      unsigned long flags;
++      u32 res = 0;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
+ EXPORT_SYMBOL(ssb_chipco_gpio_control);
+ u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
+ {
+-      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
++      unsigned long flags;
++      u32 res = 0;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
+ u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
+ {
+-      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
++      unsigned long flags;
++      u32 res = 0;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
++}
++
++u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value)
++{
++      unsigned long flags;
++      u32 res = 0;
++
++      if (cc->dev->id.revision < 20)
++              return 0xffffffff;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
++}
++
++u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value)
++{
++      unsigned long flags;
++      u32 res = 0;
++
++      if (cc->dev->id.revision < 20)
++              return 0xffffffff;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
+ #ifdef CONFIG_SSB_SERIAL
+@@ -473,12 +628,7 @@ int ssb_chipco_serial_init(struct ssb_ch
+                                      chipco_read32(cc, SSB_CHIPCO_CORECTL)
+                                      | SSB_CHIPCO_CORECTL_UARTCLK0);
+               } else if ((ccrev >= 11) && (ccrev != 15)) {
+-                      /* Fixed ALP clock */
+-                      baud_base = 20000000;
+-                      if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
+-                              /* FIXME: baud_base is different for devices with a PMU */
+-                              SSB_WARN_ON(1);
+-                      }
++                      baud_base = ssb_chipco_alp_clock(cc);
+                       div = 1;
+                       if (ccrev >= 21) {
+                               /* Turn off UART clock before switching clocksource. */
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
 @@ -13,6 +13,9 @@
  #include <linux/delay.h>
  #include <linux/export.h>
 +#ifdef CONFIG_BCM47XX
-+#include <asm/mach-bcm47xx/nvram.h>
++#include <nvram.h>
 +#endif
  
  #include "ssb_private.h"
        if (crystalfreq)
                e = pmu0_plltab_find_entry(crystalfreq);
        if (!e)
+@@ -111,8 +110,8 @@ static void ssb_pmu0_pllinit_r0(struct s
+               return;
+       }
+-      ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
+-                 (crystalfreq / 1000), (crystalfreq % 1000));
++      ssb_info("Programming PLL to %u.%03u MHz\n",
++               crystalfreq / 1000, crystalfreq % 1000);
+       /* First turn the PLL off. */
+       switch (bus->chip_id) {
+@@ -139,7 +138,7 @@ static void ssb_pmu0_pllinit_r0(struct s
+       }
+       tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
+       if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
+-              ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
++              ssb_emerg("Failed to turn the PLL off!\n");
+       /* Set PDIV in PLL control 0. */
+       pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0);
+@@ -250,8 +249,8 @@ static void ssb_pmu1_pllinit_r0(struct s
+               return;
+       }
+-      ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
+-                 (crystalfreq / 1000), (crystalfreq % 1000));
++      ssb_info("Programming PLL to %u.%03u MHz\n",
++               crystalfreq / 1000, crystalfreq % 1000);
+       /* First turn the PLL off. */
+       switch (bus->chip_id) {
+@@ -276,7 +275,7 @@ static void ssb_pmu1_pllinit_r0(struct s
+       }
+       tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
+       if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
+-              ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
++              ssb_emerg("Failed to turn the PLL off!\n");
+       /* Set p1div and p2div. */
+       pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0);
 @@ -321,7 +320,11 @@ static void ssb_pmu_pll_init(struct ssb_
        u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */
  
                ssb_pmu0_pllinit_r0(cc, crystalfreq);
                break;
        case 0x4322:
-@@ -607,3 +614,34 @@ void ssb_pmu_set_ldo_paref(struct ssb_ch
+@@ -339,10 +346,11 @@ static void ssb_pmu_pll_init(struct ssb_
+                       chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);
+               }
+               break;
++      case 43222:
++              break;
+       default:
+-              ssb_printk(KERN_ERR PFX
+-                         "ERROR: PLL init unknown for device %04X\n",
+-                         bus->chip_id);
++              ssb_err("ERROR: PLL init unknown for device %04X\n",
++                      bus->chip_id);
+       }
+ }
+@@ -427,6 +435,7 @@ static void ssb_pmu_resources_init(struc
+                min_msk = 0xCBB;
+                break;
+       case 0x4322:
++      case 43222:
+               /* We keep the default settings:
+                * min_msk = 0xCBB
+                * max_msk = 0x7FFFF
+@@ -462,9 +471,8 @@ static void ssb_pmu_resources_init(struc
+               max_msk = 0xFFFFF;
+               break;
+       default:
+-              ssb_printk(KERN_ERR PFX
+-                         "ERROR: PMU resource config unknown for device %04X\n",
+-                         bus->chip_id);
++              ssb_err("ERROR: PMU resource config unknown for device %04X\n",
++                      bus->chip_id);
+       }
+       if (updown_tab) {
+@@ -516,8 +524,8 @@ void ssb_pmu_init(struct ssb_chipcommon
+       pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP);
+       cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION);
+-      ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
+-                  cc->pmu.rev, pmucap);
++      ssb_dbg("Found rev %u PMU (capabilities 0x%08X)\n",
++              cc->pmu.rev, pmucap);
+       if (cc->pmu.rev == 1)
+               chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
+@@ -607,3 +615,102 @@ void ssb_pmu_set_ldo_paref(struct ssb_ch
+ EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
+ EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
++
++static u32 ssb_pmu_get_alp_clock_clk0(struct ssb_chipcommon *cc)
++{
++      u32 crystalfreq;
++      const struct pmu0_plltab_entry *e = NULL;
++
++      crystalfreq = chipco_read32(cc, SSB_CHIPCO_PMU_CTL) &
++                    SSB_CHIPCO_PMU_CTL_XTALFREQ >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT;
++      e = pmu0_plltab_find_entry(crystalfreq);
++      BUG_ON(!e);
++      return e->freq * 1000;
++}
++
++u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc)
++{
++      struct ssb_bus *bus = cc->dev->bus;
++
++      switch (bus->chip_id) {
++      case 0x5354:
++              ssb_pmu_get_alp_clock_clk0(cc);
++      default:
++              ssb_err("ERROR: PMU alp clock unknown for device %04X\n",
++                      bus->chip_id);
++              return 0;
++      }
++}
++
++u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc)
++{
++      struct ssb_bus *bus = cc->dev->bus;
++
++      switch (bus->chip_id) {
++      case 0x5354:
++              /* 5354 chip uses a non programmable PLL of frequency 240MHz */
++              return 240000000;
++      default:
++              ssb_err("ERROR: PMU cpu clock unknown for device %04X\n",
++                      bus->chip_id);
++              return 0;
++      }
++}
++
++u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc)
++{
++      struct ssb_bus *bus = cc->dev->bus;
++
++      switch (bus->chip_id) {
++      case 0x5354:
++              return 120000000;
++      default:
++              ssb_err("ERROR: PMU controlclock unknown for device %04X\n",
++                      bus->chip_id);
++              return 0;
++      }
++}
++
++void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid)
++{
++      u32 pmu_ctl = 0;
++
++      switch (cc->dev->bus->chip_id) {
++      case 0x4322:
++              ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100070);
++              ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x1014140a);
++              ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888854);
++              if (spuravoid == 1)
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05201828);
++              else
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05001828);
++              pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
++              break;
++      case 43222:
++              if (spuravoid == 1) {
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11500008);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0C000C06);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x0F600a08);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x2001E920);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888815);
++              } else {
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100008);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0c000c06);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x03000a08);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x200005c0);
++                      ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888855);
++              }
++              pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
++              break;
++      default:
++              ssb_printk(KERN_ERR PFX
++                         "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
++                         cc->dev->bus->chip_id);
++              return;
++      }
++
++      chipco_set32(cc, SSB_CHIPCO_PMU_CTL, pmu_ctl);
++}
++EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate);
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -112,10 +112,37 @@ void ssb_extif_get_clockcontrol(struct s
+       *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
+ }
+-void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
+-                                u32 ticks)
++u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks)
+ {
++      struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt);
++
++      return ssb_extif_watchdog_timer_set(extif, ticks);
++}
++
++u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms)
++{
++      struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt);
++      u32 ticks = (SSB_EXTIF_WATCHDOG_CLK / 1000) * ms;
++
++      ticks = ssb_extif_watchdog_timer_set(extif, ticks);
++
++      return (ticks * 1000) / SSB_EXTIF_WATCHDOG_CLK;
++}
++
++u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks)
++{
++      if (ticks > SSB_EXTIF_WATCHDOG_MAX_TIMER)
++              ticks = SSB_EXTIF_WATCHDOG_MAX_TIMER;
+       extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks);
++
++      return ticks;
++}
++
++void ssb_extif_init(struct ssb_extif *extif)
++{
++      if (!extif->dev)
++              return; /* We don't have a Extif core */
++      spin_lock_init(&extif->gpio_lock);
+ }
+ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
+@@ -125,22 +152,50 @@ u32 ssb_extif_gpio_in(struct ssb_extif *
+ u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
+ {
+-      return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
++      unsigned long flags;
++      u32 res = 0;
++
++      spin_lock_irqsave(&extif->gpio_lock, flags);
++      res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
+                                  mask, value);
++      spin_unlock_irqrestore(&extif->gpio_lock, flags);
++
++      return res;
+ }
+ u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
+ {
+-      return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
++      unsigned long flags;
++      u32 res = 0;
++
++      spin_lock_irqsave(&extif->gpio_lock, flags);
++      res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
+                                  mask, value);
++      spin_unlock_irqrestore(&extif->gpio_lock, flags);
++
++      return res;
+ }
+ u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)
+ {
+-      return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
++      unsigned long flags;
++      u32 res = 0;
++
++      spin_lock_irqsave(&extif->gpio_lock, flags);
++      res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
++      spin_unlock_irqrestore(&extif->gpio_lock, flags);
++
++      return res;
+ }
+ u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)
+ {
+-      return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
++      unsigned long flags;
++      u32 res = 0;
++
++      spin_lock_irqsave(&extif->gpio_lock, flags);
++      res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
++      spin_unlock_irqrestore(&extif->gpio_lock, flags);
++
++      return res;
+ }
+--- /dev/null
++++ b/drivers/ssb/driver_gpio.c
+@@ -0,0 +1,210 @@
++/*
++ * Sonics Silicon Backplane
++ * GPIO driver
++ *
++ * Copyright 2011, Broadcom Corporation
++ * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/gpio.h>
++#include <linux/export.h>
++#include <linux/ssb/ssb.h>
++
++#include "ssb_private.h"
++
++static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip)
++{
++      return container_of(chip, struct ssb_bus, gpio);
++}
++
++static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      return !!ssb_chipco_gpio_in(&bus->chipco, 1 << gpio);
++}
++
++static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio,
++                                    int value)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
++}
++
++static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip,
++                                         unsigned gpio)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 0);
++      return 0;
++}
++
++static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip,
++                                          unsigned gpio, int value)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 1 << gpio);
++      ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
++      return 0;
++}
++
++static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      ssb_chipco_gpio_control(&bus->chipco, 1 << gpio, 0);
++      /* clear pulldown */
++      ssb_chipco_gpio_pulldown(&bus->chipco, 1 << gpio, 0);
++      /* Set pullup */
++      ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 1 << gpio);
++
++      return 0;
++}
++
++static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      /* clear pullup */
++      ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0);
++}
++
++static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      if (bus->bustype == SSB_BUSTYPE_SSB)
++              return ssb_mips_irq(bus->chipco.dev) + 2;
++      else
++              return -EINVAL;
++}
++
++static int ssb_gpio_chipco_init(struct ssb_bus *bus)
++{
++      struct gpio_chip *chip = &bus->gpio;
++
++      chip->label             = "ssb_chipco_gpio";
++      chip->owner             = THIS_MODULE;
++      chip->request           = ssb_gpio_chipco_request;
++      chip->free              = ssb_gpio_chipco_free;
++      chip->get               = ssb_gpio_chipco_get_value;
++      chip->set               = ssb_gpio_chipco_set_value;
++      chip->direction_input   = ssb_gpio_chipco_direction_input;
++      chip->direction_output  = ssb_gpio_chipco_direction_output;
++      chip->to_irq            = ssb_gpio_chipco_to_irq;
++      chip->ngpio             = 16;
++      /* There is just one SoC in one device and its GPIO addresses should be
++       * deterministic to address them more easily. The other buses could get
++       * a random base number. */
++      if (bus->bustype == SSB_BUSTYPE_SSB)
++              chip->base              = 0;
++      else
++              chip->base              = -1;
++
++      return gpiochip_add(chip);
++}
++
++#ifdef CONFIG_SSB_DRIVER_EXTIF
++
++static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio);
++}
++
++static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio,
++                                   int value)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
++}
++
++static int ssb_gpio_extif_direction_input(struct gpio_chip *chip,
++                                        unsigned gpio)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 0);
++      return 0;
++}
++
++static int ssb_gpio_extif_direction_output(struct gpio_chip *chip,
++                                         unsigned gpio, int value)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 1 << gpio);
++      ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
++      return 0;
++}
++
++static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio)
++{
++      struct ssb_bus *bus = ssb_gpio_get_bus(chip);
++
++      if (bus->bustype == SSB_BUSTYPE_SSB)
++              return ssb_mips_irq(bus->extif.dev) + 2;
++      else
++              return -EINVAL;
++}
++
++static int ssb_gpio_extif_init(struct ssb_bus *bus)
++{
++      struct gpio_chip *chip = &bus->gpio;
++
++      chip->label             = "ssb_extif_gpio";
++      chip->owner             = THIS_MODULE;
++      chip->get               = ssb_gpio_extif_get_value;
++      chip->set               = ssb_gpio_extif_set_value;
++      chip->direction_input   = ssb_gpio_extif_direction_input;
++      chip->direction_output  = ssb_gpio_extif_direction_output;
++      chip->to_irq            = ssb_gpio_extif_to_irq;
++      chip->ngpio             = 5;
++      /* There is just one SoC in one device and its GPIO addresses should be
++       * deterministic to address them more easily. The other buses could get
++       * a random base number. */
++      if (bus->bustype == SSB_BUSTYPE_SSB)
++              chip->base              = 0;
++      else
++              chip->base              = -1;
++
++      return gpiochip_add(chip);
++}
++
++#else
++static int ssb_gpio_extif_init(struct ssb_bus *bus)
++{
++      return -ENOTSUPP;
++}
++#endif
++
++int ssb_gpio_init(struct ssb_bus *bus)
++{
++      if (ssb_chipco_available(&bus->chipco))
++              return ssb_gpio_chipco_init(bus);
++      else if (ssb_extif_available(&bus->extif))
++              return ssb_gpio_extif_init(bus);
++      else
++              SSB_WARN_ON(1);
++
++      return -1;
++}
++
++int ssb_gpio_unregister(struct ssb_bus *bus)
++{
++      if (ssb_chipco_available(&bus->chipco) ||
++          ssb_extif_available(&bus->extif)) {
++              return gpiochip_remove(&bus->gpio);
++      } else {
++              SSB_WARN_ON(1);
++      }
++
++      return -1;
++}
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -17,7 +17,6 @@
+ #include "ssb_private.h"
+-
+ static inline u32 mips_read32(struct ssb_mipscore *mcore,
+                             u16 offset)
+ {
+@@ -147,21 +146,22 @@ static void set_irq(struct ssb_device *d
+               irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
+               ssb_write32(mdev, SSB_IPSFLAG, irqflag);
+       }
+-      ssb_dprintk(KERN_INFO PFX
+-                  "set_irq: core 0x%04x, irq %d => %d\n",
+-                  dev->id.coreid, oldirq+2, irq+2);
++      ssb_dbg("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.coreid, oldirq+2, irq+2);
+ }
+ static void print_irq(struct ssb_device *dev, unsigned int irq)
+ {
+-      int i;
+       static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
+-      ssb_dprintk(KERN_INFO PFX
+-              "core 0x%04x, irq :", dev->id.coreid);
+-      for (i = 0; i <= 6; i++) {
+-              ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
+-      }
+-      ssb_dprintk("\n");
++      ssb_dbg("core 0x%04x, irq : %s%s %s%s %s%s %s%s %s%s %s%s %s%s\n",
++              dev->id.coreid,
++              irq_name[0], irq == 0 ? "*" : " ",
++              irq_name[1], irq == 1 ? "*" : " ",
++              irq_name[2], irq == 2 ? "*" : " ",
++              irq_name[3], irq == 3 ? "*" : " ",
++              irq_name[4], irq == 4 ? "*" : " ",
++              irq_name[5], irq == 5 ? "*" : " ",
++              irq_name[6], irq == 6 ? "*" : " ");
+ }
+ static void dump_irq(struct ssb_bus *bus)
+@@ -178,9 +178,9 @@ static void ssb_mips_serial_init(struct
+ {
+       struct ssb_bus *bus = mcore->dev->bus;
+-      if (bus->extif.dev)
++      if (ssb_extif_available(&bus->extif))
+               mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
+-      else if (bus->chipco.dev)
++      else if (ssb_chipco_available(&bus->chipco))
+               mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
+       else
+               mcore->nr_serial_ports = 0;
+@@ -191,7 +191,7 @@ static void ssb_mips_flash_detect(struct
+       struct ssb_bus *bus = mcore->dev->bus;
+       mcore->flash_buswidth = 2;
+-      if (bus->chipco.dev) {
++      if (ssb_chipco_available(&bus->chipco)) {
+               mcore->flash_window = 0x1c000000;
+               mcore->flash_window_size = 0x02000000;
+               if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
+@@ -208,9 +208,12 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
+       struct ssb_bus *bus = mcore->dev->bus;
+       u32 pll_type, n, m, rate = 0;
+-      if (bus->extif.dev) {
++      if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)
++              return ssb_pmu_get_cpu_clock(&bus->chipco);
++
++      if (ssb_extif_available(&bus->extif)) {
+               ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
+-      } else if (bus->chipco.dev) {
++      } else if (ssb_chipco_available(&bus->chipco)) {
+               ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
+       } else
+               return 0;
+@@ -238,7 +241,7 @@ void ssb_mipscore_init(struct ssb_mipsco
+       if (!mcore->dev)
+               return; /* We don't have a MIPS core */
+-      ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
++      ssb_dbg("Initializing MIPS core...\n");
+       bus = mcore->dev->bus;
+       hz = ssb_clockspeed(bus);
+@@ -246,9 +249,9 @@ void ssb_mipscore_init(struct ssb_mipsco
+               hz = 100000000;
+       ns = 1000000000 / hz;
+-      if (bus->extif.dev)
++      if (ssb_extif_available(&bus->extif))
+               ssb_extif_timing_init(&bus->extif, ns);
+-      else if (bus->chipco.dev)
++      else if (ssb_chipco_available(&bus->chipco))
+               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 */
+@@ -286,7 +289,7 @@ void ssb_mipscore_init(struct ssb_mipsco
+                       break;
+               }
+       }
+-      ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
++      ssb_dbg("after irq reconfiguration\n");
+       dump_irq(bus);
+       ssb_mips_serial_init(mcore);
+--- a/drivers/ssb/driver_pcicore.c
++++ b/drivers/ssb/driver_pcicore.c
+@@ -263,8 +263,7 @@ int ssb_pcicore_plat_dev_init(struct pci
+               return -ENODEV;
+       }
+-      ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
+-                 pci_name(d));
++      ssb_info("PCI: Fixing up device %s\n", pci_name(d));
+       /* Fix up interrupt lines */
+       d->irq = ssb_mips_irq(extpci_core->dev) + 2;
+@@ -285,12 +284,12 @@ static void ssb_pcicore_fixup_pcibridge(
+       if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
+               return;
+-      ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
++      ssb_info("PCI: Fixing up bridge %s\n", pci_name(dev));
+       /* Enable PCI bridge bus mastering and memory space */
+       pci_set_master(dev);
+       if (pcibios_enable_device(dev, ~0) < 0) {
+-              ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
++              ssb_err("PCI: SSB bridge enable failed\n");
+               return;
+       }
+@@ -299,8 +298,8 @@ static void ssb_pcicore_fixup_pcibridge(
+       /* Make sure our latency is high enough to handle the devices behind us */
+       lat = 168;
+-      ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
+-                 pci_name(dev), lat);
++      ssb_info("PCI: Fixing latency timer of device %s to %u\n",
++               pci_name(dev), lat);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+ }
+ DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge);
+@@ -323,7 +322,7 @@ static void __devinit ssb_pcicore_init_h
+               return;
+       extpci_core = pc;
+-      ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n");
++      ssb_dbg("PCIcore in host mode found\n");
+       /* Reset devices on the external PCI bus */
+       val = SSB_PCICORE_CTL_RST_OE;
+       val |= SSB_PCICORE_CTL_CLK_OE;
+@@ -338,7 +337,7 @@ static void __devinit ssb_pcicore_init_h
+       udelay(1); /* Assertion time demanded by the PCI standard */
+       if (pc->dev->bus->has_cardbus_slot) {
+-              ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n");
++              ssb_dbg("CardBus slot detected\n");
+               pc->cardbusmode = 1;
+               /* GPIO 1 resets the bridge */
+               ssb_gpio_out(pc->dev->bus, 1, 1);
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -4,11 +4,13 @@
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+  * Copyright 2006-2008, Michael Buesch <m@bues.ch>
++ * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/export.h>
++#include <linux/platform_device.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_embedded.h>
+ #include <linux/ssb/ssb_driver_pci.h>
+@@ -32,6 +34,38 @@ int ssb_watchdog_timer_set(struct ssb_bu
+ }
+ EXPORT_SYMBOL(ssb_watchdog_timer_set);
  
- EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
- EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
-+
-+u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc)
++int ssb_watchdog_register(struct ssb_bus *bus)
 +{
-+      struct ssb_bus *bus = cc->dev->bus;
++      struct bcm47xx_wdt wdt = {};
++      struct platform_device *pdev;
 +
-+      switch (bus->chip_id) {
-+      case 0x5354:
-+              /* 5354 chip uses a non programmable PLL of frequency 240MHz */
-+              return 240000000;
-+      default:
-+              ssb_printk(KERN_ERR PFX
-+                         "ERROR: PMU cpu clock unknown for device %04X\n",
-+                         bus->chip_id);
-+              return 0;
++      if (ssb_chipco_available(&bus->chipco)) {
++              wdt.driver_data = &bus->chipco;
++              wdt.timer_set = ssb_chipco_watchdog_timer_set_wdt;
++              wdt.timer_set_ms = ssb_chipco_watchdog_timer_set_ms;
++              wdt.max_timer_ms = bus->chipco.max_timer_ms;
++      } else if (ssb_extif_available(&bus->extif)) {
++              wdt.driver_data = &bus->extif;
++              wdt.timer_set = ssb_extif_watchdog_timer_set_wdt;
++              wdt.timer_set_ms = ssb_extif_watchdog_timer_set_ms;
++              wdt.max_timer_ms = SSB_EXTIF_WATCHDOG_MAX_TIMER_MS;
++      } else {
++              return -ENODEV;
 +      }
-+}
-+
-+u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc)
-+{
-+      struct ssb_bus *bus = cc->dev->bus;
 +
-+      switch (bus->chip_id) {
-+      case 0x5354:
-+              return 120000000;
-+      default:
-+              ssb_printk(KERN_ERR PFX
-+                         "ERROR: PMU controlclock unknown for device %04X\n",
-+                         bus->chip_id);
-+              return 0;
++      pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
++                                           bus->busnumber, &wdt,
++                                           sizeof(wdt));
++      if (IS_ERR(pdev)) {
++              ssb_dbg("can not register watchdog device, err: %li\n",
++                      PTR_ERR(pdev));
++              return PTR_ERR(pdev);
 +      }
++
++      bus->watchdog = pdev;
++      return 0;
 +}
---- a/drivers/ssb/driver_mipscore.c
-+++ b/drivers/ssb/driver_mipscore.c
-@@ -208,6 +208,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
-       struct ssb_bus *bus = mcore->dev->bus;
-       u32 pll_type, n, m, rate = 0;
-+      if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)
-+              return ssb_pmu_get_cpu_clock(&bus->chipco);
 +
-       if (bus->extif.dev) {
-               ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
-       } else if (bus->chipco.dev) {
+ u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask)
+ {
+       unsigned long flags;
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -140,19 +140,6 @@ static void ssb_device_put(struct ssb_de
+@@ -13,6 +13,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
++#include <linux/platform_device.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/ssb/ssb_driver_gige.h>
+@@ -140,19 +141,6 @@ static void ssb_device_put(struct ssb_de
                put_device(dev->dev);
  }
  
  static int ssb_device_resume(struct device *dev)
  {
        struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
-@@ -250,11 +237,9 @@ int ssb_devices_freeze(struct ssb_bus *b
+@@ -250,11 +238,9 @@ int ssb_devices_freeze(struct ssb_bus *b
                        ssb_device_put(sdev);
                        continue;
                }
                sdrv->remove(sdev);
                ctx->device_frozen[i] = 1;
        }
-@@ -293,7 +278,6 @@ int ssb_devices_thaw(struct ssb_freeze_c
-                                  dev_name(sdev->dev));
+@@ -289,11 +275,10 @@ int ssb_devices_thaw(struct ssb_freeze_c
+               err = sdrv->probe(sdev, &sdev->id);
+               if (err) {
+-                      ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
+-                                 dev_name(sdev->dev));
++                      ssb_err("Failed to thaw device %s\n",
++                              dev_name(sdev->dev));
                        result = err;
                }
 -              ssb_driver_put(sdrv);
                ssb_device_put(sdev);
        }
  
-@@ -1094,6 +1078,9 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
+@@ -449,10 +434,23 @@ static void ssb_devices_unregister(struc
+               if (sdev->dev)
+                       device_unregister(sdev->dev);
+       }
++
++#ifdef CONFIG_SSB_EMBEDDED
++      if (bus->bustype == SSB_BUSTYPE_SSB)
++              platform_device_unregister(bus->watchdog);
++#endif
+ }
+ void ssb_bus_unregister(struct ssb_bus *bus)
+ {
++      int err;
++
++      err = ssb_gpio_unregister(bus);
++      if (err == -EBUSY)
++              ssb_dbg("Some GPIOs are still in use\n");
++      else if (err)
++              ssb_dbg("Can not unregister GPIO driver: %i\n", err);
++
+       ssb_buses_lock();
+       ssb_devices_unregister(bus);
+       list_del(&bus->list);
+@@ -498,8 +496,7 @@ static int ssb_devices_register(struct s
+               devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL);
+               if (!devwrap) {
+-                      ssb_printk(KERN_ERR PFX
+-                                 "Could not allocate device\n");
++                      ssb_err("Could not allocate device\n");
+                       err = -ENOMEM;
+                       goto error;
+               }
+@@ -538,9 +535,7 @@ static int ssb_devices_register(struct s
+               sdev->dev = dev;
+               err = device_register(dev);
+               if (err) {
+-                      ssb_printk(KERN_ERR PFX
+-                                 "Could not register %s\n",
+-                                 dev_name(dev));
++                      ssb_err("Could not register %s\n", dev_name(dev));
+                       /* Set dev to NULL to not unregister
+                        * dev on error unwinding. */
+                       sdev->dev = NULL;
+@@ -577,6 +572,8 @@ static int __devinit ssb_attach_queued_b
+               if (err)
+                       goto error;
+               ssb_pcicore_init(&bus->pcicore);
++              if (bus->bustype == SSB_BUSTYPE_SSB)
++                      ssb_watchdog_register(bus);
+               ssb_bus_may_powerdown(bus);
+               err = ssb_devices_register(bus);
+@@ -812,7 +809,13 @@ static int __devinit ssb_bus_register(st
+       if (err)
+               goto err_pcmcia_exit;
+       ssb_chipcommon_init(&bus->chipco);
++      ssb_extif_init(&bus->extif);
+       ssb_mipscore_init(&bus->mipscore);
++      err = ssb_gpio_init(bus);
++      if (err == -ENOTSUPP)
++              ssb_dbg("GPIO driver not activated\n");
++      else if (err)
++              ssb_dbg("Error registering GPIO driver: %i\n", err);
+       err = ssb_fetch_invariants(bus, get_invariants);
+       if (err) {
+               ssb_bus_may_powerdown(bus);
+@@ -863,11 +866,11 @@ int __devinit ssb_bus_pcibus_register(st
+       err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);
+       if (!err) {
+-              ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+-                         "PCI device %s\n", dev_name(&host_pci->dev));
++              ssb_info("Sonics Silicon Backplane found on PCI device %s\n",
++                       dev_name(&host_pci->dev));
+       } else {
+-              ssb_printk(KERN_ERR PFX "Failed to register PCI version"
+-                         " of SSB with error %d\n", err);
++              ssb_err("Failed to register PCI version of SSB with error %d\n",
++                      err);
+       }
+       return err;
+@@ -888,8 +891,8 @@ int __devinit ssb_bus_pcmciabus_register
+       err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr);
+       if (!err) {
+-              ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+-                         "PCMCIA device %s\n", pcmcia_dev->devname);
++              ssb_info("Sonics Silicon Backplane found on PCMCIA device %s\n",
++                       pcmcia_dev->devname);
+       }
+       return err;
+@@ -911,8 +914,8 @@ int __devinit ssb_bus_sdiobus_register(s
+       err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0);
+       if (!err) {
+-              ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+-                         "SDIO device %s\n", sdio_func_id(func));
++              ssb_info("Sonics Silicon Backplane found on SDIO device %s\n",
++                       sdio_func_id(func));
+       }
+       return err;
+@@ -931,8 +934,8 @@ int __devinit ssb_bus_ssbbus_register(st
+       err = ssb_bus_register(bus, get_invariants, baseaddr);
+       if (!err) {
+-              ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at "
+-                         "address 0x%08lX\n", baseaddr);
++              ssb_info("Sonics Silicon Backplane found at address 0x%08lX\n",
++                       baseaddr);
+       }
+       return err;
+@@ -1094,6 +1097,9 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
        u32 plltype;
        u32 clkctl_n, clkctl_m;
  
        if (ssb_extif_available(&bus->extif))
                ssb_extif_get_clockcontrol(&bus->extif, &plltype,
                                           &clkctl_n, &clkctl_m);
+@@ -1131,8 +1137,7 @@ static u32 ssb_tmslow_reject_bitmask(str
+       case SSB_IDLOW_SSBREV_27:     /* same here */
+               return SSB_TMSLOW_REJECT;       /* this is a guess */
+       default:
+-              printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
+-              WARN_ON(1);
++              WARN(1, KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
+       }
+       return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
+ }
+@@ -1324,7 +1329,7 @@ out:
+ #endif
+       return err;
+ error:
+-      ssb_printk(KERN_ERR PFX "Bus powerdown failed\n");
++      ssb_err("Bus powerdown failed\n");
+       goto out;
+ }
+ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+@@ -1347,7 +1352,7 @@ int ssb_bus_powerup(struct ssb_bus *bus,
+       return 0;
+ error:
+-      ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
++      ssb_err("Bus powerup failed\n");
+       return err;
+ }
+ EXPORT_SYMBOL(ssb_bus_powerup);
+@@ -1455,15 +1460,13 @@ static int __init ssb_modinit(void)
+       err = b43_pci_ssb_bridge_init();
+       if (err) {
+-              ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
+-                         "initialization failed\n");
++              ssb_err("Broadcom 43xx PCI-SSB-bridge initialization failed\n");
+               /* don't fail SSB init because of this */
+               err = 0;
+       }
+       err = ssb_gige_init();
+       if (err) {
+-              ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet "
+-                         "driver initialization failed\n");
++              ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n");
+               /* don't fail SSB init because of this */
+               err = 0;
+       }
 --- a/drivers/ssb/pci.c
 +++ b/drivers/ssb/pci.c
-@@ -178,6 +178,18 @@ err_pci:
+@@ -56,7 +56,7 @@ int ssb_pci_switch_coreidx(struct ssb_bu
+       }
+       return 0;
+ error:
+-      ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
++      ssb_err("Failed to switch to core %u\n", coreidx);
+       return -ENODEV;
+ }
+@@ -67,10 +67,9 @@ int ssb_pci_switch_core(struct ssb_bus *
+       unsigned long flags;
+ #if SSB_VERBOSE_PCICORESWITCH_DEBUG
+-      ssb_printk(KERN_INFO PFX
+-                 "Switching to %s core, index %d\n",
+-                 ssb_core_name(dev->id.coreid),
+-                 dev->core_index);
++      ssb_info("Switching to %s core, index %d\n",
++               ssb_core_name(dev->id.coreid),
++               dev->core_index);
+ #endif
+       spin_lock_irqsave(&bus->bar_lock, flags);
+@@ -178,6 +177,18 @@ err_pci:
  #define SPEX(_outvar, _offset, _mask, _shift) \
        SPEX16(_outvar, _offset, _mask, _shift)
  
  
  static inline u8 ssb_crc8(u8 crc, u8 data)
  {
-@@ -331,7 +343,6 @@ static void sprom_extract_r123(struct ss
+@@ -219,6 +230,15 @@ static inline u8 ssb_crc8(u8 crc, u8 dat
+       return t[crc ^ data];
+ }
++static void sprom_get_mac(char *mac, const u16 *in)
++{
++      int i;
++      for (i = 0; i < 3; i++) {
++              *mac++ = in[i] >> 8;
++              *mac++ = in[i];
++      }
++}
++
+ static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
  {
-       int i;
-       u16 v;
+       int word;
+@@ -266,7 +286,7 @@ static int sprom_do_write(struct ssb_bus
+       u32 spromctl;
+       u16 size = bus->sprom_size;
+-      ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
++      ssb_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+       err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
+       if (err)
+               goto err_ctlreg;
+@@ -274,17 +294,17 @@ static int sprom_do_write(struct ssb_bus
+       err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
+       if (err)
+               goto err_ctlreg;
+-      ssb_printk(KERN_NOTICE PFX "[ 0%%");
++      ssb_notice("[ 0%%");
+       msleep(500);
+       for (i = 0; i < size; i++) {
+               if (i == size / 4)
+-                      ssb_printk("25%%");
++                      ssb_cont("25%%");
+               else if (i == size / 2)
+-                      ssb_printk("50%%");
++                      ssb_cont("50%%");
+               else if (i == (size * 3) / 4)
+-                      ssb_printk("75%%");
++                      ssb_cont("75%%");
+               else if (i % 2)
+-                      ssb_printk(".");
++                      ssb_cont(".");
+               writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
+               mmiowb();
+               msleep(20);
+@@ -297,12 +317,12 @@ static int sprom_do_write(struct ssb_bus
+       if (err)
+               goto err_ctlreg;
+       msleep(500);
+-      ssb_printk("100%% ]\n");
+-      ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
++      ssb_cont("100%% ]\n");
++      ssb_notice("SPROM written\n");
+       return 0;
+ err_ctlreg:
+-      ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
++      ssb_err("Could not access SPROM control register.\n");
+       return err;
+ }
+@@ -327,11 +347,23 @@ static s8 r123_extract_antgain(u8 sprom_
+       return (s8)gain;
+ }
++static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in)
++{
++      SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
++      SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
++      SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
++      SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
++      SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
++      SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
++      SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
++      SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
++      SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
++      SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
++           SSB_SPROM2_MAXP_A_LO_SHIFT);
++}
++
+ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
+ {
+-      int i;
+-      u16 v;
 -      s8 gain;
        u16 loc[3];
  
        if (out->revision == 3)                 /* rev 3 moved MAC */
-@@ -361,8 +372,9 @@ static void sprom_extract_r123(struct ss
+@@ -341,19 +373,10 @@ static void sprom_extract_r123(struct ss
+               loc[1] = SSB_SPROM1_ET0MAC;
+               loc[2] = SSB_SPROM1_ET1MAC;
+       }
+-      for (i = 0; i < 3; i++) {
+-              v = in[SPOFF(loc[0]) + i];
+-              *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
+-      }
++      sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);
+       if (out->revision < 3) {        /* only rev 1-2 have et0, et1 */
+-              for (i = 0; i < 3; i++) {
+-                      v = in[SPOFF(loc[1]) + i];
+-                      *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
+-              }
+-              for (i = 0; i < 3; i++) {
+-                      v = in[SPOFF(loc[2]) + i];
+-                      *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
+-              }
++              sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]);
++              sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);
+       }
+       SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
+       SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
+@@ -361,8 +384,10 @@ static void sprom_extract_r123(struct ss
        SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
        SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
        SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
 -      SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
 -           SSB_SPROM1_BINF_CCODE_SHIFT);
++      SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
 +      if (out->revision == 1)
 +              SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
 +                   SSB_SPROM1_BINF_CCODE_SHIFT);
        SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
             SSB_SPROM1_BINF_ANTA_SHIFT);
        SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
-@@ -388,22 +400,16 @@ static void sprom_extract_r123(struct ss
+@@ -386,24 +411,19 @@ static void sprom_extract_r123(struct ss
+            SSB_SPROM1_ITSSI_A_SHIFT);
+       SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
        SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
-       if (out->revision >= 2)
-               SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
+-      if (out->revision >= 2)
+-              SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
++
 +      SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
 +      SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
  
 +      out->antenna_gain.a1 = r123_extract_antgain(out->revision, in,
 +                                                  SSB_SPROM1_AGAIN_A,
 +                                                  SSB_SPROM1_AGAIN_A_SHIFT);
++      if (out->revision >= 2)
++              sprom_extract_r23(out, in);
  }
  
  /* Revs 4 5 and 8 have partially shared layout */
-@@ -464,14 +470,17 @@ static void sprom_extract_r45(struct ssb
+@@ -448,30 +468,30 @@ static void sprom_extract_r458(struct ss
+ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
+ {
+-      int i;
+-      u16 v;
+       u16 il0mac_offset;
+       if (out->revision == 4)
+               il0mac_offset = SSB_SPROM4_IL0MAC;
+       else
+               il0mac_offset = SSB_SPROM5_IL0MAC;
+-      /* extract the MAC address */
+-      for (i = 0; i < 3; i++) {
+-              v = in[SPOFF(il0mac_offset) + i];
+-              *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
+-      }
++
++      sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]);
++
        SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
        SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
             SSB_SPROM4_ETHPHY_ET1A_SHIFT);
 +      SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
++      SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
        if (out->revision == 4) {
 -              SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
 +              SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
                SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
                SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
                SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
-@@ -504,16 +513,14 @@ static void sprom_extract_r45(struct ssb
+@@ -504,16 +524,14 @@ static void sprom_extract_r45(struct ssb
        }
  
        /* Extract the antenna gain values. */
  
        sprom_extract_r458(out, in);
  
-@@ -523,14 +530,22 @@ static void sprom_extract_r45(struct ssb
+@@ -523,14 +541,21 @@ static void sprom_extract_r45(struct ssb
  static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
  {
        int i;
 -      u16 v;
-+      u16 v, o;
++      u16 o;
 +      u16 pwr_info_offset[] = {
 +              SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
 +              SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
 +                      ARRAY_SIZE(out->core_pwr_info));
  
        /* extract the MAC address */
-       for (i = 0; i < 3; i++) {
-               v = in[SPOFF(SSB_SPROM8_IL0MAC) + i];
-               *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
-       }
+-      for (i = 0; i < 3; i++) {
+-              v = in[SPOFF(SSB_SPROM8_IL0MAC) + i];
+-              *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
+-      }
 -      SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0);
++      sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
++
 +      SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
++      SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
 +      SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
 +      SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
        SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
        SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
        SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
-@@ -596,16 +611,46 @@ static void sprom_extract_r8(struct ssb_
+@@ -596,16 +621,46 @@ static void sprom_extract_r8(struct ssb_
        SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0);
  
        /* Extract the antenna gain values. */
  
        /* Extract FEM info */
        SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
-@@ -630,6 +675,63 @@ static void sprom_extract_r8(struct ssb_
+@@ -630,6 +685,63 @@ static void sprom_extract_r8(struct ssb_
        SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
                SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
  
        sprom_extract_r458(out, in);
  
        /* TODO - get remaining rev 8 stuff needed */
-@@ -759,7 +861,6 @@ static void ssb_pci_get_boardinfo(struct
+@@ -641,7 +753,7 @@ static int sprom_extract(struct ssb_bus
+       memset(out, 0, sizeof(*out));
+       out->revision = in[size - 1] & 0x00FF;
+-      ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
++      ssb_dbg("SPROM revision %d detected\n", out->revision);
+       memset(out->et0mac, 0xFF, 6);           /* preset et0 and et1 mac */
+       memset(out->et1mac, 0xFF, 6);
+@@ -650,7 +762,7 @@ static int sprom_extract(struct ssb_bus
+                * number stored in the SPROM.
+                * Always extract r1. */
+               out->revision = 1;
+-              ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
++              ssb_dbg("SPROM treated as revision %d\n", out->revision);
+       }
+       switch (out->revision) {
+@@ -667,9 +779,8 @@ static int sprom_extract(struct ssb_bus
+               sprom_extract_r8(out, in);
+               break;
+       default:
+-              ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
+-                         " revision %d detected. Will extract"
+-                         " v1\n", out->revision);
++              ssb_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
++                       out->revision);
+               out->revision = 1;
+               sprom_extract_r123(out, in);
+       }
+@@ -689,7 +800,7 @@ static int ssb_pci_sprom_get(struct ssb_
+       u16 *buf;
+       if (!ssb_is_sprom_available(bus)) {
+-              ssb_printk(KERN_ERR PFX "No SPROM available!\n");
++              ssb_err("No SPROM available!\n");
+               return -ENODEV;
+       }
+       if (bus->chipco.dev) {  /* can be unavailable! */
+@@ -708,7 +819,7 @@ static int ssb_pci_sprom_get(struct ssb_
+       } else {
+               bus->sprom_offset = SSB_SPROM_BASE1;
+       }
+-      ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
++      ssb_dbg("SPROM offset is 0x%x\n", bus->sprom_offset);
+       buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
+       if (!buf)
+@@ -733,18 +844,15 @@ static int ssb_pci_sprom_get(struct ssb_
+                        * available for this device in some other storage */
+                       err = ssb_fill_sprom_with_fallback(bus, sprom);
+                       if (err) {
+-                              ssb_printk(KERN_WARNING PFX "WARNING: Using"
+-                                         " fallback SPROM failed (err %d)\n",
+-                                         err);
++                              ssb_warn("WARNING: Using fallback SPROM failed (err %d)\n",
++                                       err);
+                       } else {
+-                              ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
+-                                          " revision %d provided by"
+-                                          " platform.\n", sprom->revision);
++                              ssb_dbg("Using SPROM revision %d provided by platform\n",
++                                      sprom->revision);
+                               err = 0;
+                               goto out_free;
+                       }
+-                      ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
+-                                 " SPROM CRC (corrupt SPROM)\n");
++                      ssb_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
+               }
+       }
+       err = sprom_extract(bus, sprom, buf, bus->sprom_size);
+@@ -759,7 +867,6 @@ static void ssb_pci_get_boardinfo(struct
  {
        bi->vendor = bus->host_pci->subsystem_vendor;
        bi->type = bus->host_pci->subsystem_device;
  int ssb_pci_get_invariants(struct ssb_bus *bus,
 --- a/drivers/ssb/pcmcia.c
 +++ b/drivers/ssb/pcmcia.c
-@@ -676,14 +676,10 @@ static int ssb_pcmcia_do_get_invariants(
+@@ -143,7 +143,7 @@ int ssb_pcmcia_switch_coreidx(struct ssb
+       return 0;
+ error:
+-      ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
++      ssb_err("Failed to switch to core %u\n", coreidx);
+       return err;
+ }
+@@ -153,10 +153,9 @@ int ssb_pcmcia_switch_core(struct ssb_bu
+       int err;
+ #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
+-      ssb_printk(KERN_INFO PFX
+-                 "Switching to %s core, index %d\n",
+-                 ssb_core_name(dev->id.coreid),
+-                 dev->core_index);
++      ssb_info("Switching to %s core, index %d\n",
++               ssb_core_name(dev->id.coreid),
++               dev->core_index);
+ #endif
+       err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
+@@ -192,7 +191,7 @@ int ssb_pcmcia_switch_segment(struct ssb
+       return 0;
+ error:
+-      ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
++      ssb_err("Failed to switch pcmcia segment\n");
+       return err;
+ }
+@@ -549,44 +548,39 @@ static int ssb_pcmcia_sprom_write_all(st
+       bool failed = 0;
+       size_t size = SSB_PCMCIA_SPROM_SIZE;
+-      ssb_printk(KERN_NOTICE PFX
+-                 "Writing SPROM. Do NOT turn off the power! "
+-                 "Please stand by...\n");
++      ssb_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+       err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN);
+       if (err) {
+-              ssb_printk(KERN_NOTICE PFX
+-                         "Could not enable SPROM write access.\n");
++              ssb_notice("Could not enable SPROM write access\n");
+               return -EBUSY;
+       }
+-      ssb_printk(KERN_NOTICE PFX "[ 0%%");
++      ssb_notice("[ 0%%");
+       msleep(500);
+       for (i = 0; i < size; i++) {
+               if (i == size / 4)
+-                      ssb_printk("25%%");
++                      ssb_cont("25%%");
+               else if (i == size / 2)
+-                      ssb_printk("50%%");
++                      ssb_cont("50%%");
+               else if (i == (size * 3) / 4)
+-                      ssb_printk("75%%");
++                      ssb_cont("75%%");
+               else if (i % 2)
+-                      ssb_printk(".");
++                      ssb_cont(".");
+               err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);
+               if (err) {
+-                      ssb_printk(KERN_NOTICE PFX
+-                                 "Failed to write to SPROM.\n");
++                      ssb_notice("Failed to write to SPROM\n");
+                       failed = 1;
+                       break;
+               }
+       }
+       err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS);
+       if (err) {
+-              ssb_printk(KERN_NOTICE PFX
+-                         "Could not disable SPROM write access.\n");
++              ssb_notice("Could not disable SPROM write access\n");
+               failed = 1;
+       }
+       msleep(500);
+       if (!failed) {
+-              ssb_printk("100%% ]\n");
+-              ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
++              ssb_cont("100%% ]\n");
++              ssb_notice("SPROM written\n");
+       }
+       return failed ? -EBUSY : 0;
+@@ -676,14 +670,10 @@ static int ssb_pcmcia_do_get_invariants(
        case SSB_PCMCIA_CIS_ANTGAIN:
                GOTO_ERROR_ON(tuple->TupleDataLen != 2,
                        "antg tpl size");
                break;
        case SSB_PCMCIA_CIS_BFLAGS:
                GOTO_ERROR_ON((tuple->TupleDataLen != 3) &&
+@@ -704,7 +694,7 @@ static int ssb_pcmcia_do_get_invariants(
+       return -ENOSPC; /* continue with next entry */
+ error:
+-      ssb_printk(KERN_ERR PFX
++      ssb_err(
+                  "PCMCIA: Failed to fetch device invariants: %s\n",
+                  error_description);
+       return -ENODEV;
+@@ -726,7 +716,7 @@ int ssb_pcmcia_get_invariants(struct ssb
+       res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE,
+                               ssb_pcmcia_get_mac, sprom);
+       if (res != 0) {
+-              ssb_printk(KERN_ERR PFX
++              ssb_err(
+                       "PCMCIA: Failed to fetch MAC address\n");
+               return -ENODEV;
+       }
+@@ -737,7 +727,7 @@ int ssb_pcmcia_get_invariants(struct ssb
+       if ((res == 0) || (res == -ENOSPC))
+               return 0;
+-      ssb_printk(KERN_ERR PFX
++      ssb_err(
+                       "PCMCIA: Failed to fetch device invariants\n");
+       return -ENODEV;
+ }
+@@ -847,6 +837,6 @@ int ssb_pcmcia_init(struct ssb_bus *bus)
+       return 0;
+ error:
+-      ssb_printk(KERN_ERR PFX "Failed to initialize PCMCIA host device\n");
++      ssb_err("Failed to initialize PCMCIA host device\n");
+       return err;
+ }
 --- a/drivers/ssb/scan.c
 +++ b/drivers/ssb/scan.c
 @@ -90,6 +90,8 @@ const char *ssb_core_name(u16 coreid)
        }
        return "UNKNOWN";
  }
-@@ -318,6 +320,9 @@ int ssb_bus_scan(struct ssb_bus *bus,
+@@ -123,8 +125,7 @@ static u16 pcidev_to_chipid(struct pci_d
+               chipid_fallback = 0x4401;
+               break;
+       default:
+-              ssb_printk(KERN_ERR PFX
+-                         "PCI-ID not in fallback list\n");
++              ssb_err("PCI-ID not in fallback list\n");
+       }
+       return chipid_fallback;
+@@ -150,8 +151,7 @@ static u8 chipid_to_nrcores(u16 chipid)
+       case 0x4704:
+               return 9;
+       default:
+-              ssb_printk(KERN_ERR PFX
+-                         "CHIPID not in nrcores fallback list\n");
++              ssb_err("CHIPID not in nrcores fallback list\n");
+       }
+       return 1;
+@@ -318,12 +318,13 @@ int ssb_bus_scan(struct ssb_bus *bus,
                        bus->chip_package = 0;
                }
        }
-+      ssb_printk(KERN_INFO PFX "Found chip with id 0x%04X, rev 0x%02X and "
-+                 "package 0x%02X\n", bus->chip_id, bus->chip_rev,
-+                 bus->chip_package);
++      ssb_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
++               bus->chip_id, bus->chip_rev, bus->chip_package);
        if (!bus->nr_devices)
                bus->nr_devices = chipid_to_nrcores(bus->chip_id);
        if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
+-              ssb_printk(KERN_ERR PFX
+-                         "More than %d ssb cores found (%d)\n",
+-                         SSB_MAX_NR_CORES, bus->nr_devices);
++              ssb_err("More than %d ssb cores found (%d)\n",
++                      SSB_MAX_NR_CORES, bus->nr_devices);
+               goto err_unmap;
+       }
+       if (bus->bustype == SSB_BUSTYPE_SSB) {
+@@ -365,8 +366,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
+                       nr_80211_cores++;
+                       if (nr_80211_cores > 1) {
+                               if (!we_support_multiple_80211_cores(bus)) {
+-                                      ssb_dprintk(KERN_INFO PFX "Ignoring additional "
+-                                                  "802.11 core\n");
++                                      ssb_dbg("Ignoring additional 802.11 core\n");
+                                       continue;
+                               }
+                       }
+@@ -374,8 +374,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
+               case SSB_DEV_EXTIF:
+ #ifdef CONFIG_SSB_DRIVER_EXTIF
+                       if (bus->extif.dev) {
+-                              ssb_printk(KERN_WARNING PFX
+-                                         "WARNING: Multiple EXTIFs found\n");
++                              ssb_warn("WARNING: Multiple EXTIFs found\n");
+                               break;
+                       }
+                       bus->extif.dev = dev;
+@@ -383,8 +382,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
+                       break;
+               case SSB_DEV_CHIPCOMMON:
+                       if (bus->chipco.dev) {
+-                              ssb_printk(KERN_WARNING PFX
+-                                         "WARNING: Multiple ChipCommon found\n");
++                              ssb_warn("WARNING: Multiple ChipCommon found\n");
+                               break;
+                       }
+                       bus->chipco.dev = dev;
+@@ -393,8 +391,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
+               case SSB_DEV_MIPS_3302:
+ #ifdef CONFIG_SSB_DRIVER_MIPS
+                       if (bus->mipscore.dev) {
+-                              ssb_printk(KERN_WARNING PFX
+-                                         "WARNING: Multiple MIPS cores found\n");
++                              ssb_warn("WARNING: Multiple MIPS cores found\n");
+                               break;
+                       }
+                       bus->mipscore.dev = dev;
+@@ -415,8 +412,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
+                               }
+                       }
+                       if (bus->pcicore.dev) {
+-                              ssb_printk(KERN_WARNING PFX
+-                                         "WARNING: Multiple PCI(E) cores found\n");
++                              ssb_warn("WARNING: Multiple PCI(E) cores found\n");
+                               break;
+                       }
+                       bus->pcicore.dev = dev;
 --- a/drivers/ssb/sdio.c
 +++ b/drivers/ssb/sdio.c
 @@ -551,14 +551,10 @@ int ssb_sdio_get_invariants(struct ssb_b
                                break;
                        case SSB_SDIO_CIS_BFLAGS:
                                GOTO_ERROR_ON((tuple->size != 3) &&
+--- a/drivers/ssb/sprom.c
++++ b/drivers/ssb/sprom.c
+@@ -127,13 +127,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_
+               goto out_kfree;
+       err = ssb_devices_freeze(bus, &freeze);
+       if (err) {
+-              ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
++              ssb_err("SPROM write: Could not freeze all devices\n");
+               goto out_unlock;
+       }
+       res = sprom_write(bus, sprom);
+       err = ssb_devices_thaw(&freeze);
+       if (err)
+-              ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
++              ssb_err("SPROM write: Could not thaw all devices\n");
+ out_unlock:
+       mutex_unlock(&bus->sprom_mutex);
+ out_kfree:
 --- a/drivers/ssb/ssb_private.h
 +++ b/drivers/ssb/ssb_private.h
-@@ -207,4 +207,8 @@ static inline void b43_pci_ssb_bridge_ex
+@@ -3,21 +3,33 @@
+ #include <linux/ssb/ssb.h>
+ #include <linux/types.h>
++#include <linux/bcm47xx_wdt.h>
+ #define PFX   "ssb: "
+ #ifdef CONFIG_SSB_SILENT
+-# define ssb_printk(fmt, x...)        do { /* nothing */ } while (0)
++# define ssb_printk(fmt, ...)                                 \
++      do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)
+ #else
+-# define ssb_printk           printk
++# define ssb_printk(fmt, ...)                                 \
++      printk(fmt, ##__VA_ARGS__)
+ #endif /* CONFIG_SSB_SILENT */
++#define ssb_emerg(fmt, ...)   ssb_printk(KERN_EMERG PFX fmt, ##__VA_ARGS__)
++#define ssb_err(fmt, ...)     ssb_printk(KERN_ERR PFX fmt, ##__VA_ARGS__)
++#define ssb_warn(fmt, ...)    ssb_printk(KERN_WARNING PFX fmt, ##__VA_ARGS__)
++#define ssb_notice(fmt, ...)  ssb_printk(KERN_NOTICE PFX fmt, ##__VA_ARGS__)
++#define ssb_info(fmt, ...)    ssb_printk(KERN_INFO PFX fmt, ##__VA_ARGS__)
++#define ssb_cont(fmt, ...)    ssb_printk(KERN_CONT fmt, ##__VA_ARGS__)
++
+ /* dprintk: Debugging printk; vanishes for non-debug compilation */
+ #ifdef CONFIG_SSB_DEBUG
+-# define ssb_dprintk(fmt, x...)       ssb_printk(fmt , ##x)
++# define ssb_dbg(fmt, ...)                                    \
++      ssb_printk(KERN_DEBUG PFX fmt, ##__VA_ARGS__)
+ #else
+-# define ssb_dprintk(fmt, x...)       do { /* nothing */ } while (0)
++# define ssb_dbg(fmt, ...)                                    \
++      do { if (0) printk(KERN_DEBUG PFX fmt, ##__VA_ARGS__); } while (0)
+ #endif
+ #ifdef CONFIG_SSB_DEBUG
+@@ -207,4 +219,60 @@ static inline void b43_pci_ssb_bridge_ex
  }
  #endif /* CONFIG_SSB_B43_PCI_BRIDGE */
  
 +/* driver_chipcommon_pmu.c */
 +extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc);
 +extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc);
++extern u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc);
++
++extern u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt,
++                                           u32 ticks);
++extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
++
++#ifdef CONFIG_SSB_DRIVER_EXTIF
++extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks);
++extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
++#else
++static inline u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt,
++                                                 u32 ticks)
++{
++      return 0;
++}
++static inline u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt,
++                                                u32 ms)
++{
++      return 0;
++}
++#endif
++
++#ifdef CONFIG_SSB_EMBEDDED
++extern int ssb_watchdog_register(struct ssb_bus *bus);
++#else /* CONFIG_SSB_EMBEDDED */
++static inline int ssb_watchdog_register(struct ssb_bus *bus)
++{
++      return 0;
++}
++#endif /* CONFIG_SSB_EMBEDDED */
++
++#ifdef CONFIG_SSB_DRIVER_EXTIF
++extern void ssb_extif_init(struct ssb_extif *extif);
++#else
++static inline void ssb_extif_init(struct ssb_extif *extif)
++{
++}
++#endif
++
++#ifdef CONFIG_SSB_DRIVER_GPIO
++extern int ssb_gpio_init(struct ssb_bus *bus);
++extern int ssb_gpio_unregister(struct ssb_bus *bus);
++#else /* CONFIG_SSB_DRIVER_GPIO */
++static inline int ssb_gpio_init(struct ssb_bus *bus)
++{
++      return -ENOTSUPP;
++}
++static inline int ssb_gpio_unregister(struct ssb_bus *bus)
++{
++      return 0;
++}
++#endif /* CONFIG_SSB_DRIVER_GPIO */
 +
  #endif /* LINUX_SSB_PRIVATE_H_ */
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -16,6 +16,12 @@ struct pcmcia_device;
+@@ -6,8 +6,10 @@
+ #include <linux/types.h>
+ #include <linux/spinlock.h>
+ #include <linux/pci.h>
++#include <linux/gpio.h>
+ #include <linux/mod_devicetable.h>
+ #include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
+ #include <linux/ssb/ssb_regs.h>
+@@ -16,19 +18,28 @@ struct pcmcia_device;
  struct ssb_bus;
  struct ssb_driver;
  
 +
  struct ssb_sprom {
        u8 revision;
-       u8 il0mac[6];           /* MAC address for 802.11b/g */
-@@ -26,9 +32,12 @@ struct ssb_sprom {
+-      u8 il0mac[6];           /* MAC address for 802.11b/g */
+-      u8 et0mac[6];           /* MAC address for Ethernet */
+-      u8 et1mac[6];           /* MAC address for 802.11a */
++      u8 il0mac[6] __aligned(sizeof(u16));    /* MAC address for 802.11b/g */
++      u8 et0mac[6] __aligned(sizeof(u16));    /* MAC address for Ethernet */
++      u8 et1mac[6] __aligned(sizeof(u16));    /* MAC address for 802.11a */
+       u8 et0phyaddr;          /* MII address for enet0 */
+       u8 et1phyaddr;          /* MII address for enet1 */
        u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
        u16 board_rev;          /* Board revision number from SPROM. */
        u8 ant_available_a;     /* 2GHz antenna available bits (up to 4) */
        u8 ant_available_bg;    /* 5GHz antenna available bits (up to 4) */
        u16 pa0b0;
-@@ -47,10 +56,10 @@ struct ssb_sprom {
+@@ -47,10 +58,10 @@ struct ssb_sprom {
        u8 gpio1;               /* GPIO pin 1 */
        u8 gpio2;               /* GPIO pin 2 */
        u8 gpio3;               /* GPIO pin 3 */
        u8 itssi_a;             /* Idle TSSI Target for A-PHY */
        u8 itssi_bg;            /* Idle TSSI Target for B/G-PHY */
        u8 tri2g;               /* 2.4GHz TX isolation */
-@@ -61,8 +70,8 @@ struct ssb_sprom {
+@@ -61,8 +72,8 @@ struct ssb_sprom {
        u8 txpid5gl[4];         /* 4.9 - 5.1GHz TX power index */
        u8 txpid5g[4];          /* 5.1 - 5.5GHz TX power index */
        u8 txpid5gh[4];         /* 5.5 - ...GHz TX power index */
        u8 rssisav2g;           /* 2GHz RSSI params */
        u8 rssismc2g;
        u8 rssismf2g;
-@@ -82,16 +91,13 @@ struct ssb_sprom {
+@@ -82,16 +93,13 @@ struct ssb_sprom {
        u16 boardflags2_hi;     /* Board flags (bits 48-63) */
        /* TODO store board flags in a single u64 */
  
        } antenna_gain;
  
        struct {
-@@ -103,14 +109,85 @@ struct ssb_sprom {
+@@ -103,14 +111,85 @@ struct ssb_sprom {
                } ghz5;
        } fem;
  
  };
  
  
-@@ -166,6 +243,7 @@ struct ssb_bus_ops {
+@@ -166,6 +245,7 @@ struct ssb_bus_ops {
  #define SSB_DEV_MINI_MACPHY   0x823
  #define SSB_DEV_ARM_1176      0x824
  #define SSB_DEV_ARM_7TDMI     0x825
  
  /* Vendor-ID values */
  #define SSB_VENDOR_BROADCOM   0x4243
+@@ -260,13 +340,61 @@ enum ssb_bustype {
+ #define SSB_BOARDVENDOR_DELL  0x1028  /* Dell */
+ #define SSB_BOARDVENDOR_HP    0x0E11  /* HP */
+ /* board_type */
++#define SSB_BOARD_BCM94301CB  0x0406
++#define SSB_BOARD_BCM94301MP  0x0407
++#define SSB_BOARD_BU4309      0x040A
++#define SSB_BOARD_BCM94309CB  0x040B
++#define SSB_BOARD_BCM4309MP   0x040C
++#define SSB_BOARD_BU4306      0x0416
+ #define SSB_BOARD_BCM94306MP  0x0418
+ #define SSB_BOARD_BCM4309G    0x0421
+ #define SSB_BOARD_BCM4306CB   0x0417
+-#define SSB_BOARD_BCM4309MP   0x040C
++#define SSB_BOARD_BCM94306PC  0x0425  /* pcmcia 3.3v 4306 card */
++#define SSB_BOARD_BCM94306CBSG        0x042B  /* with SiGe PA */
++#define SSB_BOARD_PCSG94306   0x042D  /* with SiGe PA */
++#define SSB_BOARD_BU4704SD    0x042E  /* with sdram */
++#define SSB_BOARD_BCM94704AGR 0x042F  /* dual 11a/11g Router */
++#define SSB_BOARD_BCM94308MP  0x0430  /* 11a-only minipci */
++#define SSB_BOARD_BU4318      0x0447
++#define SSB_BOARD_CB4318      0x0448
++#define SSB_BOARD_MPG4318     0x0449
+ #define SSB_BOARD_MP4318      0x044A
+-#define SSB_BOARD_BU4306      0x0416
+-#define SSB_BOARD_BU4309      0x040A
++#define SSB_BOARD_SD4318      0x044B
++#define SSB_BOARD_BCM94306P   0x044C  /* with SiGe */
++#define SSB_BOARD_BCM94303MP  0x044E
++#define SSB_BOARD_BCM94306MPM 0x0450
++#define SSB_BOARD_BCM94306MPL 0x0453
++#define SSB_BOARD_PC4303      0x0454  /* pcmcia */
++#define SSB_BOARD_BCM94306MPLNA       0x0457
++#define SSB_BOARD_BCM94306MPH 0x045B
++#define SSB_BOARD_BCM94306PCIV        0x045C
++#define SSB_BOARD_BCM94318MPGH        0x0463
++#define SSB_BOARD_BU4311      0x0464
++#define SSB_BOARD_BCM94311MC  0x0465
++#define SSB_BOARD_BCM94311MCAG        0x0466
++/* 4321 boards */
++#define SSB_BOARD_BU4321      0x046B
++#define SSB_BOARD_BU4321E     0x047C
++#define SSB_BOARD_MP4321      0x046C
++#define SSB_BOARD_CB2_4321    0x046D
++#define SSB_BOARD_CB2_4321_AG 0x0066
++#define SSB_BOARD_MC4321      0x046E
++/* 4325 boards */
++#define SSB_BOARD_BCM94325DEVBU       0x0490
++#define SSB_BOARD_BCM94325BGABU       0x0491
++#define SSB_BOARD_BCM94325SDGWB       0x0492
++#define SSB_BOARD_BCM94325SDGMDL      0x04AA
++#define SSB_BOARD_BCM94325SDGMDL2     0x04C6
++#define SSB_BOARD_BCM94325SDGMDL3     0x04C9
++#define SSB_BOARD_BCM94325SDABGWBA    0x04E1
++/* 4322 boards */
++#define SSB_BOARD_BCM94322MC  0x04A4
++#define SSB_BOARD_BCM94322USB 0x04A8  /* dualband */
++#define SSB_BOARD_BCM94322HM  0x04B0
++#define SSB_BOARD_BCM94322USB2D       0x04Bf  /* single band discrete front end */
++/* 4312 boards */
++#define SSB_BOARD_BU4312      0x048A
++#define SSB_BOARD_BCM4312MCGSG        0x04B5
+ /* chip_package */
+ #define SSB_CHIPPACK_BCM4712S 1       /* Small 200pin 4712 */
+ #define SSB_CHIPPACK_BCM4712M 2       /* Medium 225pin 4712 */
+@@ -354,7 +482,11 @@ struct ssb_bus {
+ #ifdef CONFIG_SSB_EMBEDDED
+       /* Lock for GPIO register access. */
+       spinlock_t gpio_lock;
++      struct platform_device *watchdog;
+ #endif /* EMBEDDED */
++#ifdef CONFIG_SSB_DRIVER_GPIO
++      struct gpio_chip gpio;
++#endif /* DRIVER_GPIO */
+       /* Internal-only stuff follows. Do not touch. */
+       struct list_head list;
+--- a/include/linux/ssb/ssb_driver_chipcommon.h
++++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -219,6 +219,7 @@
+ #define SSB_CHIPCO_PMU_CTL                    0x0600 /* PMU control */
+ #define  SSB_CHIPCO_PMU_CTL_ILP_DIV           0xFFFF0000 /* ILP div mask */
+ #define  SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT     16
++#define  SSB_CHIPCO_PMU_CTL_PLL_UPD           0x00000400
+ #define  SSB_CHIPCO_PMU_CTL_NOILPONW          0x00000200 /* No ILP on wait */
+ #define  SSB_CHIPCO_PMU_CTL_HTREQEN           0x00000100 /* HT req enable */
+ #define  SSB_CHIPCO_PMU_CTL_ALPREQEN          0x00000080 /* ALP req enable */
+@@ -588,7 +589,10 @@ struct ssb_chipcommon {
+       u32 status;
+       /* Fast Powerup Delay constant */
+       u16 fast_pwrup_delay;
++      spinlock_t gpio_lock;
+       struct ssb_chipcommon_pmu pmu;
++      u32 ticks_per_ms;
++      u32 max_timer_ms;
+ };
+ static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)
+@@ -628,8 +632,7 @@ enum ssb_clkmode {
+ extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
+                                    enum ssb_clkmode mode);
+-extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc,
+-                                        u32 ticks);
++extern u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks);
+ void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value);
+@@ -642,6 +645,8 @@ u32 ssb_chipco_gpio_outen(struct ssb_chi
+ u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value);
+ u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value);
+ u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value);
++u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value);
++u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value);
+ #ifdef CONFIG_SSB_SERIAL
+ extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
+@@ -661,5 +666,6 @@ enum ssb_pmu_ldo_volt_id {
+ void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc,
+                            enum ssb_pmu_ldo_volt_id id, u32 voltage);
+ void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on);
++void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid);
+ #endif /* LINUX_SSB_CHIPCO_H_ */
+--- a/include/linux/ssb/ssb_driver_extif.h
++++ b/include/linux/ssb/ssb_driver_extif.h
+@@ -152,12 +152,16 @@
+ /* watchdog */
+ #define SSB_EXTIF_WATCHDOG_CLK                48000000        /* Hz */
++#define SSB_EXTIF_WATCHDOG_MAX_TIMER  ((1 << 28) - 1)
++#define SSB_EXTIF_WATCHDOG_MAX_TIMER_MS       (SSB_EXTIF_WATCHDOG_MAX_TIMER \
++                                       / (SSB_EXTIF_WATCHDOG_CLK / 1000))
+ #ifdef CONFIG_SSB_DRIVER_EXTIF
+ struct ssb_extif {
+       struct ssb_device *dev;
++      spinlock_t gpio_lock;
+ };
+ static inline bool ssb_extif_available(struct ssb_extif *extif)
+@@ -171,8 +175,7 @@ extern void ssb_extif_get_clockcontrol(s
+ extern void ssb_extif_timing_init(struct ssb_extif *extif,
+                                 unsigned long ns);
+-extern void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
+-                                       u32 ticks);
++extern u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks);
+ /* Extif GPIO pin access */
+ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask);
+@@ -205,10 +208,52 @@ void ssb_extif_get_clockcontrol(struct s
+ }
+ static inline
+-void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
+-                                u32 ticks)
++void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns)
+ {
+ }
++static inline
++u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks)
++{
++      return 0;
++}
++
++static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
++{
++      return 0;
++}
++
++static inline u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask,
++                                   u32 value)
++{
++      return 0;
++}
++
++static inline u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask,
++                                     u32 value)
++{
++      return 0;
++}
++
++static inline u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask,
++                                        u32 value)
++{
++      return 0;
++}
++
++static inline u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask,
++                                       u32 value)
++{
++      return 0;
++}
++
++#ifdef CONFIG_SSB_SERIAL
++static inline int ssb_extif_serial_init(struct ssb_extif *extif,
++                                      struct ssb_serial_port *ports)
++{
++      return 0;
++}
++#endif /* CONFIG_SSB_SERIAL */
++
+ #endif /* CONFIG_SSB_DRIVER_EXTIF */
+ #endif /* LINUX_SSB_EXTIFCORE_H_ */
 --- a/include/linux/ssb/ssb_driver_gige.h
 +++ b/include/linux/ssb/ssb_driver_gige.h
 @@ -2,6 +2,7 @@
  #include <linux/pci.h>
  #include <linux/spinlock.h>
  
+@@ -96,21 +97,16 @@ static inline bool ssb_gige_must_flush_p
+       return 0;
+ }
+-#ifdef CONFIG_BCM47XX
+-#include <asm/mach-bcm47xx/nvram.h>
+ /* Get the device MAC address */
+-static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
+-{
+-      char buf[20];
+-      if (nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0)
+-              return;
+-      nvram_parse_macaddr(buf, macaddr);
+-}
+-#else
+-static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
++static inline int ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
+ {
++      struct ssb_gige *dev = pdev_to_ssb_gige(pdev);
++      if (!dev)
++              return -ENODEV;
++
++      memcpy(macaddr, dev->dev->bus->sprom.et0mac, 6);
++      return 0;
+ }
+-#endif
+ extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
+                                         struct pci_dev *pdev);
+@@ -174,6 +170,10 @@ static inline bool ssb_gige_must_flush_p
+ {
+       return 0;
+ }
++static inline int ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
++{
++      return -ENODEV;
++}
+ #endif /* CONFIG_SSB_DRIVER_GIGE */
+ #endif /* LINUX_SSB_DRIVER_GIGE_H_ */
+--- a/include/linux/ssb/ssb_driver_mips.h
++++ b/include/linux/ssb/ssb_driver_mips.h
+@@ -41,6 +41,11 @@ void ssb_mipscore_init(struct ssb_mipsco
+ {
+ }
++static inline unsigned int ssb_mips_irq(struct ssb_device *dev)
++{
++      return 0;
++}
++
+ #endif /* CONFIG_SSB_DRIVER_MIPS */
+ #endif /* LINUX_SSB_MIPSCORE_H_ */
 --- a/include/linux/ssb/ssb_regs.h
 +++ b/include/linux/ssb/ssb_regs.h
-@@ -228,6 +228,7 @@
+@@ -172,6 +172,7 @@
+ #define SSB_SPROMSIZE_WORDS_R4                220
+ #define SSB_SPROMSIZE_BYTES_R123      (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16))
+ #define SSB_SPROMSIZE_BYTES_R4                (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
++#define SSB_SPROMSIZE_WORDS_R10               230
+ #define SSB_SPROM_BASE1                       0x1000
+ #define SSB_SPROM_BASE31              0x0800
+ #define SSB_SPROM_REVISION            0x007E
+@@ -228,6 +229,7 @@
  #define  SSB_SPROM1_AGAIN_BG_SHIFT    0
  #define  SSB_SPROM1_AGAIN_A           0xFF00  /* A-PHY */
  #define  SSB_SPROM1_AGAIN_A_SHIFT     8
  
  /* SPROM Revision 2 (inherits from rev 1) */
  #define SSB_SPROM2_BFLHI              0x0038  /* Boardflags (high 16 bits) */
-@@ -267,6 +268,7 @@
+@@ -267,6 +269,7 @@
  #define  SSB_SPROM3_OFDMGPO           0x107A  /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
  
  /* SPROM Revision 4 */
  #define SSB_SPROM4_BFLLO              0x0044  /* Boardflags (low 16 bits) */
  #define SSB_SPROM4_BFLHI              0x0046  /* Board Flags Hi */
  #define SSB_SPROM4_BFL2LO             0x0048  /* Board flags 2 (low 16 bits) */
-@@ -389,6 +391,11 @@
+@@ -287,11 +290,11 @@
+ #define  SSB_SPROM4_ETHPHY_ET1A_SHIFT 5
+ #define  SSB_SPROM4_ETHPHY_ET0M               (1<<14) /* MDIO for enet0 */
+ #define  SSB_SPROM4_ETHPHY_ET1M               (1<<15) /* MDIO for enet1 */
+-#define SSB_SPROM4_ANTAVAIL           0x005D  /* Antenna available bitfields */
+-#define  SSB_SPROM4_ANTAVAIL_A                0x00FF  /* A-PHY bitfield */
+-#define  SSB_SPROM4_ANTAVAIL_A_SHIFT  0
+-#define  SSB_SPROM4_ANTAVAIL_BG               0xFF00  /* B-PHY and G-PHY bitfield */
+-#define  SSB_SPROM4_ANTAVAIL_BG_SHIFT 8
++#define SSB_SPROM4_ANTAVAIL           0x005C  /* Antenna available bitfields */
++#define  SSB_SPROM4_ANTAVAIL_BG               0x00FF  /* B-PHY and G-PHY bitfield */
++#define  SSB_SPROM4_ANTAVAIL_BG_SHIFT 0
++#define  SSB_SPROM4_ANTAVAIL_A                0xFF00  /* A-PHY bitfield */
++#define  SSB_SPROM4_ANTAVAIL_A_SHIFT  8
+ #define SSB_SPROM4_AGAIN01            0x005E  /* Antenna Gain (in dBm Q5.2) */
+ #define  SSB_SPROM4_AGAIN0            0x00FF  /* Antenna 0 */
+ #define  SSB_SPROM4_AGAIN0_SHIFT      0
+@@ -389,6 +392,11 @@
  #define  SSB_SPROM8_GPIOB_P2          0x00FF  /* Pin 2 */
  #define  SSB_SPROM8_GPIOB_P3          0xFF00  /* Pin 3 */
  #define  SSB_SPROM8_GPIOB_P3_SHIFT    8
  #define SSB_SPROM8_ANTAVAIL           0x009C  /* Antenna available bitfields*/
  #define  SSB_SPROM8_ANTAVAIL_A                0xFF00  /* A-PHY bitfield */
  #define  SSB_SPROM8_ANTAVAIL_A_SHIFT  8
-@@ -404,6 +411,13 @@
+@@ -404,6 +412,13 @@
  #define  SSB_SPROM8_AGAIN2_SHIFT      0
  #define  SSB_SPROM8_AGAIN3            0xFF00  /* Antenna 3 */
  #define  SSB_SPROM8_AGAIN3_SHIFT      8
  #define SSB_SPROM8_RSSIPARM2G         0x00A4  /* RSSI params for 2GHz */
  #define  SSB_SPROM8_RSSISMF2G         0x000F
  #define  SSB_SPROM8_RSSISMC2G         0x00F0
-@@ -430,6 +444,7 @@
+@@ -430,6 +445,7 @@
  #define  SSB_SPROM8_TRI5GH_SHIFT      8
  #define SSB_SPROM8_RXPO                       0x00AC  /* RX power offsets */
  #define  SSB_SPROM8_RXPO2G            0x00FF  /* 2GHz RX power offset */
  #define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
  #define  SSB_SPROM8_RXPO5G_SHIFT      8
  #define SSB_SPROM8_FEM2G              0x00AE
-@@ -445,10 +460,71 @@
+@@ -445,10 +461,71 @@
  #define  SSB_SROM8_FEM_ANTSWLUT               0xF800
  #define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
  #define SSB_SPROM8_THERMAL            0x00B2
 +#define  SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT        4
 +#define  SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL       0x0020
 +#define  SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT 5
-+#define SSB_SPROM8_TEMPDELTA          0x00BA
++#define SSB_SPROM8_TEMPDELTA          0x00BC
 +#define  SSB_SPROM8_TEMPDELTA_PHYCAL  0x00ff
 +#define  SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT    0
 +#define  SSB_SPROM8_TEMPDELTA_PERIOD  0x0f00
  #define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
  #define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
  #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
-@@ -473,12 +549,23 @@
+@@ -473,12 +550,23 @@
  #define SSB_SPROM8_PA1HIB0            0x00D8  /* 5.8GHz power amp settings */
  #define SSB_SPROM8_PA1HIB1            0x00DA
  #define SSB_SPROM8_PA1HIB2            0x00DC
  /* Values for boardflags_lo read from SPROM */
  #define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
  #define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
+--- /dev/null
++++ b/include/linux/bcm47xx_wdt.h
+@@ -0,0 +1,19 @@
++#ifndef LINUX_BCM47XX_WDT_H_
++#define LINUX_BCM47XX_WDT_H_
++
++#include <linux/types.h>
++
++
++struct bcm47xx_wdt {
++      u32 (*timer_set)(struct bcm47xx_wdt *, u32);
++      u32 (*timer_set_ms)(struct bcm47xx_wdt *, u32);
++      u32 max_timer_ms;
++
++      void *driver_data;
++};
++
++static inline void *bcm47xx_wdt_get_drvdata(struct bcm47xx_wdt *wdt)
++{
++      return wdt->driver_data;
++}
++#endif /* LINUX_BCM47XX_WDT_H_ */
+--- a/drivers/net/wireless/b43/phy_n.c
++++ b/drivers/net/wireless/b43/phy_n.c
+@@ -4259,7 +4259,8 @@ static void b43_nphy_pmu_spur_avoid(stru
+ #endif
+ #ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+-              /* FIXME */
++              ssb_pmu_spuravoid_pllupdate(&dev->dev->sdev->bus->chipco,
++                                          avoid);
+               break;
+ #endif
+       }
index 29aaa29..eeea9db 100644 (file)
@@ -1,6 +1,32 @@
+--- a/arch/mips/bcm47xx/serial.c
++++ b/arch/mips/bcm47xx/serial.c
+@@ -62,7 +62,7 @@ static int __init uart8250_init_bcma(voi
+               p->mapbase = (unsigned int) bcma_port->regs;
+               p->membase = (void *) bcma_port->regs;
+-              p->irq = bcma_port->irq + 2;
++              p->irq = bcma_port->irq;
+               p->uartclk = bcma_port->baud_base;
+               p->regshift = bcma_port->reg_shift;
+               p->iotype = UPIO_MEM;
+--- a/arch/mips/bcm47xx/gpio.c
++++ b/arch/mips/bcm47xx/gpio.c
+@@ -94,7 +94,7 @@ int gpio_to_irq(unsigned gpio)
+ #endif
+ #ifdef CONFIG_BCM47XX_BCMA
+       case BCM47XX_BUS_TYPE_BCMA:
+-              return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
++              return bcma_core_irq(bcm47xx_bus.bcma.bus.drv_cc.core);
+ #endif
+       }
+       return -EINVAL;
 --- a/drivers/bcma/Kconfig
 +++ b/drivers/bcma/Kconfig
-@@ -29,7 +29,7 @@ config BCMA_HOST_PCI
+@@ -26,10 +26,11 @@ config BCMA_HOST_PCI_POSSIBLE
+ config BCMA_HOST_PCI
+       bool "Support for BCMA on PCI-host bus"
+       depends on BCMA_HOST_PCI_POSSIBLE
++      default y
  
  config BCMA_DRIVER_PCI_HOSTMODE
        bool "Driver for PCI core working in hostmode"
@@ -9,7 +35,7 @@
        help
          PCI core hostmode operation (external PCI bus).
  
-@@ -46,6 +46,15 @@ config BCMA_DRIVER_MIPS
+@@ -46,6 +47,23 @@ config BCMA_DRIVER_MIPS
  
          If unsure, say N
  
 +
 +        If unsure, say N
 +
++config BCMA_DRIVER_GPIO
++      bool "BCMA GPIO driver"
++      depends on BCMA && GPIOLIB
++      help
++        Driver to provide access to the GPIO pins of the bcma bus.
++
++        If unsure, say N
++
  config BCMA_DEBUG
        bool "BCMA debugging"
        depends on BCMA
 --- a/drivers/bcma/Makefile
 +++ b/drivers/bcma/Makefile
-@@ -3,6 +3,7 @@ bcma-y                                 += driver_chipcommon.o driver
+@@ -3,6 +3,8 @@ bcma-y                                 += driver_chipcommon.o driver
  bcma-y                                        += driver_pci.o
  bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
  bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 +bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN)   += driver_gmac_cmn.o
++bcma-$(CONFIG_BCMA_DRIVER_GPIO)               += driver_gpio.o
  bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
  bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
  obj-$(CONFIG_BCMA)                    += bcma.o
 --- a/drivers/bcma/bcma_private.h
 +++ b/drivers/bcma/bcma_private.h
-@@ -10,10 +10,19 @@
+@@ -10,10 +10,21 @@
  
  #define BCMA_CORE_SIZE                0x1000
  
  
  /* main.c */
 -int bcma_bus_register(struct bcma_bus *bus);
++bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
++                   int timeout);
 +int __devinit bcma_bus_register(struct bcma_bus *bus);
  void bcma_bus_unregister(struct bcma_bus *bus);
  int __init bcma_bus_early_register(struct bcma_bus *bus,
                                   struct bcma_device *core_cc,
-@@ -48,8 +57,12 @@ extern int __init bcma_host_pci_init(voi
+@@ -22,6 +33,8 @@ int __init bcma_bus_early_register(struc
+ int bcma_bus_suspend(struct bcma_bus *bus);
+ int bcma_bus_resume(struct bcma_bus *bus);
+ #endif
++struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
++                                      u8 unit);
+ /* scan.c */
+ int bcma_bus_scan(struct bcma_bus *bus);
+@@ -39,8 +52,8 @@ void bcma_chipco_serial_init(struct bcma
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
+ /* driver_chipcommon_pmu.c */
+-u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
+-u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
+ #ifdef CONFIG_BCMA_HOST_PCI
+ /* host_pci.c */
+@@ -48,8 +61,29 @@ extern int __init bcma_host_pci_init(voi
  extern void __exit bcma_host_pci_exit(void);
  #endif /* CONFIG_BCMA_HOST_PCI */
  
 +/* driver_pci.c */
 +u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
 +
++extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
++
  #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 -void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
 +bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
 +void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
  #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
  
++#ifdef CONFIG_BCMA_DRIVER_GPIO
++/* driver_gpio.c */
++int bcma_gpio_init(struct bcma_drv_cc *cc);
++int bcma_gpio_unregister(struct bcma_drv_cc *cc);
++#else
++static inline int bcma_gpio_init(struct bcma_drv_cc *cc)
++{
++      return -ENOTSUPP;
++}
++static inline int bcma_gpio_unregister(struct bcma_drv_cc *cc)
++{
++      return 0;
++}
++#endif /* CONFIG_BCMA_DRIVER_GPIO */
++
  #endif
 --- a/drivers/bcma/core.c
 +++ b/drivers/bcma/core.c
-@@ -30,6 +30,7 @@ void bcma_core_disable(struct bcma_devic
-       udelay(10);
+@@ -9,6 +9,25 @@
+ #include <linux/export.h>
+ #include <linux/bcma/bcma.h>
++static bool bcma_core_wait_value(struct bcma_device *core, u16 reg, u32 mask,
++                               u32 value, int timeout)
++{
++      unsigned long deadline = jiffies + timeout;
++      u32 val;
++
++      do {
++              val = bcma_aread32(core, reg);
++              if ((val & mask) == value)
++                      return true;
++              cpu_relax();
++              udelay(10);
++      } while (!time_after_eq(jiffies, deadline));
++
++      bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg);
++
++      return false;
++}
++
+ bool bcma_core_is_enabled(struct bcma_device *core)
+ {
+       if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC))
+@@ -25,12 +44,15 @@ void bcma_core_disable(struct bcma_devic
+       if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
+               return;
+-      bcma_awrite32(core, BCMA_IOCTL, flags);
+-      bcma_aread32(core, BCMA_IOCTL);
+-      udelay(10);
++      bcma_core_wait_value(core, BCMA_RESET_ST, ~0, 0, 300);
  
        bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
 +      bcma_aread32(core, BCMA_RESET_CTL);
        udelay(1);
++
++      bcma_awrite32(core, BCMA_IOCTL, flags);
++      bcma_aread32(core, BCMA_IOCTL);
++      udelay(10);
  }
  EXPORT_SYMBOL_GPL(bcma_core_disable);
-@@ -74,10 +75,10 @@ void bcma_core_set_clockmode(struct bcma
+@@ -42,6 +64,7 @@ int bcma_core_enable(struct bcma_device
+       bcma_aread32(core, BCMA_IOCTL);
+       bcma_awrite32(core, BCMA_RESET_CTL, 0);
++      bcma_aread32(core, BCMA_RESET_CTL);
+       udelay(1);
+       bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags));
+@@ -64,7 +87,7 @@ void bcma_core_set_clockmode(struct bcma
+       switch (clkmode) {
+       case BCMA_CLKMODE_FAST:
+               bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+-              udelay(64);
++              usleep_range(64, 300);
+               for (i = 0; i < 1500; i++) {
+                       if (bcma_read32(core, BCMA_CLKCTLST) &
+                           BCMA_CLKCTLST_HAVEHT) {
+@@ -74,10 +97,10 @@ void bcma_core_set_clockmode(struct bcma
                        udelay(10);
                }
                if (i)
                break;
        }
  }
-@@ -101,9 +102,9 @@ void bcma_core_pll_ctl(struct bcma_devic
+@@ -101,9 +124,15 @@ void bcma_core_pll_ctl(struct bcma_devic
                        udelay(10);
                }
                if (i)
 +                      bcma_err(core->bus, "PLL enable timeout\n");
        } else {
 -              pr_warn("Disabling PLL not supported yet!\n");
-+              bcma_warn(core->bus, "Disabling PLL not supported yet!\n");
++              /*
++               * Mask the PLL but don't wait for it to be disabled. PLL may be
++               * shared between cores and will be still up if there is another
++               * core using it.
++               */
++              bcma_mask32(core, BCMA_CLKCTLST, ~req);
++              bcma_read32(core, BCMA_CLKCTLST);
        }
  }
  EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
-@@ -119,8 +120,8 @@ u32 bcma_core_dma_translation(struct bcm
+@@ -119,8 +148,8 @@ u32 bcma_core_dma_translation(struct bcm
                else
                        return BCMA_DMA_TRANSLATION_DMA32_CMT;
        default:
  }
 --- a/drivers/bcma/driver_chipcommon.c
 +++ b/drivers/bcma/driver_chipcommon.c
-@@ -44,7 +44,7 @@ void bcma_core_chipcommon_init(struct bc
+@@ -4,12 +4,15 @@
+  *
+  * Copyright 2005, Broadcom Corporation
+  * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
++ * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include "bcma_private.h"
++#include <linux/bcm47xx_wdt.h>
+ #include <linux/export.h>
++#include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
+@@ -22,29 +25,136 @@ static inline u32 bcma_cc_write32_masked
+       return value;
+ }
+-void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
++u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc)
+ {
+-      u32 leddc_on = 10;
+-      u32 leddc_off = 90;
++      if (cc->capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_alp_clock(cc);
+-      if (cc->setup_done)
++      return 20000000;
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_get_alp_clock);
++
++static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 nb;
++
++      if (cc->capabilities & BCMA_CC_CAP_PMU) {
++              if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
++                      nb = 32;
++              else if (cc->core->id.rev < 26)
++                      nb = 16;
++              else
++                      nb = (cc->core->id.rev >= 37) ? 32 : 24;
++      } else {
++              nb = 28;
++      }
++      if (nb == 32)
++              return 0xffffffff;
++      else
++              return (1 << nb) - 1;
++}
++
++static u32 bcma_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt,
++                                            u32 ticks)
++{
++      struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt);
++
++      return bcma_chipco_watchdog_timer_set(cc, ticks);
++}
++
++static u32 bcma_chipco_watchdog_timer_set_ms_wdt(struct bcm47xx_wdt *wdt,
++                                               u32 ms)
++{
++      struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt);
++      u32 ticks;
++
++      ticks = bcma_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms);
++      return ticks / cc->ticks_per_ms;
++}
++
++static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (cc->capabilities & BCMA_CC_CAP_PMU) {
++              if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
++                      /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */
++                      return bcma_chipco_get_alp_clock(cc) / 4000;
++              else
++                      /* based on 32KHz ILP clock */
++                      return 32;
++      } else {
++              return bcma_chipco_get_alp_clock(cc) / 1000;
++      }
++}
++
++int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
++{
++      struct bcm47xx_wdt wdt = {};
++      struct platform_device *pdev;
++
++      wdt.driver_data = cc;
++      wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
++      wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
++      wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
++
++      pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
++                                           cc->core->bus->num, &wdt,
++                                           sizeof(wdt));
++      if (IS_ERR(pdev))
++              return PTR_ERR(pdev);
++
++      cc->watchdog = pdev;
++
++      return 0;
++}
++
++void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
++{
++      if (cc->early_setup_done)
+               return;
++      spin_lock_init(&cc->gpio_lock);
++
+       if (cc->core->id.rev >= 11)
+               cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
+       cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
+       if (cc->core->id.rev >= 35)
+               cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
++      if (cc->capabilities & BCMA_CC_CAP_PMU)
++              bcma_pmu_early_init(cc);
++
++      cc->early_setup_done = true;
++}
++
++void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
++{
++      u32 leddc_on = 10;
++      u32 leddc_off = 90;
++
++      if (cc->setup_done)
++              return;
++
++      bcma_core_chipcommon_early_init(cc);
++
+       if (cc->core->id.rev >= 20) {
+-              bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
+-              bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
++              u32 pullup = 0, pulldown = 0;
++
++              if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM43142) {
++                      pullup = 0x402e0;
++                      pulldown = 0x20500;
++              }
++
++              bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, pullup);
++              bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, pulldown);
+       }
        if (cc->capabilities & BCMA_CC_CAP_PMU)
                bcma_pmu_init(cc);
        if (cc->capabilities & BCMA_CC_CAP_PCTL)
  
        if (cc->core->id.rev >= 16) {
                if (cc->core->bus->sprom.leddc_on_time &&
-@@ -137,8 +137,7 @@ void bcma_chipco_serial_init(struct bcma
+@@ -56,15 +166,33 @@ void bcma_core_chipcommon_init(struct bc
+                       ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
+                        (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
+       }
++      cc->ticks_per_ms = bcma_chipco_watchdog_ticks_per_ms(cc);
+       cc->setup_done = true;
+ }
+ /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+-void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
++u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
+ {
+-      /* instant NMI */
+-      bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
++      u32 maxt;
++      enum bcma_clkmode clkmode;
++
++      maxt = bcma_chipco_watchdog_get_max_timer(cc);
++      if (cc->capabilities & BCMA_CC_CAP_PMU) {
++              if (ticks == 1)
++                      ticks = 2;
++              else if (ticks > maxt)
++                      ticks = maxt;
++              bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
++      } else {
++              clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC;
++              bcma_core_set_clockmode(cc->core, clkmode);
++              if (ticks > maxt)
++                      ticks = maxt;
++              /* instant NMI */
++              bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
++      }
++      return ticks;
+ }
+ void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
+@@ -84,28 +212,99 @@ u32 bcma_chipco_gpio_in(struct bcma_drv_
+ u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
+ {
+-      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
++      unsigned long flags;
++      u32 res;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_gpio_out);
+ u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
+ {
+-      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
++      unsigned long flags;
++      u32 res;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen);
++/*
++ * If the bit is set to 0, chipcommon controlls this GPIO,
++ * if the bit is set to 1, it is used by some part of the chip and not our code.
++ */
+ u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
+ {
+-      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
++      unsigned long flags;
++      u32 res;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control);
+ u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value)
+ {
+-      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
++      unsigned long flags;
++      u32 res;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
+ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
+ {
+-      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
++      unsigned long flags;
++      u32 res;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
++}
++
++u32 bcma_chipco_gpio_pullup(struct bcma_drv_cc *cc, u32 mask, u32 value)
++{
++      unsigned long flags;
++      u32 res;
++
++      if (cc->core->id.rev < 20)
++              return 0;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLUP, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
++}
++
++u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value)
++{
++      unsigned long flags;
++      u32 res;
++
++      if (cc->core->id.rev < 20)
++              return 0;
++
++      spin_lock_irqsave(&cc->gpio_lock, flags);
++      res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLDOWN, mask, value);
++      spin_unlock_irqrestore(&cc->gpio_lock, flags);
++
++      return res;
+ }
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+@@ -118,8 +317,7 @@ void bcma_chipco_serial_init(struct bcma
+       struct bcma_serial_port *ports = cc->serial_ports;
+       if (ccrev >= 11 && ccrev != 15) {
+-              /* Fixed ALP clock */
+-              baud_base = bcma_pmu_alp_clock(cc);
++              baud_base = bcma_chipco_get_alp_clock(cc);
+               if (ccrev >= 21) {
+                       /* Turn off UART clock before switching clocksource. */
+                       bcma_cc_write32(cc, BCMA_CC_CORECTL,
+@@ -137,12 +335,11 @@ void bcma_chipco_serial_init(struct bcma
                                       | BCMA_CC_CORECTL_UARTCLKEN);
                }
        } else {
                return;
        }
  
+-      irq = bcma_core_mips_irq(cc->core);
++      irq = bcma_core_irq(cc->core);
+       /* Determine the registers of the UARTs */
+       cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
 --- a/drivers/bcma/driver_chipcommon_pmu.c
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
 @@ -3,7 +3,8 @@
   *
   * Licensed under the GNU/GPL. See COPYING for details.
   */
-@@ -54,38 +55,19 @@ void bcma_chipco_regctl_maskset(struct b
+@@ -12,12 +13,13 @@
+ #include <linux/export.h>
+ #include <linux/bcma/bcma.h>
+-static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
++u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+ {
+       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+       bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+       return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
+ void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
+ {
+@@ -54,19 +56,106 @@ void bcma_chipco_regctl_maskset(struct b
  }
  EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
  
--static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
--{
--      struct bcma_bus *bus = cc->core->bus;
--
--      switch (bus->chipinfo.id) {
++static u32 bcma_pmu_xtalfreq(struct bcma_drv_cc *cc)
++{
++      u32 ilp_ctl, alp_hz;
++
++      if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
++            BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
++              return 0;
++
++      bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
++                      BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
++      usleep_range(1000, 2000);
++
++      ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
++      ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
++
++      bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
++
++      alp_hz = ilp_ctl * 32768 / 4;
++      return (alp_hz + 50000) / 100000 * 100;
++}
++
++static void bcma_pmu2_pll_init0(struct bcma_drv_cc *cc, u32 xtalfreq)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 freq_tgt_target = 0, freq_tgt_current;
++      u32 pll0, mask;
++
++      switch (bus->chipinfo.id) {
++      case BCMA_CHIP_ID_BCM43142:
++              /* pmu2_xtaltab0_adfll_485 */
++              switch (xtalfreq) {
++              case 12000:
++                      freq_tgt_target = 0x50D52;
++                      break;
++              case 20000:
++                      freq_tgt_target = 0x307FE;
++                      break;
++              case 26000:
++                      freq_tgt_target = 0x254EA;
++                      break;
++              case 37400:
++                      freq_tgt_target = 0x19EF8;
++                      break;
++              case 52000:
++                      freq_tgt_target = 0x12A75;
++                      break;
++              }
++              break;
++      }
++
++      if (!freq_tgt_target) {
++              bcma_err(bus, "Unknown TGT frequency for xtalfreq %d\n",
++                       xtalfreq);
++              return;
++      }
++
++      pll0 = bcma_chipco_pll_read(cc, BCMA_CC_PMU15_PLL_PLLCTL0);
++      freq_tgt_current = (pll0 & BCMA_CC_PMU15_PLL_PC0_FREQTGT_MASK) >>
++              BCMA_CC_PMU15_PLL_PC0_FREQTGT_SHIFT;
++
++      if (freq_tgt_current == freq_tgt_target) {
++              bcma_debug(bus, "Target TGT frequency already set\n");
++              return;
++      }
++
++      /* Turn off PLL */
++      switch (bus->chipinfo.id) {
++      case BCMA_CHIP_ID_BCM43142:
++              mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
++                            BCMA_RES_4314_MACPHY_CLK_AVAIL);
++
++              bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
++              bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
++              bcma_wait_value(cc->core, BCMA_CLKCTLST,
++                              BCMA_CLKCTLST_HAVEHT, 0, 20000);
++              break;
++      }
++
++      pll0 &= ~BCMA_CC_PMU15_PLL_PC0_FREQTGT_MASK;
++      pll0 |= freq_tgt_target << BCMA_CC_PMU15_PLL_PC0_FREQTGT_SHIFT;
++      bcma_chipco_pll_write(cc, BCMA_CC_PMU15_PLL_PLLCTL0, pll0);
++
++      /* Flush */
++      if (cc->pmu.rev >= 2)
++              bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
++
++      /* TODO: Do we need to update OTP? */
++}
++
+ static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
+ {
+       struct bcma_bus *bus = cc->core->bus;
++      u32 xtalfreq = bcma_pmu_xtalfreq(cc);
+       switch (bus->chipinfo.id) {
 -      case 0x4313:
 -      case 0x4331:
 -      case 43224:
 -      case 43225:
--              break;
++      case BCMA_CHIP_ID_BCM43142:
++              if (xtalfreq == 0)
++                      xtalfreq = 20000;
++              bcma_pmu2_pll_init0(cc, xtalfreq);
+               break;
 -      default:
 -              pr_err("PLL init unknown for device 0x%04X\n",
 -                      bus->chipinfo.id);
--      }
--}
--
- static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
- {
-       struct bcma_bus *bus = cc->core->bus;
+       }
+ }
+@@ -76,16 +165,32 @@ static void bcma_pmu_resources_init(stru
        u32 min_msk = 0, max_msk = 0;
  
        switch (bus->chipinfo.id) {
                break;
 -      case 43224:
 -      case 43225:
--              break;
++      case BCMA_CHIP_ID_BCM43142:
++              min_msk = BCMA_RES_4314_LPLDO_PU |
++                        BCMA_RES_4314_PMU_SLEEP_DIS |
++                        BCMA_RES_4314_PMU_BG_PU |
++                        BCMA_RES_4314_CBUCK_LPOM_PU |
++                        BCMA_RES_4314_CBUCK_PFM_PU |
++                        BCMA_RES_4314_CLDO_PU |
++                        BCMA_RES_4314_LPLDO2_LVM |
++                        BCMA_RES_4314_WL_PMU_PU |
++                        BCMA_RES_4314_LDO3P3_PU |
++                        BCMA_RES_4314_OTP_PU |
++                        BCMA_RES_4314_WL_PWRSW_PU |
++                        BCMA_RES_4314_LQ_AVAIL |
++                        BCMA_RES_4314_LOGIC_RET |
++                        BCMA_RES_4314_MEM_SLEEP |
++                        BCMA_RES_4314_MACPHY_RET |
++                        BCMA_RES_4314_WL_CORE_READY;
++              max_msk = 0x3FFFFFFF;
+               break;
        default:
 -              pr_err("PMU resource config unknown for device 0x%04X\n",
 -                      bus->chipinfo.id);
        }
  
        /* Set the resource masks. */
-@@ -93,22 +75,9 @@ static void bcma_pmu_resources_init(stru
+@@ -93,22 +198,12 @@ static void bcma_pmu_resources_init(stru
                bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
        if (max_msk)
                bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
 -}
--
 -void bcma_pmu_swreg_init(struct bcma_drv_cc *cc)
 -{
 -      struct bcma_bus *bus = cc->core->bus;
+-
 -      switch (bus->chipinfo.id) {
 -      case 0x4313:
 -      case 0x4331:
 -              pr_err("PMU switch/regulators init unknown for device "
 -                      "0x%04X\n", bus->chipinfo.id);
 -      }
-+      /* Add some delay; allow resources to come up and settle. */
++      /*
++       * Add some delay; allow resources to come up and settle.
++       * Delay is required for SoC (early init).
++       */
 +      mdelay(2);
  }
  
  /* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
-@@ -122,8 +91,11 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
+@@ -122,51 +217,69 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
                val |= BCMA_CHIPCTL_4331_EXTPA_EN;
                if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
                        val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
                val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
        }
        bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
-@@ -134,26 +106,38 @@ void bcma_pmu_workarounds(struct bcma_dr
+ }
+-void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
++static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+ {
        struct bcma_bus *bus = cc->core->bus;
  
        switch (bus->chipinfo.id) {
 +              /* enable 12 mA drive strenth for 4313 and set chipControl
 +                 register bit 1 */
 +              bcma_chipco_chipctl_maskset(cc, 0,
-+                                          BCMA_CCTRL_4313_12MA_LED_DRIVE,
++                                          ~BCMA_CCTRL_4313_12MA_LED_DRIVE,
 +                                          BCMA_CCTRL_4313_12MA_LED_DRIVE);
                break;
 -      case 0x4331:
 -                              "implemented\n");
 -                      bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x00F000F0);
 +                      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL,
-+                                        BCMA_CCTRL_43224_GPIO_TOGGLE,
++                                        ~BCMA_CCTRL_43224_GPIO_TOGGLE,
 +                                        BCMA_CCTRL_43224_GPIO_TOGGLE);
 +                      bcma_chipco_chipctl_maskset(cc, 0,
-+                                                  BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
++                                                  ~BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
 +                                                  BCMA_CCTRL_43224A0_12MA_LED_DRIVE);
                } else {
 -                      bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
 +                      bcma_chipco_chipctl_maskset(cc, 0,
-+                                                  BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
++                                                  ~BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
 +                                                  BCMA_CCTRL_43224B0_12MA_LED_DRIVE);
                }
                break;
        }
  }
  
-@@ -164,8 +148,8 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+-void bcma_pmu_init(struct bcma_drv_cc *cc)
++void bcma_pmu_early_init(struct bcma_drv_cc *cc)
+ {
+       u32 pmucap;
        pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
        cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
  
 -               pmucap);
 +      bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
 +                 cc->pmu.rev, pmucap);
++}
  
++void bcma_pmu_init(struct bcma_drv_cc *cc)
++{
        if (cc->pmu.rev == 1)
                bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
-@@ -174,12 +158,7 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+                             ~BCMA_CC_PMU_CTL_NOILPONW);
+@@ -174,37 +287,48 @@ void bcma_pmu_init(struct bcma_drv_cc *c
                bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
                             BCMA_CC_PMU_CTL_NOILPONW);
  
 -      if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2)
 -              pr_err("Fix for 4329b0 bad LPOM state not implemented!\n");
 -
--      bcma_pmu_pll_init(cc);
+       bcma_pmu_pll_init(cc);
        bcma_pmu_resources_init(cc);
 -      bcma_pmu_swreg_init(cc);
        bcma_pmu_workarounds(cc);
  }
  
-@@ -188,23 +167,22 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
+-u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc)
+ {
        struct bcma_bus *bus = cc->core->bus;
  
        switch (bus->chipinfo.id) {
 -      case 0x5357:
 -      case 0x4749:
 -      case 53572:
++      case BCMA_CHIP_ID_BCM4313:
++      case BCMA_CHIP_ID_BCM43224:
++      case BCMA_CHIP_ID_BCM43225:
++      case BCMA_CHIP_ID_BCM43227:
++      case BCMA_CHIP_ID_BCM43228:
++      case BCMA_CHIP_ID_BCM4331:
++      case BCMA_CHIP_ID_BCM43421:
++      case BCMA_CHIP_ID_BCM43428:
++      case BCMA_CHIP_ID_BCM43431:
 +      case BCMA_CHIP_ID_BCM4716:
-+      case BCMA_CHIP_ID_BCM4748:
 +      case BCMA_CHIP_ID_BCM47162:
-+      case BCMA_CHIP_ID_BCM4313:
-+      case BCMA_CHIP_ID_BCM5357:
++      case BCMA_CHIP_ID_BCM4748:
 +      case BCMA_CHIP_ID_BCM4749:
++      case BCMA_CHIP_ID_BCM5357:
 +      case BCMA_CHIP_ID_BCM53572:
++      case BCMA_CHIP_ID_BCM6362:
                /* always 20Mhz */
                return 20000 * 1000;
 -      case 0x5356:
 -      case 0x5300:
-+      case BCMA_CHIP_ID_BCM5356:
 +      case BCMA_CHIP_ID_BCM4706:
++      case BCMA_CHIP_ID_BCM5356:
                /* always 25Mhz */
                return 25000 * 1000;
++      case BCMA_CHIP_ID_BCM43460:
++      case BCMA_CHIP_ID_BCM4352:
++      case BCMA_CHIP_ID_BCM4360:
++              if (cc->status & BCMA_CC_CHIPST_4360_XTAL_40MZ)
++                      return 40000 * 1000;
++              else
++                      return 20000 * 1000;
        default:
 -              pr_warn("No ALP clock specified for %04X device, "
 -                      "pmu rev. %d, using default %d Hz\n",
        }
        return BCMA_CC_PMU_ALP_CLOCK;
  }
-@@ -221,7 +199,8 @@ static u32 bcma_pmu_clock(struct bcma_dr
+@@ -212,7 +336,7 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
+ /* Find the output of the "m" pll divider given pll controls that start with
+  * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
+  */
+-static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++static u32 bcma_pmu_pll_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
+ {
+       u32 tmp, div, ndiv, p1, p2, fc;
+       struct bcma_bus *bus = cc->core->bus;
+@@ -221,7 +345,8 @@ static u32 bcma_pmu_clock(struct bcma_dr
  
        BUG_ON(!m || m > 4);
  
                /* Detect failure in clock setting */
                tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
                if (tmp & 0x40000)
-@@ -247,33 +226,62 @@ static u32 bcma_pmu_clock(struct bcma_dr
+@@ -240,60 +365,96 @@ static u32 bcma_pmu_clock(struct bcma_dr
+       ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
+       /* Do calculation in Mhz */
+-      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = bcma_pmu_get_alp_clock(cc) / 1000000;
+       fc = (p1 * ndiv * fc) / p2;
+       /* Return clock in Hertz */
        return (fc / div) * 1000000;
  }
  
-+static u32 bcma_pmu_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++static u32 bcma_pmu_pll_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
 +{
 +      u32 tmp, ndiv, p1div, p2div;
 +      u32 clock;
 +}
 +
  /* query bus clock frequency for PMU-enabled chipcommon */
- u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+-u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
  {
        struct bcma_bus *bus = cc->core->bus;
  
 -      case 0x4716:
 -      case 0x4748:
 -      case 47162:
-+      case BCMA_CHIP_ID_BCM4716:
-+      case BCMA_CHIP_ID_BCM4748:
-+      case BCMA_CHIP_ID_BCM47162:
-               return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
-                                     BCMA_CC_PMU5_MAINPLL_SSB);
+-              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
+-                                    BCMA_CC_PMU5_MAINPLL_SSB);
 -      case 0x5356:
-+      case BCMA_CHIP_ID_BCM5356:
-               return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
-                                     BCMA_CC_PMU5_MAINPLL_SSB);
+-              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
+-                                    BCMA_CC_PMU5_MAINPLL_SSB);
 -      case 0x5357:
 -      case 0x4749:
-+      case BCMA_CHIP_ID_BCM5357:
-+      case BCMA_CHIP_ID_BCM4749:
-               return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
-                                     BCMA_CC_PMU5_MAINPLL_SSB);
+-              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
+-                                    BCMA_CC_PMU5_MAINPLL_SSB);
 -      case 0x5300:
 -              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
 -                                    BCMA_CC_PMU5_MAINPLL_SSB);
 -      case 53572:
++      case BCMA_CHIP_ID_BCM4716:
++      case BCMA_CHIP_ID_BCM4748:
++      case BCMA_CHIP_ID_BCM47162:
++              return bcma_pmu_pll_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                        BCMA_CC_PMU5_MAINPLL_SSB);
++      case BCMA_CHIP_ID_BCM5356:
++              return bcma_pmu_pll_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                        BCMA_CC_PMU5_MAINPLL_SSB);
++      case BCMA_CHIP_ID_BCM5357:
++      case BCMA_CHIP_ID_BCM4749:
++              return bcma_pmu_pll_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                        BCMA_CC_PMU5_MAINPLL_SSB);
 +      case BCMA_CHIP_ID_BCM4706:
-+              return bcma_pmu_clock_bcm4706(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
-+                                            BCMA_CC_PMU5_MAINPLL_SSB);
++              return bcma_pmu_pll_clock_bcm4706(cc,
++                                                BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                                BCMA_CC_PMU5_MAINPLL_SSB);
 +      case BCMA_CHIP_ID_BCM53572:
                return 75000000;
        default:
 -              pr_warn("No backplane clock specified for %04X device, "
 -                      "pmu rev. %d, using default %d Hz\n",
 -                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
-+              bcma_warn(bus, "No backplane clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
++              bcma_warn(bus, "No bus clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
 +                        bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
        }
        return BCMA_CC_PMU_HT_CLOCK;
  }
-@@ -283,17 +291,21 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
++EXPORT_SYMBOL_GPL(bcma_pmu_get_bus_clock);
+ /* query cpu clock frequency for PMU-enabled chipcommon */
+-u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc)
  {
        struct bcma_bus *bus = cc->core->bus;
  
 +      if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53572)
                return 300000000;
  
++      /* New PMUs can have different clock for bus and CPU */
        if (cc->pmu.rev >= 5) {
                u32 pll;
                switch (bus->chipinfo.id) {
 -              case 0x5356:
 +              case BCMA_CHIP_ID_BCM4706:
-+                      return bcma_pmu_clock_bcm4706(cc,
++                      return bcma_pmu_pll_clock_bcm4706(cc,
 +                                              BCMA_CC_PMU4706_MAINPLL_PLL0,
 +                                              BCMA_CC_PMU5_MAINPLL_CPU);
 +              case BCMA_CHIP_ID_BCM5356:
                        pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
                        break;
                default:
-@@ -301,10 +313,188 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
+@@ -301,10 +462,189 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
                        break;
                }
  
 -              /* TODO: if (bus->chipinfo.id == 0x5300)
 -                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
-               return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
-       }
-       return bcma_pmu_get_clockcontrol(cc);
- }
+-              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++              return bcma_pmu_pll_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      /* On old PMUs CPU has the same clock as the bus */
++      return bcma_pmu_get_bus_clock(cc);
++}
 +
 +static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
 +                                       u32 value)
 +              tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
 +              bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
 +
-+              tmp = 1 << 10;
++              tmp = BCMA_CC_PMU_CTL_PLL_UPD;
 +              break;
 +
 +      case BCMA_CHIP_ID_BCM4331:
 +                      bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
 +                                                   0x03000a08);
 +              }
-+              tmp = 1 << 10;
++              tmp = BCMA_CC_PMU_CTL_PLL_UPD;
 +              break;
 +
 +      case BCMA_CHIP_ID_BCM43224:
 +                      bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
 +                                                   0x88888815);
 +              }
-+              tmp = 1 << 10;
++              tmp = BCMA_CC_PMU_CTL_PLL_UPD;
 +              break;
 +
 +      case BCMA_CHIP_ID_BCM4716:
 +                                                   0x88888815);
 +              }
 +
-+              tmp = 3 << 9;
++              tmp = BCMA_CC_PMU_CTL_PLL_UPD | BCMA_CC_PMU_CTL_NOILPONW;
 +              break;
 +
 +      case BCMA_CHIP_ID_BCM43227:
 +                      bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
 +                                                   0x88888815);
 +              }
-+              tmp = 1 << 10;
++              tmp = BCMA_CC_PMU_CTL_PLL_UPD;
 +              break;
 +      default:
 +              bcma_err(bus, "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
 +                       bus->chipinfo.id);
 +              break;
-+      }
-+
+       }
+-      return bcma_pmu_get_clockcontrol(cc);
 +      tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL);
 +      bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp);
-+}
+ }
 +EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
 --- /dev/null
 +++ b/drivers/bcma/driver_gmac_cmn.c
 +{
 +      mutex_init(&gc->phy_mutex);
 +}
+--- /dev/null
++++ b/drivers/bcma/driver_gpio.c
+@@ -0,0 +1,114 @@
++/*
++ * Broadcom specific AMBA
++ * GPIO driver
++ *
++ * Copyright 2011, Broadcom Corporation
++ * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/gpio.h>
++#include <linux/export.h>
++#include <linux/bcma/bcma.h>
++
++#include "bcma_private.h"
++
++static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip)
++{
++      return container_of(chip, struct bcma_drv_cc, gpio);
++}
++
++static int bcma_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
++{
++      struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
++
++      return !!bcma_chipco_gpio_in(cc, 1 << gpio);
++}
++
++static void bcma_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
++                              int value)
++{
++      struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
++
++      bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
++}
++
++static int bcma_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
++{
++      struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
++
++      bcma_chipco_gpio_outen(cc, 1 << gpio, 0);
++      return 0;
++}
++
++static int bcma_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
++                                    int value)
++{
++      struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
++
++      bcma_chipco_gpio_outen(cc, 1 << gpio, 1 << gpio);
++      bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
++      return 0;
++}
++
++static int bcma_gpio_request(struct gpio_chip *chip, unsigned gpio)
++{
++      struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
++
++      bcma_chipco_gpio_control(cc, 1 << gpio, 0);
++      /* clear pulldown */
++      bcma_chipco_gpio_pulldown(cc, 1 << gpio, 0);
++      /* Set pullup */
++      bcma_chipco_gpio_pullup(cc, 1 << gpio, 1 << gpio);
++
++      return 0;
++}
++
++static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio)
++{
++      struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
++
++      /* clear pullup */
++      bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
++}
++
++static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
++{
++      struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
++
++      if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
++              return bcma_core_irq(cc->core);
++      else
++              return -EINVAL;
++}
++
++int bcma_gpio_init(struct bcma_drv_cc *cc)
++{
++      struct gpio_chip *chip = &cc->gpio;
++
++      chip->label             = "bcma_gpio";
++      chip->owner             = THIS_MODULE;
++      chip->request           = bcma_gpio_request;
++      chip->free              = bcma_gpio_free;
++      chip->get               = bcma_gpio_get_value;
++      chip->set               = bcma_gpio_set_value;
++      chip->direction_input   = bcma_gpio_direction_input;
++      chip->direction_output  = bcma_gpio_direction_output;
++      chip->to_irq            = bcma_gpio_to_irq;
++      chip->ngpio             = 16;
++      /* There is just one SoC in one device and its GPIO addresses should be
++       * deterministic to address them more easily. The other buses could get
++       * a random base number. */
++      if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
++              chip->base              = 0;
++      else
++              chip->base              = -1;
++
++      return gpiochip_add(chip);
++}
++
++int bcma_gpio_unregister(struct bcma_drv_cc *cc)
++{
++      return gpiochip_remove(&cc->gpio);
++}
 --- a/drivers/bcma/driver_mips.c
 +++ b/drivers/bcma/driver_mips.c
 @@ -22,15 +22,15 @@
               dev->bus->chipinfo.pkg == 11 &&
               dev->id.id == BCMA_CORE_USB20_HOST;
  }
-@@ -143,8 +143,8 @@ static void bcma_core_mips_set_irq(struc
+@@ -74,28 +74,41 @@ static u32 bcma_core_mips_irqflag(struct
+               return dev->core_index;
+       flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
+-      return flag & 0x1F;
++      if (flag)
++              return flag & 0x1F;
++      else
++              return 0x3f;
+ }
+ /* Get the MIPS IRQ assignment for a specified device.
+  * If unassigned, 0 is returned.
++ * If disabled, 5 is returned.
++ * If not supported, 6 is returned.
+  */
+-unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+ {
+       struct bcma_device *mdev = dev->bus->drv_mips.core;
+       u32 irqflag;
+       unsigned int irq;
+       irqflag = bcma_core_mips_irqflag(dev);
++      if (irqflag == 0x3f)
++              return 6;
+-      for (irq = 1; irq <= 4; irq++)
++      for (irq = 0; irq <= 4; irq++)
+               if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
+                   (1 << irqflag))
+                       return irq;
+-      return 0;
++      return 5;
++}
++
++unsigned int bcma_core_irq(struct bcma_device *dev)
++{
++      unsigned int mips_irq = bcma_core_mips_irq(dev);
++      return mips_irq <= 4 ? mips_irq + 2 : 0;
+ }
+-EXPORT_SYMBOL(bcma_core_mips_irq);
++EXPORT_SYMBOL(bcma_core_irq);
+ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+ {
+@@ -114,8 +127,8 @@ static void bcma_core_mips_set_irq(struc
+               bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+                           bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
+                           ~(1 << irqflag));
+-      else
+-              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++      else if (oldirq != 5)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
+       /* assign the new one */
+       if (irq == 0) {
+@@ -123,17 +136,17 @@ static void bcma_core_mips_set_irq(struc
+                           bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
+                           (1 << irqflag));
+       } else {
+-              u32 oldirqflag = bcma_read32(mdev,
+-                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
+-              if (oldirqflag) {
++              u32 irqinitmask = bcma_read32(mdev,
++                                            BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (irqinitmask) {
+                       struct bcma_device *core;
+                       /* backplane irq line is in use, find out who uses
+                        * it and set user to irq 0
+                        */
+-                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                      list_for_each_entry(core, &bus->cores, list) {
+                               if ((1 << bcma_core_mips_irqflag(core)) ==
+-                                  oldirqflag) {
++                                  irqinitmask) {
+                                       bcma_core_mips_set_irq(core, 0);
+                                       break;
+                               }
+@@ -143,15 +156,31 @@ static void bcma_core_mips_set_irq(struc
                             1 << irqflag);
        }
  
 -      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
 -              dev->id.id, oldirq + 2, irq + 2);
-+      bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n",
-+                dev->id.id, oldirq + 2, irq + 2);
++      bcma_debug(bus, "set_irq: core 0x%04x, irq %d => %d\n",
++                 dev->id.id, oldirq <= 4 ? oldirq + 2 : 0, irq + 2);
++}
++
++static void bcma_core_mips_set_irq_name(struct bcma_bus *bus, unsigned int irq,
++                                      u16 coreid, u8 unit)
++{
++      struct bcma_device *core;
++
++      core = bcma_find_core_unit(bus, coreid, unit);
++      if (!core) {
++              bcma_warn(bus,
++                        "Can not find core (id: 0x%x, unit %i) for IRQ configuration.\n",
++                        coreid, unit);
++              return;
++      }
++
++      bcma_core_mips_set_irq(core, irq);
  }
  
  static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
-@@ -173,7 +173,7 @@ u32 bcma_cpu_clock(struct bcma_drv_mips
+ {
+       int i;
+       static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
+-      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      printk(KERN_DEBUG KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+       for (i = 0; i <= 6; i++)
+               printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
+       printk("\n");
+@@ -161,7 +190,7 @@ static void bcma_core_mips_dump_irq(stru
+ {
+       struct bcma_device *core;
+-      list_for_each_entry_reverse(core, &bus->cores, list) {
++      list_for_each_entry(core, &bus->cores, list) {
+               bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
+       }
+ }
+@@ -171,9 +200,9 @@ u32 bcma_cpu_clock(struct bcma_drv_mips
+       struct bcma_bus *bus = mcore->core->bus;
        if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
-               return bcma_pmu_get_clockcpu(&bus->drv_cc);
+-              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++              return bcma_pmu_get_cpu_clock(&bus->drv_cc);
  
 -      pr_err("No PMU available, need this to get the cpu clock\n");
 +      bcma_err(bus, "No PMU available, need this to get the cpu clock\n");
        return 0;
  }
  EXPORT_SYMBOL(bcma_cpu_clock);
-@@ -185,10 +185,10 @@ static void bcma_core_mips_flash_detect(
+@@ -185,10 +214,10 @@ static void bcma_core_mips_flash_detect(
        switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
        case BCMA_CC_FLASHT_STSER:
        case BCMA_CC_FLASHT_ATSER:
                bus->drv_cc.pflash.window = 0x1c000000;
                bus->drv_cc.pflash.window_size = 0x02000000;
  
-@@ -199,7 +199,7 @@ static void bcma_core_mips_flash_detect(
+@@ -199,7 +228,46 @@ static void bcma_core_mips_flash_detect(
                        bus->drv_cc.pflash.buswidth = 2;
                break;
        default:
 -              pr_err("flash not supported.\n");
 +              bcma_err(bus, "flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (mcore->early_setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++
++      mcore->early_setup_done = true;
++}
++
++static void bcma_fix_i2s_irqflag(struct bcma_bus *bus)
++{
++      struct bcma_device *cpu, *pcie, *i2s;
++
++      /* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK)
++       * (IRQ flags > 7 are ignored when setting the interrupt masks)
++       */
++      if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4716 &&
++          bus->chipinfo.id != BCMA_CHIP_ID_BCM4748)
++              return;
++
++      cpu = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      pcie = bcma_find_core(bus, BCMA_CORE_PCIE);
++      i2s = bcma_find_core(bus, BCMA_CORE_I2S);
++      if (cpu && pcie && i2s &&
++          bcma_aread32(cpu, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
++          bcma_aread32(pcie, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
++          bcma_aread32(i2s, BCMA_MIPS_OOBSELOUTA30) == 0x88) {
++              bcma_awrite32(cpu, BCMA_MIPS_OOBSELINA74, 0x07060504);
++              bcma_awrite32(pcie, BCMA_MIPS_OOBSELINA74, 0x07060504);
++              bcma_awrite32(i2s, BCMA_MIPS_OOBSELOUTA30, 0x87);
++              bcma_debug(bus,
++                         "Moved i2s interrupt to oob line 7 instead of 8\n");
        }
  }
  
-@@ -209,7 +209,7 @@ void bcma_core_mips_init(struct bcma_drv
+@@ -209,48 +277,59 @@ void bcma_core_mips_init(struct bcma_drv
        struct bcma_device *core;
        bus = mcore->core->bus;
  
 -      pr_info("Initializing MIPS core...\n");
-+      bcma_info(bus, "Initializing MIPS core...\n");
++      if (mcore->setup_done)
++              return;
++
++      bcma_debug(bus, "Initializing MIPS core...\n");
  
-       if (!mcore->setup_done)
-               mcore->assigned_irqs = 1;
-@@ -244,7 +244,7 @@ void bcma_core_mips_init(struct bcma_drv
-                       break;
+-      if (!mcore->setup_done)
+-              mcore->assigned_irqs = 1;
++      bcma_core_mips_early_init(mcore);
+-      /* Assign IRQs to all cores on the bus */
+-      list_for_each_entry_reverse(core, &bus->cores, list) {
+-              int mips_irq;
+-              if (core->irq)
+-                      continue;
+-
+-              mips_irq = bcma_core_mips_irq(core);
+-              if (mips_irq > 4)
+-                      core->irq = 0;
+-              else
+-                      core->irq = mips_irq + 2;
+-              if (core->irq > 5)
+-                      continue;
+-              switch (core->id.id) {
+-              case BCMA_CORE_PCI:
+-              case BCMA_CORE_PCIE:
+-              case BCMA_CORE_ETHERNET:
+-              case BCMA_CORE_ETHERNET_GBIT:
+-              case BCMA_CORE_MAC_GBIT:
+-              case BCMA_CORE_80211:
+-              case BCMA_CORE_USB20_HOST:
+-                      /* These devices get their own IRQ line if available,
+-                       * the rest goes on IRQ0
+-                       */
+-                      if (mcore->assigned_irqs <= 4)
+-                              bcma_core_mips_set_irq(core,
+-                                                     mcore->assigned_irqs++);
+-                      break;
++      bcma_fix_i2s_irqflag(bus);
++
++      switch (bus->chipinfo.id) {
++      case BCMA_CHIP_ID_BCM4716:
++      case BCMA_CHIP_ID_BCM4748:
++              bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
++              bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
++              bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
++              bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_PCIE, 0);
++              bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
++              bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
++              break;
++      case BCMA_CHIP_ID_BCM5356:
++      case BCMA_CHIP_ID_BCM47162:
++      case BCMA_CHIP_ID_BCM53572:
++              bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
++              bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
++              bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
++              break;
++      case BCMA_CHIP_ID_BCM5357:
++      case BCMA_CHIP_ID_BCM4749:
++              bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
++              bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
++              bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
++              bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
++              bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
++              break;
++      case BCMA_CHIP_ID_BCM4706:
++              bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_PCIE, 0);
++              bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_4706_MAC_GBIT,
++                                          0);
++              bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_PCIE, 1);
++              bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_USB20_HOST, 0);
++              bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_4706_CHIPCOMMON,
++                                          0);
++              break;
++      default:
++              list_for_each_entry(core, &bus->cores, list) {
++                      core->irq = bcma_core_irq(core);
                }
++              bcma_err(bus,
++                       "Unknown device (0x%x) found, can not configure IRQs\n",
++                       bus->chipinfo.id);
        }
 -      pr_info("IRQ reconfiguration done\n");
-+      bcma_info(bus, "IRQ reconfiguration done\n");
++      bcma_debug(bus, "IRQ reconfiguration done\n");
        bcma_core_mips_dump_irq(bus);
  
-       if (mcore->setup_done)
+-      if (mcore->setup_done)
+-              return;
+-
+-      bcma_chipco_serial_init(&bus->drv_cc);
+-      bcma_core_mips_flash_detect(mcore);
+       mcore->setup_done = true;
+ }
 --- a/drivers/bcma/driver_pci.c
 +++ b/drivers/bcma/driver_pci.c
 @@ -2,8 +2,9 @@
   *
   * Licensed under the GNU/GPL. See COPYING for details.
   */
-@@ -16,40 +17,39 @@
+@@ -16,120 +17,124 @@
   * R/W ops.
   **************************************************/
  
 +              v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
 +              if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
                        break;
-               msleep(1);
+-              msleep(1);
++              usleep_range(1000, 2000);
        }
-@@ -57,79 +57,84 @@ static void bcma_pcie_mdio_set_phy(struc
+ }
  
  static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
  {
 +                      ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA);
                        break;
                }
-               msleep(1);
+-              msleep(1);
++              usleep_range(1000, 2000);
        }
 -      pcicore_write32(pc, mdio_control, 0);
 +      pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
 +              v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
 +              if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
                        break;
-               msleep(1);
+-              msleep(1);
++              usleep_range(1000, 2000);
        }
 -      pcicore_write32(pc, mdio_control, 0);
 +      pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
 +EXPORT_SYMBOL_GPL(bcma_core_pci_extend_L1timer);
 --- a/drivers/bcma/driver_pci_host.c
 +++ b/drivers/bcma/driver_pci_host.c
-@@ -2,13 +2,592 @@
+@@ -2,13 +2,616 @@
   * Broadcom specific AMBA
   * PCI Core in hostmode
   *
 +          chipid_top != 0x5300)
 +              return false;
 +
-+      if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
-+              bcma_info(bus, "This PCI core is disabled and not working\n");
-+              return false;
-+      }
-+
 +      bcma_core_enable(pc->core, 0);
 +
 +      return !mips_busprobe32(tmp, pc->core->io_addr);
 +out:
 +      return addr;
 +}
--void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
++
 +static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
 +                                unsigned int func, unsigned int off,
 +                                void *buf, int len)
- {
--      pr_err("No support for PCI core in hostmode yet\n");
++{
 +      int err = -EINVAL;
 +      u32 addr, val;
 +      void __iomem *mmio = 0;
 +      if (dev == 0) {
 +              /* we support only two functions on device 0 */
 +              if (func > 1)
-+                      return -EINVAL;
++                      goto out;
 +
 +              /* accesses to config registers with offsets >= 256
 +               * requires indirect access.
 +               */
 +              if (off >= PCI_CONFIG_SPACE_SIZE) {
 +                      addr = (func << 12);
-+                      addr |= (off & 0x0FFF);
++                      addr |= (off & 0x0FFC);
 +                      val = bcma_pcie_read_config(pc, addr);
 +              } else {
 +                      addr = BCMA_CORE_PCI_PCICFG0;
 +                      addr |= (func << 8);
-+                      addr |= (off & 0xfc);
++                      addr |= (off & 0xFC);
 +                      val = pcicore_read32(pc, addr);
 +              }
 +      } else {
 +                      goto out;
 +
 +              if (mips_busprobe32(val, mmio)) {
-+                      val = 0xffffffff;
++                      val = 0xFFFFFFFF;
 +                      goto unmap;
 +              }
-+
-+              val = readl(mmio);
 +      }
 +      val >>= (8 * (off & 3));
 +
 +out:
 +      return err;
 +}
-+
+-void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
 +static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
 +                                 unsigned int func, unsigned int off,
 +                                 const void *buf, int len)
-+{
+ {
+-      pr_err("No support for PCI core in hostmode yet\n");
 +      int err = -EINVAL;
-+      u32 addr = 0, val = 0;
++      u32 addr, val;
 +      void __iomem *mmio = 0;
 +      u16 chipid = pc->core->bus->chipinfo.id;
 +
 +      if (unlikely(len != 1 && len != 2 && len != 4))
 +              goto out;
 +      if (dev == 0) {
++              /* we support only two functions on device 0 */
++              if (func > 1)
++                      goto out;
++
 +              /* accesses to config registers with offsets >= 256
 +               * requires indirect access.
 +               */
-+              if (off < PCI_CONFIG_SPACE_SIZE) {
-+                      addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
++              if (off >= PCI_CONFIG_SPACE_SIZE) {
++                      addr = (func << 12);
++                      addr |= (off & 0x0FFC);
++                      val = bcma_pcie_read_config(pc, addr);
++              } else {
++                      addr = BCMA_CORE_PCI_PCICFG0;
 +                      addr |= (func << 8);
-+                      addr |= (off & 0xfc);
-+                      mmio = ioremap_nocache(addr, sizeof(val));
-+                      if (!mmio)
-+                              goto out;
++                      addr |= (off & 0xFC);
++                      val = pcicore_read32(pc, addr);
 +              }
 +      } else {
 +              addr = bcma_get_cfgspace_addr(pc, dev, func, off);
 +                      goto out;
 +
 +              if (mips_busprobe32(val, mmio)) {
-+                      val = 0xffffffff;
++                      val = 0xFFFFFFFF;
 +                      goto unmap;
 +              }
 +      }
 +
 +      switch (len) {
 +      case 1:
-+              val = readl(mmio);
 +              val &= ~(0xFF << (8 * (off & 3)));
 +              val |= *((const u8 *)buf) << (8 * (off & 3));
 +              break;
 +      case 2:
-+              val = readl(mmio);
 +              val &= ~(0xFFFF << (8 * (off & 3)));
 +              val |= *((const u16 *)buf) << (8 * (off & 3));
 +              break;
 +              val = *((const u32 *)buf);
 +              break;
 +      }
-+      if (dev == 0 && !addr) {
++      if (dev == 0) {
 +              /* accesses to config registers with offsets >= 256
 +               * requires indirect access.
 +               */
-+              addr = (func << 12);
-+              addr |= (off & 0x0FFF);
-+              bcma_pcie_write_config(pc, addr, val);
++              if (off >= PCI_CONFIG_SPACE_SIZE)
++                      bcma_pcie_write_config(pc, addr, val);
++              else
++                      pcicore_write32(pc, addr, val);
 +      } else {
 +              writel(val, mmio);
 +
 +      /* check for Header type 0 */
 +      bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val,
 +                              sizeof(u8));
-+      if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
++      if ((byte_val & 0x7F) != PCI_HEADER_TYPE_NORMAL)
 +              return cap_ptr;
 +
 +      /* check if the capability pointer field exists */
 +
 +      bcma_info(bus, "PCIEcore in host mode found\n");
 +
++      if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
++              bcma_info(bus, "This PCIE core is disabled and not working\n");
++              return;
++      }
++
 +      pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
 +      if (!pc_host)  {
 +              bcma_err(bus, "can not allocate memory");
 +              return;
 +      }
 +
++      spin_lock_init(&pc_host->cfgspace_lock);
++
 +      pc->host_controller = pc_host;
 +      pc_host->pci_controller.io_resource = &pc_host->io_resource;
 +      pc_host->pci_controller.mem_resource = &pc_host->mem_resource;
 +      pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
 +
 +      /* Reset RC */
-+      udelay(3000);
++      usleep_range(3000, 5000);
 +      pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
-+      udelay(1000);
++      msleep(50);
 +      pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
 +                      BCMA_CORE_PCI_CTL_RST_OE);
 +
 +                      pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
 +                      pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
 +                                                  BCMA_SOC_PCI_MEM_SZ - 1;
++                      pc_host->io_resource.start = 0x100;
++                      pc_host->io_resource.end = 0x47F;
 +                      pci_membase_1G = BCMA_SOC_PCIE_DMA_H32;
 +                      pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
 +                                      tmp | BCMA_SOC_PCI_MEM);
 +                      pc_host->mem_resource.start = BCMA_SOC_PCI1_MEM;
 +                      pc_host->mem_resource.end = BCMA_SOC_PCI1_MEM +
 +                                                  BCMA_SOC_PCI_MEM_SZ - 1;
++                      pc_host->io_resource.start = 0x480;
++                      pc_host->io_resource.end = 0x7FF;
 +                      pci_membase_1G = BCMA_SOC_PCIE1_DMA_H32;
 +                      pc_host->host_cfg_addr = BCMA_SOC_PCI1_CFG;
 +                      pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
 +       * before issuing configuration requests to PCI Express
 +       * devices.
 +       */
-+      udelay(100000);
++      msleep(100);
 +
 +      bcma_core_pci_enable_crs(pc);
 +
++      if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706 ||
++          bus->chipinfo.id == BCMA_CHIP_ID_BCM4716) {
++              u16 val16;
++              bcma_extpci_read_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
++                                      &val16, sizeof(val16));
++              val16 |= (2 << 5);      /* Max payload size of 512 */
++              val16 |= (2 << 12);     /* MRRS 512 */
++              bcma_extpci_write_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
++                                       &val16, sizeof(val16));
++      }
++
 +      /* Enable PCI bridge BAR0 memory & master access */
 +      tmp = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
 +      bcma_extpci_write_config(pc, 0, 0, PCI_COMMAND, &tmp, sizeof(tmp));
 +      set_io_port_base(pc_host->pci_controller.io_map_base);
 +      /* Give some time to the PCI controller to configure itself with the new
 +       * values. Not waiting at this point causes crashes of the machine. */
-+      mdelay(10);
++      usleep_range(10000, 15000);
 +      register_pci_controller(&pc_host->pci_controller);
 +      return;
 +}
 +static void bcma_core_pci_fixup_addresses(struct pci_dev *dev)
 +{
 +      struct resource *res;
-+      int pos;
++      int pos, err;
 +
 +      if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
 +              /* This is not a device on the PCI-core bridge. */
 +
 +      for (pos = 0; pos < 6; pos++) {
 +              res = &dev->resource[pos];
-+              if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM))
-+                      pci_assign_resource(dev, pos);
++              if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM)) {
++                      err = pci_assign_resource(dev, pos);
++                      if (err)
++                              pr_err("PCI: Problem fixing up the addresses on %s\n",
++                                     pci_name(dev));
++              }
 +      }
 +}
 +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_addresses);
 +      pr_info("PCI: Fixing up device %s\n", pci_name(dev));
 +
 +      /* Fix up interrupt lines */
-+      dev->irq = bcma_core_mips_irq(pc_host->pdev->core) + 2;
++      dev->irq = bcma_core_irq(pc_host->pdev->core);
 +      pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 +
 +      return 0;
 +
 +      pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
 +                             pci_ops);
-+      return bcma_core_mips_irq(pc_host->pdev->core) + 2;
++      return bcma_core_irq(pc_host->pdev->core);
  }
 +EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
 --- a/drivers/bcma/host_pci.c
  }
  
  /* Provides access to the requested core. Returns base offset that has to be
-@@ -154,8 +154,8 @@ const struct bcma_host_ops bcma_host_pci
+@@ -77,8 +77,8 @@ static void bcma_host_pci_write32(struct
+ }
+ #ifdef CONFIG_BCMA_BLOCKIO
+-void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
+-                            size_t count, u16 offset, u8 reg_width)
++static void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
+ {
+       void __iomem *addr = core->bus->mmio + offset;
+       if (core->bus->mapped_core != core)
+@@ -100,8 +100,9 @@ void bcma_host_pci_block_read(struct bcm
+       }
+ }
+-void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer,
+-                             size_t count, u16 offset, u8 reg_width)
++static void bcma_host_pci_block_write(struct bcma_device *core,
++                                    const void *buffer, size_t count,
++                                    u16 offset, u8 reg_width)
+ {
+       void __iomem *addr = core->bus->mmio + offset;
+       if (core->bus->mapped_core != core)
+@@ -139,7 +140,7 @@ static void bcma_host_pci_awrite32(struc
+       iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
+ }
+-const struct bcma_host_ops bcma_host_pci_ops = {
++static const struct bcma_host_ops bcma_host_pci_ops = {
+       .read8          = bcma_host_pci_read8,
+       .read16         = bcma_host_pci_read16,
+       .read32         = bcma_host_pci_read32,
+@@ -154,8 +155,8 @@ const struct bcma_host_ops bcma_host_pci
        .awrite32       = bcma_host_pci_awrite32,
  };
  
  {
        struct bcma_bus *bus;
        int err = -ENOMEM;
-@@ -188,7 +188,7 @@ static int bcma_host_pci_probe(struct pc
+@@ -188,7 +189,7 @@ static int bcma_host_pci_probe(struct pc
  
        /* SSB needed additional powering up, do we have any AMBA PCI cards? */
        if (!pci_is_pcie(dev))
  
        /* Map MMIO */
        err = -ENOMEM;
-@@ -201,6 +201,9 @@ static int bcma_host_pci_probe(struct pc
+@@ -201,6 +202,9 @@ static int bcma_host_pci_probe(struct pc
        bus->hosttype = BCMA_HOSTTYPE_PCI;
        bus->ops = &bcma_host_pci_ops;
  
        /* Register */
        err = bcma_bus_register(bus);
        if (err)
-@@ -222,7 +225,7 @@ err_kfree_bus:
+@@ -222,7 +226,7 @@ err_kfree_bus:
        return err;
  }
  
  {
        struct bcma_bus *bus = pci_get_drvdata(dev);
  
-@@ -265,6 +268,7 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bc
+@@ -234,7 +238,7 @@ static void bcma_host_pci_remove(struct
+       pci_set_drvdata(dev, NULL);
+ }
+-#ifdef CONFIG_PM
++#ifdef CONFIG_PM_SLEEP
+ static int bcma_host_pci_suspend(struct device *dev)
+ {
+       struct pci_dev *pdev = to_pci_dev(dev);
+@@ -257,17 +261,21 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bc
+                        bcma_host_pci_resume);
+ #define BCMA_PM_OPS   (&bcma_pm_ops)
+-#else /* CONFIG_PM */
++#else /* CONFIG_PM_SLEEP */
+ #define BCMA_PM_OPS     NULL
+-#endif /* CONFIG_PM */
++#endif /* CONFIG_PM_SLEEP */
  
  static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
-@@ -277,7 +281,7 @@ static struct pci_driver bcma_pci_bridge
++      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
++      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
++      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
+       { 0, },
+ };
+@@ -277,7 +285,7 @@ static struct pci_driver bcma_pci_bridge
        .name = "bcma-pci-bridge",
        .id_table = bcma_pci_bridge_tbl,
        .probe = bcma_host_pci_probe,
        .driver.pm = BCMA_PM_OPS,
  };
  
+--- a/drivers/bcma/host_soc.c
++++ b/drivers/bcma/host_soc.c
+@@ -143,7 +143,7 @@ static void bcma_host_soc_awrite32(struc
+       writel(value, core->io_wrap + offset);
+ }
+-const struct bcma_host_ops bcma_host_soc_ops = {
++static const struct bcma_host_ops bcma_host_soc_ops = {
+       .read8          = bcma_host_soc_read8,
+       .read16         = bcma_host_soc_read16,
+       .read32         = bcma_host_soc_read32,
 --- a/drivers/bcma/main.c
 +++ b/drivers/bcma/main.c
 @@ -13,6 +13,12 @@
  {
        struct bcma_device *core;
  
-@@ -65,6 +78,7 @@ static struct bcma_device *bcma_find_cor
+@@ -65,6 +78,38 @@ static struct bcma_device *bcma_find_cor
        }
        return NULL;
  }
 +EXPORT_SYMBOL_GPL(bcma_find_core);
++
++struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
++                                      u8 unit)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->id.id == coreid && core->core_unit == unit)
++                      return core;
++      }
++      return NULL;
++}
++
++bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
++                   int timeout)
++{
++      unsigned long deadline = jiffies + timeout;
++      u32 val;
++
++      do {
++              val = bcma_read32(core, reg);
++              if ((val & mask) == value)
++                      return true;
++              cpu_relax();
++              udelay(10);
++      } while (!time_after_eq(jiffies, deadline));
++
++      bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg);
++
++      return false;
++}
  
  static void bcma_release_core_dev(struct device *dev)
  {
-@@ -84,16 +98,18 @@ static int bcma_register_cores(struct bc
+@@ -84,16 +129,23 @@ static int bcma_register_cores(struct bc
        list_for_each_entry(core, &bus->cores, list) {
                /* We support that cores ourself */
                switch (core->id.id) {
                        continue;
                }
  
++              /* Only first GMAC core on BCM4706 is connected and working */
++              if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
++                  core->core_unit > 0)
++                      continue;
++
                core->dev.release = bcma_release_core_dev;
                core->dev.bus = &bcma_bus_type;
 -              dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
  
                switch (bus->hosttype) {
                case BCMA_HOSTTYPE_PCI:
-@@ -111,8 +127,9 @@ static int bcma_register_cores(struct bc
+@@ -111,41 +163,75 @@ static int bcma_register_cores(struct bc
  
                err = device_register(&core->dev);
                if (err) {
                        continue;
                }
                core->dev_registered = true;
-@@ -132,20 +149,24 @@ static void bcma_unregister_cores(struct
+               dev_id++;
+       }
++      err = bcma_gpio_init(&bus->drv_cc);
++      if (err == -ENOTSUPP)
++              bcma_debug(bus, "GPIO driver not activated\n");
++      else if (err)
++              bcma_err(bus, "Error registering GPIO driver: %i\n", err);
++
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              err = bcma_chipco_watchdog_register(&bus->drv_cc);
++              if (err)
++                      bcma_err(bus, "Error registering watchdog driver\n");
++      }
++
+       return 0;
+ }
+ static void bcma_unregister_cores(struct bcma_bus *bus)
+ {
+-      struct bcma_device *core;
++      struct bcma_device *core, *tmp;
+-      list_for_each_entry(core, &bus->cores, list) {
++      list_for_each_entry_safe(core, tmp, &bus->cores, list) {
++              list_del(&core->list);
+               if (core->dev_registered)
+                       device_unregister(&core->dev);
        }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              platform_device_unregister(bus->drv_cc.watchdog);
  }
  
 -int bcma_bus_register(struct bcma_bus *bus)
                return -1;
        }
  
++      /* Early init CC core */
++      core = bcma_find_core(bus, bcma_cc_core_id(bus));
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_early_init(&bus->drv_cc);
++      }
++
++      /* Try to get SPROM */
++      err = bcma_sprom_get(bus);
++      if (err == -ENOENT) {
++              bcma_err(bus, "No SPROM available\n");
++      } else if (err)
++              bcma_err(bus, "Failed to get SPROM: %d\n", err);
++
        /* Init CC core */
 -      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
 +      core = bcma_find_core(bus, bcma_cc_core_id(bus));
        if (core) {
                bus->drv_cc.core = core;
                bcma_core_chipcommon_init(&bus->drv_cc);
-@@ -165,17 +186,24 @@ int bcma_bus_register(struct bcma_bus *b
-               bcma_core_pci_init(&bus->drv_pci);
+@@ -159,30 +245,54 @@ int bcma_bus_register(struct bcma_bus *b
+       }
+       /* Init PCIE core */
+-      core = bcma_find_core(bus, BCMA_CORE_PCIE);
++      core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 0);
+       if (core) {
+-              bus->drv_pci.core = core;
+-              bcma_core_pci_init(&bus->drv_pci);
++              bus->drv_pci[0].core = core;
++              bcma_core_pci_init(&bus->drv_pci[0]);
        }
  
+-      /* Try to get SPROM */
+-      err = bcma_sprom_get(bus);
+-      if (err == -ENOENT) {
+-              pr_err("No SPROM available\n");
+-      } else if (err)
+-              pr_err("Failed to get SPROM: %d\n", err);
++      /* Init PCIE core */
++      core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1);
++      if (core) {
++              bus->drv_pci[1].core = core;
++              bcma_core_pci_init(&bus->drv_pci[1]);
++      }
++
 +      /* Init GBIT MAC COMMON core */
 +      core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
 +      if (core) {
 +              bus->drv_gmac_cmn.core = core;
 +              bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
 +      }
-+
-       /* Try to get SPROM */
-       err = bcma_sprom_get(bus);
-       if (err == -ENOENT) {
--              pr_err("No SPROM available\n");
-+              bcma_err(bus, "No SPROM available\n");
-       } else if (err)
--              pr_err("Failed to get SPROM: %d\n", err);
-+              bcma_err(bus, "Failed to get SPROM: %d\n", err);
  
        /* Register found cores */
        bcma_register_cores(bus);
  
        return 0;
  }
-@@ -196,14 +224,14 @@ int __init bcma_bus_early_register(struc
+ void bcma_bus_unregister(struct bcma_bus *bus)
+ {
++      struct bcma_device *cores[3];
++      int err;
++
++      err = bcma_gpio_unregister(&bus->drv_cc);
++      if (err == -EBUSY)
++              bcma_err(bus, "Some GPIOs are still in use.\n");
++      else if (err)
++              bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
++
++      cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
++      cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
++
+       bcma_unregister_cores(bus);
++
++      kfree(cores[2]);
++      kfree(cores[1]);
++      kfree(cores[0]);
+ }
+ int __init bcma_bus_early_register(struct bcma_bus *bus,
+@@ -196,14 +306,14 @@ int __init bcma_bus_early_register(struc
        bcma_init_bus(bus);
  
        match.manuf = BCMA_MANUF_BCM;
                return -1;
        }
  
-@@ -215,12 +243,12 @@ int __init bcma_bus_early_register(struc
+@@ -215,25 +325,25 @@ int __init bcma_bus_early_register(struc
        /* Scan for mips core */
        err = bcma_bus_scan_early(bus, &match, core_mips);
        if (err) {
                return -1;
        }
  
-       /* Init CC core */
+-      /* Init CC core */
 -      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      /* Early init CC core */
 +      core = bcma_find_core(bus, bcma_cc_core_id(bus));
        if (core) {
                bus->drv_cc.core = core;
-               bcma_core_chipcommon_init(&bus->drv_cc);
-@@ -233,7 +261,7 @@ int __init bcma_bus_early_register(struc
-               bcma_core_mips_init(&bus->drv_mips);
+-              bcma_core_chipcommon_init(&bus->drv_cc);
++              bcma_core_chipcommon_early_init(&bus->drv_cc);
+       }
+-      /* Init MIPS core */
++      /* Early init MIPS core */
+       core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+       if (core) {
+               bus->drv_mips.core = core;
+-              bcma_core_mips_init(&bus->drv_mips);
++              bcma_core_mips_early_init(&bus->drv_mips);
        }
  
 -      pr_info("Early bus registered\n");
  
        return 0;
  }
-@@ -259,8 +287,7 @@ int bcma_bus_resume(struct bcma_bus *bus
+@@ -259,8 +369,7 @@ int bcma_bus_resume(struct bcma_bus *bus
        struct bcma_device *core;
  
        /* Init CC core */
        { BCMA_CORE_MAC_GBIT, "GBit MAC" },
        { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
        { BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
-@@ -79,16 +86,41 @@ struct bcma_device_id_name bcma_device_n
+@@ -77,18 +84,45 @@ struct bcma_device_id_name bcma_device_n
+       { BCMA_CORE_I2S, "I2S" },
+       { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
        { BCMA_CORE_SHIM, "SHIM" },
++      { BCMA_CORE_PCIE2, "PCIe Gen2" },
++      { BCMA_CORE_ARM_CR4, "ARM CR4" },
        { BCMA_CORE_DEFAULT, "Default" },
  };
 -const char *bcma_device_name(struct bcma_device_id *id)
 +              break;
 +      default:
 +              return "UNKNOWN";
-+      }
+       }
 +
 +      for (i = 0; i < size; i++) {
 +              if (names[i].id == id->id)
 +                      return names[i].name;
-       }
++      }
 +
        return "UNKNOWN";
  }
  
-@@ -212,6 +244,17 @@ static struct bcma_device *bcma_find_cor
+@@ -105,19 +139,19 @@ static void bcma_scan_switch_core(struct
+                                      addr);
+ }
+-static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr)
++static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 __iomem **eromptr)
+ {
+       u32 ent = readl(*eromptr);
+       (*eromptr)++;
+       return ent;
+ }
+-static void bcma_erom_push_ent(u32 **eromptr)
++static void bcma_erom_push_ent(u32 __iomem **eromptr)
+ {
+       (*eromptr)--;
+ }
+-static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr)
++static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 __iomem **eromptr)
+ {
+       u32 ent = bcma_erom_get_ent(bus, eromptr);
+       if (!(ent & SCAN_ER_VALID))
+@@ -127,14 +161,14 @@ static s32 bcma_erom_get_ci(struct bcma_
+       return ent;
+ }
+-static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr)
++static bool bcma_erom_is_end(struct bcma_bus *bus, u32 __iomem **eromptr)
+ {
+       u32 ent = bcma_erom_get_ent(bus, eromptr);
+       bcma_erom_push_ent(eromptr);
+       return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
+ }
+-static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr)
++static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 __iomem **eromptr)
+ {
+       u32 ent = bcma_erom_get_ent(bus, eromptr);
+       bcma_erom_push_ent(eromptr);
+@@ -143,7 +177,7 @@ static bool bcma_erom_is_bridge(struct b
+               ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
+ }
+-static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr)
++static void bcma_erom_skip_component(struct bcma_bus *bus, u32 __iomem **eromptr)
+ {
+       u32 ent;
+       while (1) {
+@@ -157,7 +191,7 @@ static void bcma_erom_skip_component(str
+       bcma_erom_push_ent(eromptr);
+ }
+-static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr)
++static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
+ {
+       u32 ent = bcma_erom_get_ent(bus, eromptr);
+       if (!(ent & SCAN_ER_VALID))
+@@ -167,7 +201,7 @@ static s32 bcma_erom_get_mst_port(struct
+       return ent;
+ }
+-static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
++static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
+                                 u32 type, u8 port)
+ {
+       u32 addrl, addrh, sizel, sizeh = 0;
+@@ -212,6 +246,17 @@ static struct bcma_device *bcma_find_cor
        return NULL;
  }
  
  static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                              struct bcma_device_id *match, int core_num,
                              struct bcma_device *core)
-@@ -252,11 +295,15 @@ static int bcma_get_next_core(struct bcm
+@@ -252,11 +297,15 @@ static int bcma_get_next_core(struct bcm
  
        /* check if component is a core at all */
        if (wrappers[0] + wrappers[1] == 0) {
        }
  
        if (bcma_erom_is_bridge(bus, eromptr)) {
-@@ -286,6 +333,23 @@ static int bcma_get_next_core(struct bcm
+@@ -286,6 +335,23 @@ static int bcma_get_next_core(struct bcm
                        return -EILSEQ;
        }
  
        /* get & parse slave ports */
        for (i = 0; i < ports[1]; i++) {
                for (j = 0; ; j++) {
-@@ -298,7 +362,7 @@ static int bcma_get_next_core(struct bcm
+@@ -298,7 +364,7 @@ static int bcma_get_next_core(struct bcm
                                break;
                        } else {
                                if (i == 0 && j == 0)
                        }
                }
        }
-@@ -353,6 +417,7 @@ static int bcma_get_next_core(struct bcm
+@@ -353,6 +419,7 @@ static int bcma_get_next_core(struct bcm
  void bcma_init_bus(struct bcma_bus *bus)
  {
        s32 tmp;
  
        if (bus->init_done)
                return;
-@@ -363,9 +428,12 @@ void bcma_init_bus(struct bcma_bus *bus)
+@@ -363,9 +430,12 @@ void bcma_init_bus(struct bcma_bus *bus)
        bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
  
        tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
        bus->init_done = true;
  }
  
-@@ -392,6 +460,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
+@@ -392,9 +462,12 @@ int bcma_bus_scan(struct bcma_bus *bus)
        bcma_scan_switch_core(bus, erombase);
  
        while (eromptr < eromend) {
 +              struct bcma_device *other_core;
                struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
-               if (!core)
-                       return -ENOMEM;
-@@ -414,14 +483,15 @@ int bcma_bus_scan(struct bcma_bus *bus)
+-              if (!core)
+-                      return -ENOMEM;
++              if (!core) {
++                      err = -ENOMEM;
++                      goto out;
++              }
+               INIT_LIST_HEAD(&core->list);
+               core->bus = bus;
+@@ -409,25 +482,28 @@ int bcma_bus_scan(struct bcma_bus *bus)
+                       } else if (err == -ESPIPE) {
+                               break;
+                       }
+-                      return err;
++                      goto out;
+               }
  
                core->core_index = core_num++;
                bus->nr_cores++;
 +              list_add_tail(&core->list, &bus->cores);
        }
  
++      err = 0;
++out:
        if (bus->hosttype == BCMA_HOSTTYPE_SOC)
-@@ -471,13 +541,12 @@ int __init bcma_bus_scan_early(struct bc
+               iounmap(eromptr);
+-      return 0;
++      return err;
+ }
+ int __init bcma_bus_scan_early(struct bcma_bus *bus,
+@@ -467,21 +543,21 @@ int __init bcma_bus_scan_early(struct bc
+               else if (err == -ESPIPE)
+                       break;
+               else if (err < 0)
+-                      return err;
++                      goto out;
  
                core->core_index = core_num++;
                bus->nr_cores++;
                err = 0;
                break;
        }
++out:
+       if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+               iounmap(eromptr);
 --- a/drivers/bcma/scan.h
 +++ b/drivers/bcma/scan.h
 @@ -27,7 +27,7 @@
   * Licensed under the GNU/GPL. See COPYING for details.
   */
  
-@@ -14,7 +16,57 @@
+@@ -14,18 +16,68 @@
  #include <linux/dma-mapping.h>
  #include <linux/slab.h>
  
  
  /**************************************************
   * R/W ops.
-@@ -124,10 +176,37 @@ static int bcma_sprom_valid(const u16 *s
+  **************************************************/
+-static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
++static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
++                          size_t words)
+ {
+       int i;
+-      for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
+-              sprom[i] = bcma_read16(bus->drv_cc.core,
+-                                     offset + (i * 2));
++      for (i = 0; i < words; i++)
++              sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));
+ }
+ /**************************************************
+@@ -72,29 +124,29 @@ static inline u8 bcma_crc8(u8 crc, u8 da
+       return t[crc ^ data];
+ }
+-static u8 bcma_sprom_crc(const u16 *sprom)
++static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
+ {
+       int word;
+       u8 crc = 0xFF;
+-      for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
++      for (word = 0; word < words - 1; word++) {
+               crc = bcma_crc8(crc, sprom[word] & 0x00FF);
+               crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+       }
+-      crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
++      crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
+       crc ^= 0xFF;
+       return crc;
+ }
+-static int bcma_sprom_check_crc(const u16 *sprom)
++static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
+ {
+       u8 crc;
+       u8 expected_crc;
+       u16 tmp;
+-      crc = bcma_sprom_crc(sprom);
+-      tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
++      crc = bcma_sprom_crc(sprom, words);
++      tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
+       expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
+       if (crc != expected_crc)
+               return -EPROTO;
+@@ -102,21 +154,25 @@ static int bcma_sprom_check_crc(const u1
+       return 0;
+ }
+-static int bcma_sprom_valid(const u16 *sprom)
++static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom,
++                          size_t words)
+ {
+       u16 revision;
+       int err;
+-      err = bcma_sprom_check_crc(sprom);
++      err = bcma_sprom_check_crc(sprom, words);
+       if (err)
+               return err;
+-      revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
+-      if (revision != 8 && revision != 9) {
++      revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
++      if (revision != 8 && revision != 9 && revision != 10) {
+               pr_err("Unsupported SPROM revision: %d\n", revision);
+               return -ENOENT;
+       }
++      bus->sprom.revision = revision;
++      bcma_debug(bus, "Found SPROM revision %d\n", revision);
++
+       return 0;
+ }
+@@ -124,124 +180,439 @@ static int bcma_sprom_valid(const u16 *s
   * SPROM extraction.
   **************************************************/
  
 -      u16 v;
 +      u16 v, o;
        int i;
+-
+-      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
+-              SSB_SPROM_REVISION_REV;
 +      u16 pwr_info_offset[] = {
 +              SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
 +              SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
 +      BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
 +                      ARRAY_SIZE(bus->sprom.core_pwr_info));
  
-       bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
-               SSB_SPROM_REVISION_REV;
-@@ -137,102 +216,378 @@ static void bcma_sprom_extract_r8(struct
+       for (i = 0; i < 3; i++) {
+               v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
                *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
        }
  
 -      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
 +      SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
--      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
--           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
--      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
--           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
--      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
--           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
--      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
--           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
--
--      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
--           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
--      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
--           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
--      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
--           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
--      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
--           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
--
--      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
--           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
--      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
--           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
--      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
--           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
--      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
--           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
--
--      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
--           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
--      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
--           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
--      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
--           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
--      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
--           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
--
--      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
--      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
--      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
--      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
--
--      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
--
--      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
--              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
--      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
--              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
--      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
--              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
--      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
--              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
--      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
--              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
--
--      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
--              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
--      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
--              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
--      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
--              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
--      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
--              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
--      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
--              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++      SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
++
 +      SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
 +           SSB_SPROM4_TXPID2G0_SHIFT);
 +      SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
 +      case BCMA_CHIP_ID_BCM4331:
 +              present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
 +              break;
-+
+-      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
+-           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
+-      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
+-           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
+-      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
+-           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
+-      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
+-           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
+-
+-      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
+-           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
+-      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
+-           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
+-      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
+-           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
+-      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
+-           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
+-
+-      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
+-           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
+-      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
+-           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
+-      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
+-           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
+-      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
+-           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
+-
+-      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
+-           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
+-      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
+-           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
+-      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
+-           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
+-      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
+-           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
+-
+-      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
+-      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
+-      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
+-      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
+-
+-      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
+-
+-      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+-              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
+-      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+-              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
+-      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+-              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
+-      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+-              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
+-      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+-              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
+-
+-      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+-              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
+-      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+-              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
+-      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+-              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
+-      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+-              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
+-      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+-              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
 +      default:
 +              return true;
 +      }
 +      case BCMA_CHIP_ID_BCM4331:
 +              present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
 +              break;
-+
++      case BCMA_CHIP_ID_BCM43142:
 +      case BCMA_CHIP_ID_BCM43224:
 +      case BCMA_CHIP_ID_BCM43225:
 +              /* for these chips OTP is always available */
 +              present = true;
 +              break;
-+
++      case BCMA_CHIP_ID_BCM43227:
++      case BCMA_CHIP_ID_BCM43228:
++      case BCMA_CHIP_ID_BCM43428:
++              present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
++              break;
 +      default:
 +              present = false;
 +              break;
 -      u16 offset;
 +      u16 offset = BCMA_CC_SPROM;
        u16 *sprom;
-       int err = 0;
+-      int err = 0;
++      size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
++                               SSB_SPROMSIZE_WORDS_R10, };
++      int i, err = 0;
  
        if (!bus->drv_cc.core)
                return -EOPNOTSUPP;
 -              return -ENOENT;
 +      if (!bcma_sprom_ext_available(bus)) {
 +              bool sprom_onchip;
-+
+-      sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+-                      GFP_KERNEL);
+-      if (!sprom)
+-              return -ENOMEM;
 +              /*
 +               * External SPROM takes precedence so check
 +               * on-chip OTP only when no external SPROM
 +              }
 +      }
  
-       sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
-                       GFP_KERNEL);
-       if (!sprom)
-               return -ENOMEM;
 -      if (bus->chipinfo.id == 0x4331)
 +      if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
 +          bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
 -       * TODO: understand this condition and use it */
 -      offset = (bus->chipinfo.id == 0x4331) ? BCMA_CC_SPROM :
 -              BCMA_CC_SPROM_PCIE6;
+-      bcma_sprom_read(bus, offset, sprom);
 +      bcma_debug(bus, "SPROM offset 0x%x\n", offset);
-       bcma_sprom_read(bus, offset, sprom);
++      for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
++              size_t words = sprom_sizes[i];
++
++              sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
++              if (!sprom)
++                      return -ENOMEM;
++
++              bcma_sprom_read(bus, offset, sprom, words);
++              err = bcma_sprom_valid(bus, sprom, words);
++              if (!err)
++                      break;
  
 -      if (bus->chipinfo.id == 0x4331)
+-              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++              kfree(sprom);
++      }
+-      err = bcma_sprom_valid(sprom);
+-      if (err)
+-              goto out;
 +      if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
 +          bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
-               bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
+-      bcma_sprom_extract_r8(bus, sprom);
++      if (err) {
++              bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
++              err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
++      } else {
++              bcma_sprom_extract_r8(bus, sprom);
++              kfree(sprom);
++      }
  
-       err = bcma_sprom_valid(sprom);
+-out:
+-      kfree(sprom);
+       return err;
+ }
 --- a/include/linux/bcma/bcma.h
 +++ b/include/linux/bcma/bcma.h
-@@ -7,6 +7,7 @@
+@@ -7,9 +7,10 @@
  #include <linux/bcma/bcma_driver_chipcommon.h>
  #include <linux/bcma/bcma_driver_pci.h>
  #include <linux/bcma/bcma_driver_mips.h>
 +#include <linux/bcma/bcma_driver_gmac_cmn.h>
  #include <linux/ssb/ssb.h> /* SPROM sharing */
  
- #include "bcma_regs.h"
+-#include "bcma_regs.h"
++#include <linux/bcma/bcma_regs.h>
+ struct bcma_device;
+ struct bcma_bus;
 @@ -26,6 +27,11 @@ struct bcma_chipinfo {
        u8 pkg;
  };
  #define BCMA_CORE_INVALID             0x700
  #define BCMA_CORE_CHIPCOMMON          0x800
  #define BCMA_CORE_ILINE20             0x801
-@@ -125,6 +138,36 @@ struct bcma_host_ops {
+@@ -121,10 +134,104 @@ struct bcma_host_ops {
+ #define BCMA_CORE_I2S                 0x834
+ #define BCMA_CORE_SDR_DDR1_MEM_CTL    0x835   /* SDR/DDR1 memory controller core */
+ #define BCMA_CORE_SHIM                        0x837   /* SHIM component in ubus/6362 */
++#define BCMA_CORE_PHY_AC              0x83B
++#define BCMA_CORE_PCIE2                       0x83C   /* PCI Express Gen2 */
++#define BCMA_CORE_USB30_DEV           0x83D
++#define BCMA_CORE_ARM_CR4             0x83E
+ #define BCMA_CORE_DEFAULT             0xFFF
  
  #define BCMA_MAX_NR_CORES             16
  
 +/* Chip IDs of PCIe devices */
 +#define BCMA_CHIP_ID_BCM4313  0x4313
++#define BCMA_CHIP_ID_BCM43142 43142
 +#define BCMA_CHIP_ID_BCM43224 43224
 +#define  BCMA_PKG_ID_BCM43224_FAB_CSM 0x8
 +#define  BCMA_PKG_ID_BCM43224_FAB_SMIC        0xa
 +
 +/* Chip IDs of SoCs */
 +#define BCMA_CHIP_ID_BCM4706  0x5300
++#define  BCMA_PKG_ID_BCM4706L 1
 +#define BCMA_CHIP_ID_BCM4716  0x4716
 +#define  BCMA_PKG_ID_BCM4716  8
 +#define  BCMA_PKG_ID_BCM4717  9
 +#define BCMA_CHIP_ID_BCM4749  0x4749
 +#define BCMA_CHIP_ID_BCM5356  0x5356
 +#define BCMA_CHIP_ID_BCM5357  0x5357
++#define  BCMA_PKG_ID_BCM5358  9
++#define  BCMA_PKG_ID_BCM47186 10
++#define  BCMA_PKG_ID_BCM5357  11
 +#define BCMA_CHIP_ID_BCM53572 53572
++#define  BCMA_PKG_ID_BCM47188 9
++
++/* Board types (on PCI usually equals to the subsystem dev id) */
++/* BCM4313 */
++#define BCMA_BOARD_TYPE_BCM94313BU    0X050F
++#define BCMA_BOARD_TYPE_BCM94313HM    0X0510
++#define BCMA_BOARD_TYPE_BCM94313EPA   0X0511
++#define BCMA_BOARD_TYPE_BCM94313HMG   0X051C
++/* BCM4716 */
++#define BCMA_BOARD_TYPE_BCM94716NR2   0X04CD
++/* BCM43224 */
++#define BCMA_BOARD_TYPE_BCM943224X21  0X056E
++#define BCMA_BOARD_TYPE_BCM943224X21_FCC      0X00D1
++#define BCMA_BOARD_TYPE_BCM943224X21B 0X00E9
++#define BCMA_BOARD_TYPE_BCM943224M93  0X008B
++#define BCMA_BOARD_TYPE_BCM943224M93A 0X0090
++#define BCMA_BOARD_TYPE_BCM943224X16  0X0093
++#define BCMA_BOARD_TYPE_BCM94322X9    0X008D
++#define BCMA_BOARD_TYPE_BCM94322M35E  0X008E
++/* BCM43228 */
++#define BCMA_BOARD_TYPE_BCM943228BU8  0X0540
++#define BCMA_BOARD_TYPE_BCM943228BU9  0X0541
++#define BCMA_BOARD_TYPE_BCM943228BU   0X0542
++#define BCMA_BOARD_TYPE_BCM943227HM4L 0X0543
++#define BCMA_BOARD_TYPE_BCM943227HMB  0X0544
++#define BCMA_BOARD_TYPE_BCM943228HM4L 0X0545
++#define BCMA_BOARD_TYPE_BCM943228SD   0X0573
++/* BCM4331 */
++#define BCMA_BOARD_TYPE_BCM94331X19   0X00D6
++#define BCMA_BOARD_TYPE_BCM94331X28   0X00E4
++#define BCMA_BOARD_TYPE_BCM94331X28B  0X010E
++#define BCMA_BOARD_TYPE_BCM94331PCIEBT3AX     0X00E4
++#define BCMA_BOARD_TYPE_BCM94331X12_2G        0X00EC
++#define BCMA_BOARD_TYPE_BCM94331X12_5G        0X00ED
++#define BCMA_BOARD_TYPE_BCM94331X29B  0X00EF
++#define BCMA_BOARD_TYPE_BCM94331CSAX  0X00EF
++#define BCMA_BOARD_TYPE_BCM94331X19C  0X00F5
++#define BCMA_BOARD_TYPE_BCM94331X33   0X00F4
++#define BCMA_BOARD_TYPE_BCM94331BU    0X0523
++#define BCMA_BOARD_TYPE_BCM94331S9BU  0X0524
++#define BCMA_BOARD_TYPE_BCM94331MC    0X0525
++#define BCMA_BOARD_TYPE_BCM94331MCI   0X0526
++#define BCMA_BOARD_TYPE_BCM94331PCIEBT4       0X0527
++#define BCMA_BOARD_TYPE_BCM94331HM    0X0574
++#define BCMA_BOARD_TYPE_BCM94331PCIEDUAL      0X059B
++#define BCMA_BOARD_TYPE_BCM94331MCH5  0X05A9
++#define BCMA_BOARD_TYPE_BCM94331CS    0X05C6
++#define BCMA_BOARD_TYPE_BCM94331CD    0X05DA
++/* BCM53572 */
++#define BCMA_BOARD_TYPE_BCM953572BU   0X058D
++#define BCMA_BOARD_TYPE_BCM953572NR2  0X058E
++#define BCMA_BOARD_TYPE_BCM947188NR2  0X058F
++#define BCMA_BOARD_TYPE_BCM953572SDRNR2       0X0590
++/* BCM43142 */
++#define BCMA_BOARD_TYPE_BCM943142HM   0X05E0
 +
  struct bcma_device {
        struct bcma_bus *bus;
        struct bcma_device_id id;
-@@ -136,8 +179,10 @@ struct bcma_device {
+@@ -136,8 +243,10 @@ struct bcma_device {
        bool dev_registered;
  
        u8 core_index;
        u32 wrap;
  
        void __iomem *io_addr;
-@@ -175,6 +220,12 @@ int __bcma_driver_register(struct bcma_d
+@@ -175,6 +284,12 @@ int __bcma_driver_register(struct bcma_d
  
  extern void bcma_driver_unregister(struct bcma_driver *drv);
  
  struct bcma_bus {
        /* The MMIO area. */
        void __iomem *mmio;
-@@ -191,14 +242,18 @@ struct bcma_bus {
+@@ -191,14 +306,18 @@ struct bcma_bus {
  
        struct bcma_chipinfo chipinfo;
  
 +      u8 num;
  
        struct bcma_drv_cc drv_cc;
-       struct bcma_drv_pci drv_pci;
+-      struct bcma_drv_pci drv_pci;
++      struct bcma_drv_pci drv_pci[2];
        struct bcma_drv_mips drv_mips;
 +      struct bcma_drv_gmac_cmn drv_gmac_cmn;
  
        /* We decided to share SPROM struct with SSB as long as we do not need
         * any hacks for BCMA. This simplifies drivers code. */
-@@ -282,6 +337,7 @@ static inline void bcma_maskset16(struct
+@@ -282,6 +401,7 @@ static inline void bcma_maskset16(struct
        bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
  }
  
  extern bool bcma_core_is_enabled(struct bcma_device *core);
  extern void bcma_core_disable(struct bcma_device *core, u32 flags);
  extern int bcma_core_enable(struct bcma_device *core, u32 flags);
+@@ -289,6 +409,7 @@ extern void bcma_core_set_clockmode(stru
+                                   enum bcma_clkmode clkmode);
+ extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status,
+                             bool on);
++extern u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset);
+ #define BCMA_DMA_TRANSLATION_MASK     0xC0000000
+ #define  BCMA_DMA_TRANSLATION_NONE    0x00000000
+ #define  BCMA_DMA_TRANSLATION_DMA32_CMT       0x40000000 /* Client Mode Translation for 32-bit DMA */
 --- a/include/linux/bcma/bcma_driver_chipcommon.h
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -56,6 +56,9 @@
+@@ -1,6 +1,9 @@
+ #ifndef LINUX_BCMA_DRIVER_CC_H_
+ #define LINUX_BCMA_DRIVER_CC_H_
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++
+ /** ChipCommon core registers. **/
+ #define BCMA_CC_ID                    0x0000
+ #define  BCMA_CC_ID_ID                        0x0000FFFF
+@@ -24,7 +27,7 @@
+ #define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
+ #define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
+ #define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
+-#define   BCMA_CC_FLASHT_NFLASH               0x00000200
++#define   BCMA_CC_FLASHT_NAND         0x00000300      /* NAND flash */
+ #define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
+ #define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
+ #define   BCMA_PLLTYPE_NONE           0x00000000
+@@ -45,6 +48,7 @@
+ #define  BCMA_CC_CAP_PMU              0x10000000      /* PMU available (rev >= 20) */
+ #define  BCMA_CC_CAP_ECI              0x20000000      /* ECI available (rev >= 20) */
+ #define  BCMA_CC_CAP_SPROM            0x40000000      /* SPROM present */
++#define  BCMA_CC_CAP_NFLASH           0x80000000      /* NAND flash present (rev >= 35 or BCM4706?) */
+ #define BCMA_CC_CORECTL                       0x0008
+ #define  BCMA_CC_CORECTL_UARTCLK0     0x00000001      /* Drive UART with internal clock */
+ #define        BCMA_CC_CORECTL_SE             0x00000002      /* sync clk out enable (corerev >= 3) */
+@@ -56,6 +60,9 @@
  #define        BCMA_CC_OTPS_HW_PROTECT        0x00000001
  #define        BCMA_CC_OTPS_SW_PROTECT        0x00000002
  #define        BCMA_CC_OTPS_CID_PROTECT       0x00000004
  #define BCMA_CC_OTPC                  0x0014          /* OTP control */
  #define        BCMA_CC_OTPC_RECWAIT           0xFF000000
  #define        BCMA_CC_OTPC_PROGWAIT          0x00FFFF00
-@@ -72,6 +75,8 @@
+@@ -72,6 +79,8 @@
  #define        BCMA_CC_OTPP_READ              0x40000000
  #define        BCMA_CC_OTPP_START             0x80000000
  #define        BCMA_CC_OTPP_BUSY              0x80000000
  #define BCMA_CC_IRQSTAT                       0x0020
  #define BCMA_CC_IRQMASK                       0x0024
  #define        BCMA_CC_IRQ_GPIO               0x00000001      /* gpio intr */
-@@ -79,6 +84,15 @@
+@@ -79,6 +88,23 @@
  #define        BCMA_CC_IRQ_WDRESET            0x80000000      /* watchdog reset occurred */
  #define BCMA_CC_CHIPCTL                       0x0028          /* Rev >= 11 only */
  #define BCMA_CC_CHIPSTAT              0x002C          /* Rev >= 11 only */
 +#define  BCMA_CC_CHIPST_4313_OTP_PRESENT      2
 +#define  BCMA_CC_CHIPST_4331_SPROM_PRESENT    2
 +#define  BCMA_CC_CHIPST_4331_OTP_PRESENT      4
++#define  BCMA_CC_CHIPST_43228_ILP_DIV_EN      0x00000001
++#define  BCMA_CC_CHIPST_43228_OTP_PRESENT     0x00000002
++#define  BCMA_CC_CHIPST_43228_SERDES_REFCLK_PADSEL    0x00000004
++#define  BCMA_CC_CHIPST_43228_SDIO_MODE               0x00000008
++#define  BCMA_CC_CHIPST_43228_SDIO_OTP_PRESENT        0x00000010
++#define  BCMA_CC_CHIPST_43228_SDIO_RESET      0x00000020
 +#define  BCMA_CC_CHIPST_4706_PKG_OPTION               BIT(0) /* 0: full-featured package 1: low-cost package */
 +#define  BCMA_CC_CHIPST_4706_SFLASH_PRESENT   BIT(1) /* 0: parallel, 1: serial flash is present */
 +#define  BCMA_CC_CHIPST_4706_SFLASH_TYPE      BIT(2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */
 +#define  BCMA_CC_CHIPST_4706_MIPS_BENDIAN     BIT(3) /* 0: little, 1: big endian */
 +#define  BCMA_CC_CHIPST_4706_PCIE1_DISABLE    BIT(5) /* PCIE1 enable strap pin */
++#define  BCMA_CC_CHIPST_5357_NAND_BOOT                BIT(4) /* NAND boot, valid for CC rev 38 and/or BCM5357 */
++#define  BCMA_CC_CHIPST_4360_XTAL_40MZ                0x00000001
  #define BCMA_CC_JCMD                  0x0030          /* Rev >= 10 only */
  #define  BCMA_CC_JCMD_START           0x80000000
  #define  BCMA_CC_JCMD_BUSY            0x80000000
-@@ -181,6 +195,22 @@
+@@ -108,10 +134,58 @@
+ #define  BCMA_CC_JCTL_EXT_EN          2               /* Enable external targets */
+ #define  BCMA_CC_JCTL_EN              1               /* Enable Jtag master */
+ #define BCMA_CC_FLASHCTL              0x0040
++/* Start/busy bit in flashcontrol */
++#define  BCMA_CC_FLASHCTL_OPCODE      0x000000ff
++#define  BCMA_CC_FLASHCTL_ACTION      0x00000700
++#define  BCMA_CC_FLASHCTL_CS_ACTIVE   0x00001000      /* Chip Select Active, rev >= 20 */
+ #define  BCMA_CC_FLASHCTL_START               0x80000000
+ #define  BCMA_CC_FLASHCTL_BUSY                BCMA_CC_FLASHCTL_START
++/* Flashcontrol action + opcodes for ST flashes */
++#define  BCMA_CC_FLASHCTL_ST_WREN     0x0006          /* Write Enable */
++#define  BCMA_CC_FLASHCTL_ST_WRDIS    0x0004          /* Write Disable */
++#define  BCMA_CC_FLASHCTL_ST_RDSR     0x0105          /* Read Status Register */
++#define  BCMA_CC_FLASHCTL_ST_WRSR     0x0101          /* Write Status Register */
++#define  BCMA_CC_FLASHCTL_ST_READ     0x0303          /* Read Data Bytes */
++#define  BCMA_CC_FLASHCTL_ST_PP               0x0302          /* Page Program */
++#define  BCMA_CC_FLASHCTL_ST_SE               0x02d8          /* Sector Erase */
++#define  BCMA_CC_FLASHCTL_ST_BE               0x00c7          /* Bulk Erase */
++#define  BCMA_CC_FLASHCTL_ST_DP               0x00b9          /* Deep Power-down */
++#define  BCMA_CC_FLASHCTL_ST_RES      0x03ab          /* Read Electronic Signature */
++#define  BCMA_CC_FLASHCTL_ST_CSA      0x1000          /* Keep chip select asserted */
++#define  BCMA_CC_FLASHCTL_ST_SSE      0x0220          /* Sub-sector Erase */
++/* Flashcontrol action + opcodes for Atmel flashes */
++#define  BCMA_CC_FLASHCTL_AT_READ                     0x07e8
++#define  BCMA_CC_FLASHCTL_AT_PAGE_READ                        0x07d2
++#define  BCMA_CC_FLASHCTL_AT_STATUS                   0x01d7
++#define  BCMA_CC_FLASHCTL_AT_BUF1_WRITE                       0x0384
++#define  BCMA_CC_FLASHCTL_AT_BUF2_WRITE                       0x0387
++#define  BCMA_CC_FLASHCTL_AT_BUF1_ERASE_PROGRAM               0x0283
++#define  BCMA_CC_FLASHCTL_AT_BUF2_ERASE_PROGRAM               0x0286
++#define  BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM             0x0288
++#define  BCMA_CC_FLASHCTL_AT_BUF2_PROGRAM             0x0289
++#define  BCMA_CC_FLASHCTL_AT_PAGE_ERASE                       0x0281
++#define  BCMA_CC_FLASHCTL_AT_BLOCK_ERASE              0x0250
++#define  BCMA_CC_FLASHCTL_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
++#define  BCMA_CC_FLASHCTL_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
++#define  BCMA_CC_FLASHCTL_AT_BUF1_LOAD                        0x0253
++#define  BCMA_CC_FLASHCTL_AT_BUF2_LOAD                        0x0255
++#define  BCMA_CC_FLASHCTL_AT_BUF1_COMPARE             0x0260
++#define  BCMA_CC_FLASHCTL_AT_BUF2_COMPARE             0x0261
++#define  BCMA_CC_FLASHCTL_AT_BUF1_REPROGRAM           0x0258
++#define  BCMA_CC_FLASHCTL_AT_BUF2_REPROGRAM           0x0259
+ #define BCMA_CC_FLASHADDR             0x0044
+ #define BCMA_CC_FLASHDATA             0x0048
++/* Status register bits for ST flashes */
++#define  BCMA_CC_FLASHDATA_ST_WIP     0x01            /* Write In Progress */
++#define  BCMA_CC_FLASHDATA_ST_WEL     0x02            /* Write Enable Latch */
++#define  BCMA_CC_FLASHDATA_ST_BP_MASK 0x1c            /* Block Protect */
++#define  BCMA_CC_FLASHDATA_ST_BP_SHIFT        2
++#define  BCMA_CC_FLASHDATA_ST_SRWD    0x80            /* Status Register Write Disable */
++/* Status register bits for Atmel flashes */
++#define  BCMA_CC_FLASHDATA_AT_READY   0x80
++#define  BCMA_CC_FLASHDATA_AT_MISMATCH        0x40
++#define  BCMA_CC_FLASHDATA_AT_ID_MASK 0x38
++#define  BCMA_CC_FLASHDATA_AT_ID_SHIFT        3
+ #define BCMA_CC_BCAST_ADDR            0x0050
+ #define BCMA_CC_BCAST_DATA            0x0054
+ #define BCMA_CC_GPIOPULLUP            0x0058          /* Rev >= 20 only */
+@@ -181,6 +255,45 @@
  #define BCMA_CC_FLASH_CFG             0x0128
  #define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
  #define BCMA_CC_FLASH_WAITCNT         0x012C
 +#define  BCMA_CC_SROM_CONTROL_SIZE_16K        0x00000004
 +#define  BCMA_CC_SROM_CONTROL_SIZE_SHIFT      1
 +#define  BCMA_CC_SROM_CONTROL_PRESENT 0x00000001
++/* Block 0x140 - 0x190 registers are chipset specific */
++#define BCMA_CC_4706_FLASHSCFG                0x18C           /* Flash struct configuration */
++#define  BCMA_CC_4706_FLASHSCFG_MASK  0x000000ff
++#define  BCMA_CC_4706_FLASHSCFG_SF1   0x00000001      /* 2nd serial flash present */
++#define  BCMA_CC_4706_FLASHSCFG_PF1   0x00000002      /* 2nd parallel flash present */
++#define  BCMA_CC_4706_FLASHSCFG_SF1_TYPE      0x00000004      /* 2nd serial flash type : 0 : ST, 1 : Atmel */
++#define  BCMA_CC_4706_FLASHSCFG_NF1   0x00000008      /* 2nd NAND flash present */
++#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_MASK    0x000000f0
++#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_4MB     0x00000010      /* 4MB */
++#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_8MB     0x00000020      /* 8MB */
++#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_16MB    0x00000030      /* 16MB */
++#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_32MB    0x00000040      /* 32MB */
++#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_64MB    0x00000050      /* 64MB */
++#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_128MB   0x00000060      /* 128MB */
++#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_256MB   0x00000070      /* 256MB */
++/* NAND flash registers for BCM4706 (corerev = 31) */
++#define BCMA_CC_NFLASH_CTL            0x01A0
++#define  BCMA_CC_NFLASH_CTL_ERR               0x08000000
++#define BCMA_CC_NFLASH_CONF           0x01A4
++#define BCMA_CC_NFLASH_COL_ADDR               0x01A8
++#define BCMA_CC_NFLASH_ROW_ADDR               0x01AC
++#define BCMA_CC_NFLASH_DATA           0x01B0
++#define BCMA_CC_NFLASH_WAITCNT0               0x01B4
  /* 0x1E0 is defined as shared BCMA_CLKCTLST */
  #define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
  #define BCMA_CC_UART0_DATA            0x0300
-@@ -240,7 +270,6 @@
+@@ -203,6 +316,9 @@
+ #define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
+ #define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
+ #define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_RES          0x00006000 /* reset control mask */
++#define  BCMA_CC_PMU_CTL_RES_SHIFT    13
++#define  BCMA_CC_PMU_CTL_RES_RELOAD   0x2     /* reload POR values */
+ #define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
+ #define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
+ #define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
+@@ -214,6 +330,8 @@
+ #define BCMA_CC_PMU_CAP                       0x0604 /* PMU capabilities */
+ #define  BCMA_CC_PMU_CAP_REVISION     0x000000FF /* Revision mask */
+ #define BCMA_CC_PMU_STAT              0x0608 /* PMU status */
++#define  BCMA_CC_PMU_STAT_EXT_LPO_AVAIL       0x00000100
++#define  BCMA_CC_PMU_STAT_WDRESET     0x00000080
+ #define  BCMA_CC_PMU_STAT_INTPEND     0x00000040 /* Interrupt pending */
+ #define  BCMA_CC_PMU_STAT_SBCLKST     0x00000030 /* Backplane clock status? */
+ #define  BCMA_CC_PMU_STAT_HAVEALP     0x00000008 /* ALP available */
+@@ -239,8 +357,66 @@
+ #define BCMA_CC_REGCTL_DATA           0x065C
  #define BCMA_CC_PLLCTL_ADDR           0x0660
  #define BCMA_CC_PLLCTL_DATA           0x0664
++#define BCMA_CC_PMU_STRAPOPT          0x0668 /* (corerev >= 28) */
++#define BCMA_CC_PMU_XTAL_FREQ         0x066C /* (pmurev >= 10) */
++#define  BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK    0x00001FFF
++#define  BCMA_CC_PMU_XTAL_FREQ_MEASURE_MASK   0x80000000
++#define  BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT  31
  #define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
 -#define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
++/* NAND flash MLC controller registers (corerev >= 38) */
++#define BCMA_CC_NAND_REVISION         0x0C00
++#define BCMA_CC_NAND_CMD_START                0x0C04
++#define BCMA_CC_NAND_CMD_ADDR_X               0x0C08
++#define BCMA_CC_NAND_CMD_ADDR         0x0C0C
++#define BCMA_CC_NAND_CMD_END_ADDR     0x0C10
++#define BCMA_CC_NAND_CS_NAND_SELECT   0x0C14
++#define BCMA_CC_NAND_CS_NAND_XOR      0x0C18
++#define BCMA_CC_NAND_SPARE_RD0                0x0C20
++#define BCMA_CC_NAND_SPARE_RD4                0x0C24
++#define BCMA_CC_NAND_SPARE_RD8                0x0C28
++#define BCMA_CC_NAND_SPARE_RD12               0x0C2C
++#define BCMA_CC_NAND_SPARE_WR0                0x0C30
++#define BCMA_CC_NAND_SPARE_WR4                0x0C34
++#define BCMA_CC_NAND_SPARE_WR8                0x0C38
++#define BCMA_CC_NAND_SPARE_WR12               0x0C3C
++#define BCMA_CC_NAND_ACC_CONTROL      0x0C40
++#define BCMA_CC_NAND_CONFIG           0x0C48
++#define BCMA_CC_NAND_TIMING_1         0x0C50
++#define BCMA_CC_NAND_TIMING_2         0x0C54
++#define BCMA_CC_NAND_SEMAPHORE                0x0C58
++#define BCMA_CC_NAND_DEVID            0x0C60
++#define BCMA_CC_NAND_DEVID_X          0x0C64
++#define BCMA_CC_NAND_BLOCK_LOCK_STATUS        0x0C68
++#define BCMA_CC_NAND_INTFC_STATUS     0x0C6C
++#define BCMA_CC_NAND_ECC_CORR_ADDR_X  0x0C70
++#define BCMA_CC_NAND_ECC_CORR_ADDR    0x0C74
++#define BCMA_CC_NAND_ECC_UNC_ADDR_X   0x0C78
++#define BCMA_CC_NAND_ECC_UNC_ADDR     0x0C7C
++#define BCMA_CC_NAND_READ_ERROR_COUNT 0x0C80
++#define BCMA_CC_NAND_CORR_STAT_THRESHOLD      0x0C84
++#define BCMA_CC_NAND_READ_ADDR_X      0x0C90
++#define BCMA_CC_NAND_READ_ADDR                0x0C94
++#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR_X      0x0C98
++#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR        0x0C9C
++#define BCMA_CC_NAND_COPY_BACK_ADDR_X 0x0CA0
++#define BCMA_CC_NAND_COPY_BACK_ADDR   0x0CA4
++#define BCMA_CC_NAND_BLOCK_ERASE_ADDR_X       0x0CA8
++#define BCMA_CC_NAND_BLOCK_ERASE_ADDR 0x0CAC
++#define BCMA_CC_NAND_INV_READ_ADDR_X  0x0CB0
++#define BCMA_CC_NAND_INV_READ_ADDR    0x0CB4
++#define BCMA_CC_NAND_BLK_WR_PROTECT   0x0CC0
++#define BCMA_CC_NAND_ACC_CONTROL_CS1  0x0CD0
++#define BCMA_CC_NAND_CONFIG_CS1               0x0CD4
++#define BCMA_CC_NAND_TIMING_1_CS1     0x0CD8
++#define BCMA_CC_NAND_TIMING_2_CS1     0x0CDC
++#define BCMA_CC_NAND_SPARE_RD16               0x0D30
++#define BCMA_CC_NAND_SPARE_RD20               0x0D34
++#define BCMA_CC_NAND_SPARE_RD24               0x0D38
++#define BCMA_CC_NAND_SPARE_RD28               0x0D3C
++#define BCMA_CC_NAND_CACHE_ADDR               0x0D40
++#define BCMA_CC_NAND_CACHE_DATA               0x0D44
++#define BCMA_CC_NAND_CTRL_CONFIG      0x0D48
++#define BCMA_CC_NAND_CTRL_STATUS      0x0D4C
  
  /* Divider allocation in 4716/47162/5356 */
  #define BCMA_CC_PMU5_MAINPLL_CPU      1
-@@ -256,6 +285,15 @@
+@@ -256,6 +432,32 @@
  
  /* 4706 PMU */
  #define BCMA_CC_PMU4706_MAINPLL_PLL0  0
 +#define  BCMA_CC_PMU6_4706_PROC_NDIV_INT_SHIFT        3
 +#define  BCMA_CC_PMU6_4706_PROC_NDIV_MODE_MASK        0x00000007
 +#define  BCMA_CC_PMU6_4706_PROC_NDIV_MODE_SHIFT       0
++
++/* PMU rev 15 */
++#define BCMA_CC_PMU15_PLL_PLLCTL0     0
++#define  BCMA_CC_PMU15_PLL_PC0_CLKSEL_MASK    0x00000003
++#define  BCMA_CC_PMU15_PLL_PC0_CLKSEL_SHIFT   0
++#define  BCMA_CC_PMU15_PLL_PC0_FREQTGT_MASK   0x003FFFFC
++#define  BCMA_CC_PMU15_PLL_PC0_FREQTGT_SHIFT  2
++#define  BCMA_CC_PMU15_PLL_PC0_PRESCALE_MASK  0x00C00000
++#define  BCMA_CC_PMU15_PLL_PC0_PRESCALE_SHIFT 22
++#define  BCMA_CC_PMU15_PLL_PC0_KPCTRL_MASK    0x07000000
++#define  BCMA_CC_PMU15_PLL_PC0_KPCTRL_SHIFT   24
++#define  BCMA_CC_PMU15_PLL_PC0_FCNTCTRL_MASK  0x38000000
++#define  BCMA_CC_PMU15_PLL_PC0_FCNTCTRL_SHIFT 27
++#define  BCMA_CC_PMU15_PLL_PC0_FDCMODE_MASK   0x40000000
++#define  BCMA_CC_PMU15_PLL_PC0_FDCMODE_SHIFT  30
++#define  BCMA_CC_PMU15_PLL_PC0_CTRLBIAS_MASK  0x80000000
++#define  BCMA_CC_PMU15_PLL_PC0_CTRLBIAS_SHIFT 31
  
  /* ALP clock on pre-PMU chips */
  #define BCMA_CC_PMU_ALP_CLOCK         20000000
-@@ -284,6 +322,19 @@
+@@ -284,6 +486,19 @@
  #define BCMA_CC_PPL_PCHI_OFF          5
  #define BCMA_CC_PPL_PCHI_MASK         0x0000003f
  
  /* BCM4331 ChipControl numbers. */
  #define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
  #define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
-@@ -297,9 +348,18 @@
+@@ -297,9 +512,56 @@
  #define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
  #define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
  #define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
 +/* 4313 Chip specific ChipControl register bits */
 +#define BCMA_CCTRL_4313_12MA_LED_DRIVE                0x00000007      /* 12 mA drive strengh for later 4313 */
 +
++/* BCM5357 ChipControl register bits */
++#define BCMA_CHIPCTL_5357_EXTPA                       BIT(14)
++#define BCMA_CHIPCTL_5357_ANT_MUX_2O3         BIT(15)
++#define BCMA_CHIPCTL_5357_NFLASH              BIT(16)
++#define BCMA_CHIPCTL_5357_I2S_PINS_ENABLE     BIT(18)
++#define BCMA_CHIPCTL_5357_I2CSPI_PINS_ENABLE  BIT(19)
++
++#define BCMA_RES_4314_LPLDO_PU                        BIT(0)
++#define BCMA_RES_4314_PMU_SLEEP_DIS           BIT(1)
++#define BCMA_RES_4314_PMU_BG_PU                       BIT(2)
++#define BCMA_RES_4314_CBUCK_LPOM_PU           BIT(3)
++#define BCMA_RES_4314_CBUCK_PFM_PU            BIT(4)
++#define BCMA_RES_4314_CLDO_PU                 BIT(5)
++#define BCMA_RES_4314_LPLDO2_LVM              BIT(6)
++#define BCMA_RES_4314_WL_PMU_PU                       BIT(7)
++#define BCMA_RES_4314_LNLDO_PU                        BIT(8)
++#define BCMA_RES_4314_LDO3P3_PU                       BIT(9)
++#define BCMA_RES_4314_OTP_PU                  BIT(10)
++#define BCMA_RES_4314_XTAL_PU                 BIT(11)
++#define BCMA_RES_4314_WL_PWRSW_PU             BIT(12)
++#define BCMA_RES_4314_LQ_AVAIL                        BIT(13)
++#define BCMA_RES_4314_LOGIC_RET                       BIT(14)
++#define BCMA_RES_4314_MEM_SLEEP                       BIT(15)
++#define BCMA_RES_4314_MACPHY_RET              BIT(16)
++#define BCMA_RES_4314_WL_CORE_READY           BIT(17)
++#define BCMA_RES_4314_ILP_REQ                 BIT(18)
++#define BCMA_RES_4314_ALP_AVAIL                       BIT(19)
++#define BCMA_RES_4314_MISC_PWRSW_PU           BIT(20)
++#define BCMA_RES_4314_SYNTH_PWRSW_PU          BIT(21)
++#define BCMA_RES_4314_RX_PWRSW_PU             BIT(22)
++#define BCMA_RES_4314_RADIO_PU                        BIT(23)
++#define BCMA_RES_4314_VCO_LDO_PU              BIT(24)
++#define BCMA_RES_4314_AFE_LDO_PU              BIT(25)
++#define BCMA_RES_4314_RX_LDO_PU                       BIT(26)
++#define BCMA_RES_4314_TX_LDO_PU                       BIT(27)
++#define BCMA_RES_4314_HT_AVAIL                        BIT(28)
++#define BCMA_RES_4314_MACPHY_CLK_AVAIL                BIT(29)
++
  /* Data for the PMU, if available.
   * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
   */
-@@ -387,5 +447,6 @@ extern void bcma_chipco_chipctl_maskset(
+@@ -330,6 +592,7 @@ struct bcma_drv_cc {
+       u32 capabilities;
+       u32 capabilities_ext;
+       u8 setup_done:1;
++      u8 early_setup_done:1;
+       /* Fast Powerup Delay constant */
+       u16 fast_pwrup_delay;
+       struct bcma_chipcommon_pmu pmu;
+@@ -339,6 +602,14 @@ struct bcma_drv_cc {
+       int nr_serial_ports;
+       struct bcma_serial_port serial_ports[4];
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
++      u32 ticks_per_ms;
++      struct platform_device *watchdog;
++
++      /* Lock for GPIO register access. */
++      spinlock_t gpio_lock;
++#ifdef CONFIG_BCMA_DRIVER_GPIO
++      struct gpio_chip gpio;
++#endif
+ };
+ /* Register access */
+@@ -355,14 +626,16 @@ struct bcma_drv_cc {
+       bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
+ extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
++extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
+ extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
+ extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
+ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+-extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
+-                                        u32 ticks);
++extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
++
++extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
+ void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value);
+@@ -375,9 +648,12 @@ u32 bcma_chipco_gpio_outen(struct bcma_d
+ u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value);
+ u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value);
+ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value);
++u32 bcma_chipco_gpio_pullup(struct bcma_drv_cc *cc, u32 mask, u32 value);
++u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value);
+ /* PMU support */
+ extern void bcma_pmu_init(struct bcma_drv_cc *cc);
++extern void bcma_pmu_early_init(struct bcma_drv_cc *cc);
+ extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
+                                 u32 value);
+@@ -387,5 +663,8 @@ extern void bcma_chipco_chipctl_maskset(
                                        u32 offset, u32 mask, u32 set);
  extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
                                       u32 offset, u32 mask, u32 set);
 +extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
++
++extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc);
  
  #endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- /dev/null
 +#endif
 +
 +#endif /* LINUX_BCMA_DRIVER_GMAC_CMN_H_ */
+--- a/include/linux/bcma/bcma_driver_mips.h
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -28,6 +28,7 @@
+ #define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
+ #define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++#define BCMA_MIPS_OOBSELINA74         0x004
+ #define BCMA_MIPS_OOBSELOUTA30                0x100
+ struct bcma_device;
+@@ -35,17 +36,24 @@ struct bcma_device;
+ struct bcma_drv_mips {
+       struct bcma_device *core;
+       u8 setup_done:1;
+-      unsigned int assigned_irqs;
++      u8 early_setup_done:1;
+ };
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_irq(struct bcma_device *core);
+ #else
+ static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
++
++static inline unsigned int bcma_core_irq(struct bcma_device *core)
++{
++      return 0;
++}
+ #endif
+ extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
+-extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+-
+ #endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
 --- a/include/linux/bcma/bcma_driver_pci.h
 +++ b/include/linux/bcma/bcma_driver_pci.h
 @@ -53,11 +53,47 @@ struct pci_dev;
  
  /* SBtoPCIx */
  #define BCMA_CORE_PCI_SBTOPCI_MEM             0x00000000
-@@ -72,20 +108,118 @@ struct pci_dev;
+@@ -72,20 +108,120 @@ struct pci_dev;
  #define  BCMA_CORE_PCI_SBTOPCI_RC_READL               0x00000010 /* Memory read line */
  #define  BCMA_CORE_PCI_SBTOPCI_RC_READM               0x00000020 /* Memory read multiple */
  
 +#define BCMA_CORE_PCI_CFG_FUN_MASK            7       /* Function mask */
 +#define BCMA_CORE_PCI_CFG_OFF_MASK            0xfff   /* Register mask */
 +
++#define BCMA_CORE_PCI_CFG_DEVCTRL             0xd8
++
 +/* PCIE Root Capability Register bits (Host mode only) */
 +#define BCMA_CORE_PCI_RC_CRS_VISIBILITY               0x0001
 +
  #endif /* LINUX_BCMA_DRIVER_PCI_H_ */
 --- a/include/linux/bcma/bcma_regs.h
 +++ b/include/linux/bcma/bcma_regs.h
-@@ -56,4 +56,31 @@
+@@ -11,11 +11,13 @@
+ #define  BCMA_CLKCTLST_HAVEHTREQ      0x00000010 /* HT available request */
+ #define  BCMA_CLKCTLST_HWCROFF                0x00000020 /* Force HW clock request off */
+ #define  BCMA_CLKCTLST_EXTRESREQ      0x00000700 /* Mask of external resource requests */
++#define  BCMA_CLKCTLST_EXTRESREQ_SHIFT        8
+ #define  BCMA_CLKCTLST_HAVEALP                0x00010000 /* ALP available */
+ #define  BCMA_CLKCTLST_HAVEHT         0x00020000 /* HT available */
+ #define  BCMA_CLKCTLST_BP_ON_ALP      0x00040000 /* RO: running on ALP clock */
+ #define  BCMA_CLKCTLST_BP_ON_HT               0x00080000 /* RO: running on HT clock */
+ #define  BCMA_CLKCTLST_EXTRESST               0x07000000 /* Mask of external resource status */
++#define  BCMA_CLKCTLST_EXTRESST_SHIFT 24
+ /* Is there any BCM4328 on BCMA bus? */
+ #define  BCMA_CLKCTLST_4328A0_HAVEHT  0x00010000 /* 4328a0 has reversed bits */
+ #define  BCMA_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */
+@@ -35,6 +37,7 @@
+ #define  BCMA_IOST_BIST_DONE          0x8000
+ #define BCMA_RESET_CTL                        0x0800
+ #define  BCMA_RESET_CTL_RESET         0x0001
++#define BCMA_RESET_ST                 0x0804
+ /* BCMA PCI config space registers. */
+ #define BCMA_PCI_PMCSR                        0x44
+@@ -56,4 +59,31 @@
  #define  BCMA_PCI_GPIO_XTAL           0x40    /* PCI config space GPIO 14 for Xtal powerup */
  #define  BCMA_PCI_GPIO_PLL            0x80    /* PCI config space GPIO 15 for PLL powerdown */
  
 +                                                       */
 +
  #endif /* LINUX_BCMA_REGS_H_ */
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -4618,7 +4618,7 @@ static int b43_wireless_core_init(struct
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+-              bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci,
++              bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0],
+                                     dev->dev->bdev, true);
+               break;
+ #endif
+--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
+@@ -533,7 +533,7 @@ ai_buscore_setup(struct si_info *sii, st
+       /* fixup necessary chip/core configurations */
+       if (!sii->pch) {
+-              sii->pch = pcicore_init(&sii->pub, sii->icbus->drv_pci.core);
++              sii->pch = pcicore_init(&sii->pub, sii->icbus->drv_pci[0].core);
+               if (sii->pch == NULL)
+                       return false;
+       }
diff --git a/target/linux/generic/patches-3.3/026-bcma_pmu_regression.patch b/target/linux/generic/patches-3.3/026-bcma_pmu_regression.patch
deleted file mode 100644 (file)
index 35ca6b8..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
---- a/drivers/bcma/driver_chipcommon_pmu.c
-+++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -110,7 +110,7 @@ void bcma_pmu_workarounds(struct bcma_dr
-               /* enable 12 mA drive strenth for 4313 and set chipControl
-                  register bit 1 */
-               bcma_chipco_chipctl_maskset(cc, 0,
--                                          BCMA_CCTRL_4313_12MA_LED_DRIVE,
-+                                          ~BCMA_CCTRL_4313_12MA_LED_DRIVE,
-                                           BCMA_CCTRL_4313_12MA_LED_DRIVE);
-               break;
-       case BCMA_CHIP_ID_BCM4331:
-@@ -124,14 +124,14 @@ void bcma_pmu_workarounds(struct bcma_dr
-                  register bit 15 */
-               if (bus->chipinfo.rev == 0) {
-                       bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL,
--                                        BCMA_CCTRL_43224_GPIO_TOGGLE,
-+                                        ~BCMA_CCTRL_43224_GPIO_TOGGLE,
-                                         BCMA_CCTRL_43224_GPIO_TOGGLE);
-                       bcma_chipco_chipctl_maskset(cc, 0,
--                                                  BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
-+                                                  ~BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
-                                                   BCMA_CCTRL_43224A0_12MA_LED_DRIVE);
-               } else {
-                       bcma_chipco_chipctl_maskset(cc, 0,
--                                                  BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
-+                                                  ~BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
-                                                   BCMA_CCTRL_43224B0_12MA_LED_DRIVE);
-               }
-               break;
diff --git a/target/linux/generic/patches-3.3/027-bcma-add-missing-iounmap-on-error-path.patch b/target/linux/generic/patches-3.3/027-bcma-add-missing-iounmap-on-error-path.patch
deleted file mode 100644 (file)
index dc8367b..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
---- a/drivers/bcma/scan.c
-+++ b/drivers/bcma/scan.c
-@@ -462,8 +462,10 @@ int bcma_bus_scan(struct bcma_bus *bus)
-       while (eromptr < eromend) {
-               struct bcma_device *other_core;
-               struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
--              if (!core)
--                      return -ENOMEM;
-+              if (!core) {
-+                      err = -ENOMEM;
-+                      goto out;
-+              }
-               INIT_LIST_HEAD(&core->list);
-               core->bus = bus;
-@@ -478,7 +480,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
-                       } else if (err == -ESPIPE) {
-                               break;
-                       }
--                      return err;
-+                      goto out;
-               }
-               core->core_index = core_num++;
-@@ -494,10 +496,12 @@ int bcma_bus_scan(struct bcma_bus *bus)
-               list_add_tail(&core->list, &bus->cores);
-       }
-+      err = 0;
-+out:
-       if (bus->hosttype == BCMA_HOSTTYPE_SOC)
-               iounmap(eromptr);
--      return 0;
-+      return err;
- }
- int __init bcma_bus_scan_early(struct bcma_bus *bus,
-@@ -537,7 +541,7 @@ int __init bcma_bus_scan_early(struct bc
-               else if (err == -ESPIPE)
-                       break;
-               else if (err < 0)
--                      return err;
-+                      goto out;
-               core->core_index = core_num++;
-               bus->nr_cores++;
-@@ -551,6 +555,7 @@ int __init bcma_bus_scan_early(struct bc
-               break;
-       }
-+out:
-       if (bus->hosttype == BCMA_HOSTTYPE_SOC)
-               iounmap(eromptr);
diff --git a/target/linux/generic/patches-3.3/028-bcma-fix-regression-in-interrupt-assignment-on-mips.patch b/target/linux/generic/patches-3.3/028-bcma-fix-regression-in-interrupt-assignment-on-mips.patch
deleted file mode 100644 (file)
index 9386af2..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -131,7 +131,7 @@ static void bcma_core_mips_set_irq(struc
-                       /* backplane irq line is in use, find out who uses
-                        * it and set user to irq 0
-                        */
--                      list_for_each_entry_reverse(core, &bus->cores, list) {
-+                      list_for_each_entry(core, &bus->cores, list) {
-                               if ((1 << bcma_core_mips_irqflag(core)) ==
-                                   oldirqflag) {
-                                       bcma_core_mips_set_irq(core, 0);
-@@ -161,7 +161,7 @@ static void bcma_core_mips_dump_irq(stru
- {
-       struct bcma_device *core;
--      list_for_each_entry_reverse(core, &bus->cores, list) {
-+      list_for_each_entry(core, &bus->cores, list) {
-               bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
-       }
- }
-@@ -215,7 +215,7 @@ void bcma_core_mips_init(struct bcma_drv
-               mcore->assigned_irqs = 1;
-       /* Assign IRQs to all cores on the bus */
--      list_for_each_entry_reverse(core, &bus->cores, list) {
-+      list_for_each_entry(core, &bus->cores, list) {
-               int mips_irq;
-               if (core->irq)
-                       continue;