kernel: update bcma and ssb to version from wireless-testing/master tag master-2013...
authorhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 19 Jul 2013 12:02:34 +0000 (12:02 +0000)
committerhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 19 Jul 2013 12:02:34 +0000 (12:02 +0000)
This should fix some build problems in b43 with kernel 3.3.

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

23 files changed:
target/linux/brcm47xx/patches-3.10/241-bcma-broadcom-2011-sdk-updates.patch [deleted file]
target/linux/brcm47xx/patches-3.10/280-activate_ssb_support_in_usb.patch
target/linux/brcm47xx/patches-3.8/030-mtd-bcm47xxsflash-add-own-struct-for-abstrating-bus-.patch
target/linux/brcm47xx/patches-3.8/060-ssb-add-serial-flash-driver.patch
target/linux/brcm47xx/patches-3.8/070-bcma-add-functions-to-write-to-serial-flash.patch
target/linux/brcm47xx/patches-3.8/241-bcma-broadcom-2011-sdk-updates.patch [deleted file]
target/linux/brcm47xx/patches-3.8/280-activate_ssb_support_in_usb.patch
target/linux/brcm47xx/patches-3.9/060-ssb-add-serial-flash-driver.patch
target/linux/brcm47xx/patches-3.9/070-bcma-add-functions-to-write-to-serial-flash.patch
target/linux/brcm47xx/patches-3.9/241-bcma-broadcom-2011-sdk-updates.patch [deleted file]
target/linux/brcm47xx/patches-3.9/280-activate_ssb_support_in_usb.patch
target/linux/generic/patches-3.10/020-ssb_update.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/025-bcma_backport.patch [new file with mode: 0644]
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.6/020-ssb_update.patch
target/linux/generic/patches-3.6/025-bcma_backport.patch
target/linux/generic/patches-3.7/020-ssb_update.patch
target/linux/generic/patches-3.7/025-bcma_backport.patch
target/linux/generic/patches-3.8/020-ssb_update.patch
target/linux/generic/patches-3.8/025-bcma_backport.patch
target/linux/generic/patches-3.9/020-ssb_update.patch
target/linux/generic/patches-3.9/025-bcma_backport.patch

diff --git a/target/linux/brcm47xx/patches-3.10/241-bcma-broadcom-2011-sdk-updates.patch b/target/linux/brcm47xx/patches-3.10/241-bcma-broadcom-2011-sdk-updates.patch
deleted file mode 100644 (file)
index 72b0208..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
---- a/drivers/bcma/core.c
-+++ b/drivers/bcma/core.c
-@@ -43,6 +43,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));
index c4382ed..aabaf29 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
@@ -18,7 +18,7 @@ This prevents the options from being delete with make kernel_oldconfig.
 @@ -146,6 +146,7 @@ config SSB_SFLASH
  config SSB_EMBEDDED
        bool
-       depends on SSB_DRIVER_MIPS
+       depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
 +      select USB_HCD_SSB if USB_EHCI_HCD || USB_OHCI_HCD
        default y
  
index 2d2f11b..a1d9b37 100644 (file)
 +#endif /* BCM47XXSFLASH */
 --- a/include/linux/bcma/bcma_driver_chipcommon.h
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -544,6 +544,7 @@ struct bcma_nflash {
+@@ -599,6 +599,7 @@ struct bcma_nflash {
        bool boot;              /* This is the flash the SoC boots from */
  
        struct mtd_info *mtd;
index 1148a48..dcb70e8 100644 (file)
@@ -11,7 +11,7 @@
  # Assumption: We are on embedded, if we compile the MIPS core.
 --- a/drivers/ssb/driver_chipcommon_sflash.c
 +++ b/drivers/ssb/driver_chipcommon_sflash.c
-@@ -1,14 +1,35 @@
+@@ -1,14 +1,22 @@
  /*
   * Sonics Silicon Backplane
   * ChipCommon serial flash interface
  
 +#define NUM_RETRIES   3
 +
-+static struct resource ssb_sflash_resource = {
-+      .name   = "ssb_sflash",
-+      .start  = SSB_FLASH2,
-+      .end    = 0,
-+      .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
-+};
-+
-+struct platform_device ssb_sflash_dev = {
-+      .name           = "bcm47xx-sflash",
-+      .resource       = &ssb_sflash_resource,
-+      .num_resources  = 1,
-+};
-+
- struct ssb_sflash_tbl_e {
-       char *name;
-       u32 id;
-@@ -16,7 +37,7 @@ struct ssb_sflash_tbl_e {
-       u16 numblocks;
+ static struct resource ssb_sflash_resource = {
+       .name   = "ssb_sflash",
+       .start  = SSB_FLASH2,
+@@ -17,7 +25,7 @@ static struct resource ssb_sflash_resour
  };
  
--static struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
-+static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
-       { "M25P20", 0x11, 0x10000, 4, },
-       { "M25P40", 0x12, 0x10000, 8, },
-@@ -27,7 +48,7 @@ static struct ssb_sflash_tbl_e ssb_sflas
-       { 0 },
- };
--static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
-+static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
-       { "SST25WF512", 1, 0x1000, 16, },
-       { "SST25VF512", 0x48, 0x1000, 16, },
-       { "SST25WF010", 2, 0x1000, 32, },
-@@ -45,7 +66,7 @@ static struct ssb_sflash_tbl_e ssb_sflas
-       { 0 },
+ struct platform_device ssb_sflash_dev = {
+-      .name           = "ssb_sflash",
++      .name           = "bcm47xx-sflash",
+       .resource       = &ssb_sflash_resource,
+       .num_resources  = 1,
  };
--static struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
-+static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
-       { "AT45DB011", 0xc, 256, 512, },
-       { "AT45DB021", 0x14, 256, 1024, },
-       { "AT45DB041", 0x1c, 256, 2048, },
-@@ -70,10 +91,186 @@ static void ssb_sflash_cmd(struct ssb_ch
+@@ -83,10 +91,185 @@ static void ssb_sflash_cmd(struct ssb_ch
        pr_err("SFLASH control command failed (timeout)!\n");
  }
  
  /* Initialize serial flash access */
  int ssb_sflash_init(struct ssb_chipcommon *cc)
  {
--      struct ssb_sflash_tbl_e *e;
+-      struct ssb_sflash *sflash = &cc->dev->bus->mipscore.sflash;
 +      struct bcm47xxsflash *sflash = &cc->sflash;
-+      const struct ssb_sflash_tbl_e *e;
+       const struct ssb_sflash_tbl_e *e;
        u32 id, id2;
  
-       switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-@@ -131,10 +328,26 @@ int ssb_sflash_init(struct ssb_chipcommo
-               return -ENOTSUPP;
-       }
+@@ -150,17 +333,21 @@ int ssb_sflash_init(struct ssb_chipcommo
+       sflash->numblocks = e->numblocks;
+       sflash->size = sflash->blocksize * sflash->numblocks;
+       sflash->present = true;
+-
 -      pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
 -              e->name, e->blocksize, e->numblocks);
--
--      pr_err("Serial flash support is not implemented yet!\n");
-+      sflash->window = SSB_FLASH2;
-+      sflash->blocksize = e->blocksize;
-+      sflash->numblocks = e->numblocks;
-+      sflash->size = sflash->blocksize * sflash->numblocks;
-+      sflash->present = true;
 +      sflash->poll = ssb_sflash_poll;
 +      sflash->write = ssb_sflash_write;
 +      sflash->erase = ssb_sflash_erase;
 +      pr_info("Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
 +                e->name, sflash->size / 1024, sflash->blocksize,
 +                sflash->numblocks);
-+
-+      /* Prepare platform device, but don't register it yet. It's too early,
-+       * malloc (required by device_private_init) is not available yet. */
-+      ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
+       /* Prepare platform device, but don't register it yet. It's too early,
+        * malloc (required by device_private_init) is not available yet. */
+       ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
+-                                       sflash->size;
 +                                        sflash->size;
-+      ssb_sflash_dev.dev.platform_data = sflash;
+       ssb_sflash_dev.dev.platform_data = sflash;
  
+-      pr_err("Serial flash support is not implemented yet!\n");
+-
 -      return -ENOTSUPP;
 +      return 0;
  }
index bba2b69..fb0e046 100644 (file)
        .resource       = &bcma_sflash_resource,
        .num_resources  = 1,
  };
-@@ -30,7 +37,7 @@ struct bcma_sflash_tbl_e {
-       u16 numblocks;
- };
--static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
-+static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
-       { "M25P20", 0x11, 0x10000, 4, },
-       { "M25P40", 0x12, 0x10000, 8, },
-@@ -41,7 +48,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
-       { 0 },
- };
--static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
-+static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
-       { "SST25WF512", 1, 0x1000, 16, },
-       { "SST25VF512", 0x48, 0x1000, 16, },
-       { "SST25WF010", 2, 0x1000, 32, },
-@@ -59,7 +66,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
-       { 0 },
- };
--static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
-+static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
-       { "AT45DB011", 0xc, 256, 512, },
-       { "AT45DB021", 0x14, 256, 1024, },
-       { "AT45DB041", 0x1c, 256, 2048, },
-@@ -84,12 +91,186 @@ static void bcma_sflash_cmd(struct bcma_
+@@ -84,11 +91,185 @@ static void bcma_sflash_cmd(struct bcma_
        bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
  }
  
  {
        struct bcma_bus *bus = cc->core->bus;
 -      struct bcma_sflash *sflash = &cc->sflash;
--      struct bcma_sflash_tbl_e *e;
 +      struct bcm47xxsflash *sflash = &cc->sflash;
-+      const struct bcma_sflash_tbl_e *e;
+       const struct bcma_sflash_tbl_e *e;
        u32 id, id2;
  
-       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 @@ -150,6 +331,11 @@ int bcma_sflash_init(struct bcma_drv_cc
        sflash->numblocks = e->numblocks;
        sflash->size = sflash->blocksize * sflash->numblocks;
  
  /** ChipCommon core registers. **/
  #define BCMA_CC_ID                    0x0000
-@@ -523,19 +524,6 @@ struct bcma_pflash {
+@@ -578,19 +579,6 @@ struct bcma_pflash {
        u32 window_size;
  };
  
  #ifdef CONFIG_BCMA_NFLASH
  struct mtd_info;
  
-@@ -570,7 +558,7 @@ struct bcma_drv_cc {
+@@ -625,7 +613,7 @@ struct bcma_drv_cc {
  #ifdef CONFIG_BCMA_DRIVER_MIPS
        struct bcma_pflash pflash;
  #ifdef CONFIG_BCMA_SFLASH
diff --git a/target/linux/brcm47xx/patches-3.8/241-bcma-broadcom-2011-sdk-updates.patch b/target/linux/brcm47xx/patches-3.8/241-bcma-broadcom-2011-sdk-updates.patch
deleted file mode 100644 (file)
index 72b0208..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
---- a/drivers/bcma/core.c
-+++ b/drivers/bcma/core.c
-@@ -43,6 +43,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));
index c4382ed..aabaf29 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
@@ -18,7 +18,7 @@ This prevents the options from being delete with make kernel_oldconfig.
 @@ -146,6 +146,7 @@ config SSB_SFLASH
  config SSB_EMBEDDED
        bool
-       depends on SSB_DRIVER_MIPS
+       depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
 +      select USB_HCD_SSB if USB_EHCI_HCD || USB_OHCI_HCD
        default y
  
index 1148a48..dcb70e8 100644 (file)
@@ -11,7 +11,7 @@
  # Assumption: We are on embedded, if we compile the MIPS core.
 --- a/drivers/ssb/driver_chipcommon_sflash.c
 +++ b/drivers/ssb/driver_chipcommon_sflash.c
-@@ -1,14 +1,35 @@
+@@ -1,14 +1,22 @@
  /*
   * Sonics Silicon Backplane
   * ChipCommon serial flash interface
  
 +#define NUM_RETRIES   3
 +
-+static struct resource ssb_sflash_resource = {
-+      .name   = "ssb_sflash",
-+      .start  = SSB_FLASH2,
-+      .end    = 0,
-+      .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
-+};
-+
-+struct platform_device ssb_sflash_dev = {
-+      .name           = "bcm47xx-sflash",
-+      .resource       = &ssb_sflash_resource,
-+      .num_resources  = 1,
-+};
-+
- struct ssb_sflash_tbl_e {
-       char *name;
-       u32 id;
-@@ -16,7 +37,7 @@ struct ssb_sflash_tbl_e {
-       u16 numblocks;
+ static struct resource ssb_sflash_resource = {
+       .name   = "ssb_sflash",
+       .start  = SSB_FLASH2,
+@@ -17,7 +25,7 @@ static struct resource ssb_sflash_resour
  };
  
--static struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
-+static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
-       { "M25P20", 0x11, 0x10000, 4, },
-       { "M25P40", 0x12, 0x10000, 8, },
-@@ -27,7 +48,7 @@ static struct ssb_sflash_tbl_e ssb_sflas
-       { 0 },
- };
--static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
-+static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
-       { "SST25WF512", 1, 0x1000, 16, },
-       { "SST25VF512", 0x48, 0x1000, 16, },
-       { "SST25WF010", 2, 0x1000, 32, },
-@@ -45,7 +66,7 @@ static struct ssb_sflash_tbl_e ssb_sflas
-       { 0 },
+ struct platform_device ssb_sflash_dev = {
+-      .name           = "ssb_sflash",
++      .name           = "bcm47xx-sflash",
+       .resource       = &ssb_sflash_resource,
+       .num_resources  = 1,
  };
--static struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
-+static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
-       { "AT45DB011", 0xc, 256, 512, },
-       { "AT45DB021", 0x14, 256, 1024, },
-       { "AT45DB041", 0x1c, 256, 2048, },
-@@ -70,10 +91,186 @@ static void ssb_sflash_cmd(struct ssb_ch
+@@ -83,10 +91,185 @@ static void ssb_sflash_cmd(struct ssb_ch
        pr_err("SFLASH control command failed (timeout)!\n");
  }
  
  /* Initialize serial flash access */
  int ssb_sflash_init(struct ssb_chipcommon *cc)
  {
--      struct ssb_sflash_tbl_e *e;
+-      struct ssb_sflash *sflash = &cc->dev->bus->mipscore.sflash;
 +      struct bcm47xxsflash *sflash = &cc->sflash;
-+      const struct ssb_sflash_tbl_e *e;
+       const struct ssb_sflash_tbl_e *e;
        u32 id, id2;
  
-       switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-@@ -131,10 +328,26 @@ int ssb_sflash_init(struct ssb_chipcommo
-               return -ENOTSUPP;
-       }
+@@ -150,17 +333,21 @@ int ssb_sflash_init(struct ssb_chipcommo
+       sflash->numblocks = e->numblocks;
+       sflash->size = sflash->blocksize * sflash->numblocks;
+       sflash->present = true;
+-
 -      pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
 -              e->name, e->blocksize, e->numblocks);
--
--      pr_err("Serial flash support is not implemented yet!\n");
-+      sflash->window = SSB_FLASH2;
-+      sflash->blocksize = e->blocksize;
-+      sflash->numblocks = e->numblocks;
-+      sflash->size = sflash->blocksize * sflash->numblocks;
-+      sflash->present = true;
 +      sflash->poll = ssb_sflash_poll;
 +      sflash->write = ssb_sflash_write;
 +      sflash->erase = ssb_sflash_erase;
 +      pr_info("Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
 +                e->name, sflash->size / 1024, sflash->blocksize,
 +                sflash->numblocks);
-+
-+      /* Prepare platform device, but don't register it yet. It's too early,
-+       * malloc (required by device_private_init) is not available yet. */
-+      ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
+       /* Prepare platform device, but don't register it yet. It's too early,
+        * malloc (required by device_private_init) is not available yet. */
+       ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
+-                                       sflash->size;
 +                                        sflash->size;
-+      ssb_sflash_dev.dev.platform_data = sflash;
+       ssb_sflash_dev.dev.platform_data = sflash;
  
+-      pr_err("Serial flash support is not implemented yet!\n");
+-
 -      return -ENOTSUPP;
 +      return 0;
  }
index 3a06b52..9999848 100644 (file)
        .resource       = &bcma_sflash_resource,
        .num_resources  = 1,
  };
-@@ -30,7 +37,7 @@ struct bcma_sflash_tbl_e {
-       u16 numblocks;
- };
--static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
-+static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
-       { "M25P20", 0x11, 0x10000, 4, },
-       { "M25P40", 0x12, 0x10000, 8, },
-@@ -41,7 +48,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
-       { 0 },
- };
--static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
-+static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
-       { "SST25WF512", 1, 0x1000, 16, },
-       { "SST25VF512", 0x48, 0x1000, 16, },
-       { "SST25WF010", 2, 0x1000, 32, },
-@@ -59,7 +66,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
-       { 0 },
- };
--static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
-+static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
-       { "AT45DB011", 0xc, 256, 512, },
-       { "AT45DB021", 0x14, 256, 1024, },
-       { "AT45DB041", 0x1c, 256, 2048, },
-@@ -84,12 +91,186 @@ static void bcma_sflash_cmd(struct bcma_
+@@ -84,11 +91,185 @@ static void bcma_sflash_cmd(struct bcma_
        bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
  }
  
  {
        struct bcma_bus *bus = cc->core->bus;
 -      struct bcma_sflash *sflash = &cc->sflash;
--      struct bcma_sflash_tbl_e *e;
 +      struct bcm47xxsflash *sflash = &cc->sflash;
-+      const struct bcma_sflash_tbl_e *e;
+       const struct bcma_sflash_tbl_e *e;
        u32 id, id2;
  
-       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 @@ -150,6 +331,11 @@ int bcma_sflash_init(struct bcma_drv_cc
        sflash->numblocks = e->numblocks;
        sflash->size = sflash->blocksize * sflash->numblocks;
  
  /** ChipCommon core registers. **/
  #define BCMA_CC_ID                    0x0000
-@@ -523,19 +524,6 @@ struct bcma_pflash {
+@@ -578,19 +579,6 @@ struct bcma_pflash {
        u32 window_size;
  };
  
  #ifdef CONFIG_BCMA_NFLASH
  struct mtd_info;
  
-@@ -569,7 +557,7 @@ struct bcma_drv_cc {
+@@ -624,7 +612,7 @@ struct bcma_drv_cc {
  #ifdef CONFIG_BCMA_DRIVER_MIPS
        struct bcma_pflash pflash;
  #ifdef CONFIG_BCMA_SFLASH
diff --git a/target/linux/brcm47xx/patches-3.9/241-bcma-broadcom-2011-sdk-updates.patch b/target/linux/brcm47xx/patches-3.9/241-bcma-broadcom-2011-sdk-updates.patch
deleted file mode 100644 (file)
index 72b0208..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
---- a/drivers/bcma/core.c
-+++ b/drivers/bcma/core.c
-@@ -43,6 +43,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));
index c4382ed..aabaf29 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
@@ -18,7 +18,7 @@ This prevents the options from being delete with make kernel_oldconfig.
 @@ -146,6 +146,7 @@ config SSB_SFLASH
  config SSB_EMBEDDED
        bool
-       depends on SSB_DRIVER_MIPS
+       depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
 +      select USB_HCD_SSB if USB_EHCI_HCD || USB_OHCI_HCD
        default y
  
diff --git a/target/linux/generic/patches-3.10/020-ssb_update.patch b/target/linux/generic/patches-3.10/020-ssb_update.patch
new file mode 100644 (file)
index 0000000..0a75e5e
--- /dev/null
@@ -0,0 +1,201 @@
+diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
+index 5ff3a4f..36171fd 100644
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -144,7 +144,7 @@ config SSB_SFLASH
+ # Assumption: We are on embedded, if we compile the MIPS core.
+ config SSB_EMBEDDED
+       bool
+-      depends on SSB_DRIVER_MIPS
++      depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
+       default y
+ config SSB_DRIVER_EXTIF
+diff --git a/drivers/ssb/driver_chipcommon_sflash.c b/drivers/ssb/driver_chipcommon_sflash.c
+index 720665c..e84cf04 100644
+--- a/drivers/ssb/driver_chipcommon_sflash.c
++++ b/drivers/ssb/driver_chipcommon_sflash.c
+@@ -9,6 +9,19 @@
+ #include "ssb_private.h"
++static struct resource ssb_sflash_resource = {
++      .name   = "ssb_sflash",
++      .start  = SSB_FLASH2,
++      .end    = 0,
++      .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
++};
++
++struct platform_device ssb_sflash_dev = {
++      .name           = "ssb_sflash",
++      .resource       = &ssb_sflash_resource,
++      .num_resources  = 1,
++};
++
+ struct ssb_sflash_tbl_e {
+       char *name;
+       u32 id;
+@@ -16,7 +29,7 @@ struct ssb_sflash_tbl_e {
+       u16 numblocks;
+ };
+-static struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
++static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
+       { "M25P20", 0x11, 0x10000, 4, },
+       { "M25P40", 0x12, 0x10000, 8, },
+@@ -27,7 +40,7 @@ static struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
+       { 0 },
+ };
+-static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
++static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
+       { "SST25WF512", 1, 0x1000, 16, },
+       { "SST25VF512", 0x48, 0x1000, 16, },
+       { "SST25WF010", 2, 0x1000, 32, },
+@@ -45,7 +58,7 @@ static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
+       { 0 },
+ };
+-static struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
++static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
+       { "AT45DB011", 0xc, 256, 512, },
+       { "AT45DB021", 0x14, 256, 1024, },
+       { "AT45DB041", 0x1c, 256, 2048, },
+@@ -73,7 +86,8 @@ static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
+ /* Initialize serial flash access */
+ int ssb_sflash_init(struct ssb_chipcommon *cc)
+ {
+-      struct ssb_sflash_tbl_e *e;
++      struct ssb_sflash *sflash = &cc->dev->bus->mipscore.sflash;
++      const struct ssb_sflash_tbl_e *e;
+       u32 id, id2;
+       switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
+@@ -131,9 +145,21 @@ int ssb_sflash_init(struct ssb_chipcommon *cc)
+               return -ENOTSUPP;
+       }
++      sflash->window = SSB_FLASH2;
++      sflash->blocksize = e->blocksize;
++      sflash->numblocks = e->numblocks;
++      sflash->size = sflash->blocksize * sflash->numblocks;
++      sflash->present = true;
++
+       pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
+               e->name, e->blocksize, e->numblocks);
++      /* Prepare platform device, but don't register it yet. It's too early,
++       * malloc (required by device_private_init) is not available yet. */
++      ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
++                                       sflash->size;
++      ssb_sflash_dev.dev.platform_data = sflash;
++
+       pr_err("Serial flash support is not implemented yet!\n");
+       return -ENOTSUPP;
+diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
+index 812775a..e55ddf7 100644
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -553,6 +553,14 @@ static int ssb_devices_register(struct ssb_bus *bus)
+       }
+ #endif
++#ifdef CONFIG_SSB_SFLASH
++      if (bus->mipscore.sflash.present) {
++              err = platform_device_register(&ssb_sflash_dev);
++              if (err)
++                      pr_err("Error registering serial flash\n");
++      }
++#endif
++
+       return 0;
+ error:
+       /* Unwind the already registered devices. */
+diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
+index 32ed1fa..69161bb 100644
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -38,7 +38,7 @@ static int ssb_pcihost_resume(struct pci_dev *dev)
+       struct ssb_bus *ssb = pci_get_drvdata(dev);
+       int err;
+-      pci_set_power_state(dev, 0);
++      pci_set_power_state(dev, PCI_D0);
+       err = pci_enable_device(dev);
+       if (err)
+               return err;
+diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
+index a3b2364..e753fbe 100644
+--- a/drivers/ssb/sprom.c
++++ b/drivers/ssb/sprom.c
+@@ -54,7 +54,7 @@ static int hex2sprom(u16 *sprom, const char *dump, size_t len,
+       while (cnt < sprom_size_words) {
+               memcpy(tmp, dump, 4);
+               dump += 4;
+-              err = strict_strtoul(tmp, 16, &parsed);
++              err = kstrtoul(tmp, 16, &parsed);
+               if (err)
+                       return err;
+               sprom[cnt++] = swab16((u16)parsed);
+diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
+index 4671f17..eb507a5 100644
+--- a/drivers/ssb/ssb_private.h
++++ b/drivers/ssb/ssb_private.h
+@@ -243,6 +243,10 @@ static inline int ssb_sflash_init(struct ssb_chipcommon *cc)
+ extern struct platform_device ssb_pflash_dev;
+ #endif
++#ifdef CONFIG_SSB_SFLASH
++extern struct platform_device ssb_sflash_dev;
++#endif
++
+ #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);
+diff --git a/include/linux/ssb/ssb_driver_mips.h b/include/linux/ssb/ssb_driver_mips.h
+index afe79d4..6535e47 100644
+--- a/include/linux/ssb/ssb_driver_mips.h
++++ b/include/linux/ssb/ssb_driver_mips.h
+@@ -20,6 +20,18 @@ struct ssb_pflash {
+       u32 window_size;
+ };
++#ifdef CONFIG_SSB_SFLASH
++struct ssb_sflash {
++      bool present;
++      u32 window;
++      u32 blocksize;
++      u16 numblocks;
++      u32 size;
++
++      void *priv;
++};
++#endif
++
+ struct ssb_mipscore {
+       struct ssb_device *dev;
+@@ -27,6 +39,9 @@ struct ssb_mipscore {
+       struct ssb_serial_port serial_ports[4];
+       struct ssb_pflash pflash;
++#ifdef CONFIG_SSB_SFLASH
++      struct ssb_sflash sflash;
++#endif
+ };
+ extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
+diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
+index 3a72569..f9f931c 100644
+--- a/include/linux/ssb/ssb_regs.h
++++ b/include/linux/ssb/ssb_regs.h
+@@ -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
diff --git a/target/linux/generic/patches-3.10/025-bcma_backport.patch b/target/linux/generic/patches-3.10/025-bcma_backport.patch
new file mode 100644 (file)
index 0000000..a6e3b01
--- /dev/null
@@ -0,0 +1,601 @@
+diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
+index 8b4221c..380a200 100644
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -26,6 +26,7 @@ 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"
+diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
+index 79595a0..0215f9a 100644
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -22,6 +22,8 @@
+ struct bcma_bus;
+ /* main.c */
++bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
++                   int timeout);
+ int 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,
+diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c
+index 17b26ce..37a5ffe 100644
+--- a/drivers/bcma/core.c
++++ b/drivers/bcma/core.c
+@@ -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,13 +44,15 @@ void bcma_core_disable(struct bcma_device *core, u32 flags)
+       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);
+@@ -43,6 +64,7 @@ int bcma_core_enable(struct bcma_device *core, u32 flags)
+       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));
+diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
+index 036c674..b068f98 100644
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -140,8 +140,15 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
+       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)
+diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
+index edca73a..5081a8c 100644
+--- a/drivers/bcma/driver_chipcommon_pmu.c
++++ b/drivers/bcma/driver_chipcommon_pmu.c
+@@ -56,6 +56,109 @@ void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
++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 BCMA_CHIP_ID_BCM43142:
++              if (xtalfreq == 0)
++                      xtalfreq = 20000;
++              bcma_pmu2_pll_init0(cc, xtalfreq);
++              break;
++      }
++}
++
+ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
+ {
+       struct bcma_bus *bus = cc->core->bus;
+@@ -66,6 +169,25 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
+               min_msk = 0x200D;
+               max_msk = 0xFFFF;
+               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:
+               bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n",
+                          bus->chipinfo.id);
+@@ -165,6 +287,7 @@ void bcma_pmu_init(struct bcma_drv_cc *cc)
+               bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+                            BCMA_CC_PMU_CTL_NOILPONW);
++      bcma_pmu_pll_init(cc);
+       bcma_pmu_resources_init(cc);
+       bcma_pmu_workarounds(cc);
+ }
+diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c
+index e6ed4fe..4d07cce 100644
+--- a/drivers/bcma/driver_chipcommon_sflash.c
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -30,7 +30,7 @@ struct bcma_sflash_tbl_e {
+       u16 numblocks;
+ };
+-static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
+       { "M25P20", 0x11, 0x10000, 4, },
+       { "M25P40", 0x12, 0x10000, 8, },
+@@ -41,7 +41,7 @@ static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
+       { 0 },
+ };
+-static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
+       { "SST25WF512", 1, 0x1000, 16, },
+       { "SST25VF512", 0x48, 0x1000, 16, },
+       { "SST25WF010", 2, 0x1000, 32, },
+@@ -59,7 +59,7 @@ static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
+       { 0 },
+ };
+-static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
+       { "AT45DB011", 0xc, 256, 512, },
+       { "AT45DB021", 0x14, 256, 1024, },
+       { "AT45DB041", 0x1c, 256, 2048, },
+@@ -89,7 +89,7 @@ int bcma_sflash_init(struct bcma_drv_cc *cc)
+ {
+       struct bcma_bus *bus = cc->core->bus;
+       struct bcma_sflash *sflash = &cc->sflash;
+-      struct bcma_sflash_tbl_e *e;
++      const struct bcma_sflash_tbl_e *e;
+       u32 id, id2;
+       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
+diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
+index fbf2759..a355e63 100644
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -275,6 +275,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
+       { 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, },
+ };
+diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
+index f72f52b..0067422 100644
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -93,6 +93,25 @@ struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
+       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)
+ {
+       struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
+index 8934298..72bf454 100644
+--- a/drivers/bcma/sprom.c
++++ b/drivers/bcma/sprom.c
+@@ -72,12 +72,12 @@ fail:
+  * R/W ops.
+  **************************************************/
+-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));
+ }
+ /**************************************************
+@@ -124,29 +124,29 @@ static inline u8 bcma_crc8(u8 crc, u8 data)
+       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;
+@@ -154,21 +154,25 @@ static int bcma_sprom_check_crc(const u16 *sprom)
+       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;
+ }
+@@ -208,9 +212,6 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
+       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;
+-
+       for (i = 0; i < 3; i++) {
+               v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
+               *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
+@@ -502,7 +503,7 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
+       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 */
+@@ -550,7 +551,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ {
+       u16 offset = BCMA_CC_SPROM;
+       u16 *sprom;
+-      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;
+@@ -579,32 +582,37 @@ int bcma_sprom_get(struct bcma_bus *bus)
+               }
+       }
+-      sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+-                      GFP_KERNEL);
+-      if (!sprom)
+-              return -ENOMEM;
+-
+       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, false);
+       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;
++
++              kfree(sprom);
++      }
+       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);
+-      err = bcma_sprom_valid(sprom);
+       if (err) {
+-              bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
++              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);
+-              goto out;
++      } else {
++              bcma_sprom_extract_r8(bus, sprom);
++              kfree(sprom);
+       }
+-      bcma_sprom_extract_r8(bus, sprom);
+-
+-out:
+-      kfree(sprom);
+       return err;
+ }
+diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
+index 2e34db8..622fc50 100644
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -144,6 +144,7 @@ struct bcma_host_ops {
+ /* 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
+diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
+index b8b09ea..c49e1a1 100644
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -330,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 */
+@@ -355,6 +357,11 @@
+ #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 */
+ /* NAND flash MLC controller registers (corerev >= 38) */
+ #define BCMA_CC_NAND_REVISION         0x0C00
+@@ -435,6 +442,23 @@
+ #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
+ /* HT clock for systems with PMU-enabled chipcommon */
+@@ -507,6 +531,37 @@
+ #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)
+  */
index 4ca2614..51b23b0 100644 (file)
@@ -30,7 +30,7 @@
                                            ARRAY_SIZE(wgt634u_devices));
 --- a/drivers/ssb/Kconfig
 +++ b/drivers/ssb/Kconfig
-@@ -136,6 +136,11 @@ config SSB_DRIVER_MIPS
+@@ -136,10 +136,15 @@ config SSB_DRIVER_MIPS
  
          If unsure, say N
  
  # Assumption: We are on embedded, if we compile the MIPS core.
  config SSB_EMBEDDED
        bool
+-      depends on SSB_DRIVER_MIPS
++      depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
+       default y
+ config SSB_DRIVER_EXTIF
 @@ -160,4 +165,12 @@ config SSB_DRIVER_GIGE
  
          If unsure, say N
  
  #include "ssb_private.h"
  
-@@ -280,10 +282,76 @@ static void calc_fast_powerup_delay(stru
+@@ -280,13 +282,79 @@ static void calc_fast_powerup_delay(stru
        cc->fast_pwrup_delay = tmp;
  }
  
 +
        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_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);
        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:
-@@ -339,6 +346,8 @@ static void ssb_pmu_pll_init(struct ssb_
+@@ -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",
-@@ -427,6 +436,7 @@ static void ssb_pmu_resources_init(struc
+-              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:
                /* We keep the default settings:
                 * min_msk = 0xCBB
                 * max_msk = 0x7FFFF
-@@ -607,3 +617,90 @@ void ssb_pmu_set_ldo_paref(struct ssb_ch
+@@ -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);
 +      case 0x5354:
 +              ssb_pmu_get_alp_clock_clk0(cc);
 +      default:
-+              ssb_printk(KERN_ERR PFX
-+                         "ERROR: PMU alp clock unknown for device %04X\n",
-+                         bus->chip_id);
++              ssb_err("ERROR: PMU alp clock unknown for device %04X\n",
++                      bus->chip_id);
 +              return 0;
 +      }
 +}
 +              /* 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);
++              ssb_err("ERROR: PMU cpu clock unknown for device %04X\n",
++                      bus->chip_id);
 +              return 0;
 +      }
 +}
 +      case 0x5354:
 +              return 120000000;
 +      default:
-+              ssb_printk(KERN_ERR PFX
-+                         "ERROR: PMU controlclock unknown for device %04X\n",
-+                         bus->chip_id);
++              ssb_err("ERROR: PMU controlclock unknown for device %04X\n",
++                      bus->chip_id);
 +              return 0;
 +      }
 +}
 +              pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
 +              break;
 +      case 43222:
-+              /* TODO: BCM43222 requires updating PLLs too */
-+              return;
++              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",
 +EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate);
 --- /dev/null
 +++ b/drivers/ssb/driver_chipcommon_sflash.c
-@@ -0,0 +1,18 @@
+@@ -0,0 +1,166 @@
 +/*
 + * Sonics Silicon Backplane
 + * ChipCommon serial flash interface
 +
 +#include "ssb_private.h"
 +
++static struct resource ssb_sflash_resource = {
++      .name   = "ssb_sflash",
++      .start  = SSB_FLASH2,
++      .end    = 0,
++      .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
++};
++
++struct platform_device ssb_sflash_dev = {
++      .name           = "ssb_sflash",
++      .resource       = &ssb_sflash_resource,
++      .num_resources  = 1,
++};
++
++struct ssb_sflash_tbl_e {
++      char *name;
++      u32 id;
++      u32 blocksize;
++      u16 numblocks;
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
++      { "M25P20", 0x11, 0x10000, 4, },
++      { "M25P40", 0x12, 0x10000, 8, },
++
++      { "M25P16", 0x14, 0x10000, 32, },
++      { "M25P32", 0x15, 0x10000, 64, },
++      { "M25P64", 0x16, 0x10000, 128, },
++      { "M25FL128", 0x17, 0x10000, 256, },
++      { 0 },
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
++      { "SST25WF512", 1, 0x1000, 16, },
++      { "SST25VF512", 0x48, 0x1000, 16, },
++      { "SST25WF010", 2, 0x1000, 32, },
++      { "SST25VF010", 0x49, 0x1000, 32, },
++      { "SST25WF020", 3, 0x1000, 64, },
++      { "SST25VF020", 0x43, 0x1000, 64, },
++      { "SST25WF040", 4, 0x1000, 128, },
++      { "SST25VF040", 0x44, 0x1000, 128, },
++      { "SST25VF040B", 0x8d, 0x1000, 128, },
++      { "SST25WF080", 5, 0x1000, 256, },
++      { "SST25VF080B", 0x8e, 0x1000, 256, },
++      { "SST25VF016", 0x41, 0x1000, 512, },
++      { "SST25VF032", 0x4a, 0x1000, 1024, },
++      { "SST25VF064", 0x4b, 0x1000, 2048, },
++      { 0 },
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
++      { "AT45DB011", 0xc, 256, 512, },
++      { "AT45DB021", 0x14, 256, 1024, },
++      { "AT45DB041", 0x1c, 256, 2048, },
++      { "AT45DB081", 0x24, 256, 4096, },
++      { "AT45DB161", 0x2c, 512, 4096, },
++      { "AT45DB321", 0x34, 512, 8192, },
++      { "AT45DB642", 0x3c, 1024, 8192, },
++      { 0 },
++};
++
++static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
++{
++      int i;
++      chipco_write32(cc, SSB_CHIPCO_FLASHCTL,
++                     SSB_CHIPCO_FLASHCTL_START | opcode);
++      for (i = 0; i < 1000; i++) {
++              if (!(chipco_read32(cc, SSB_CHIPCO_FLASHCTL) &
++                    SSB_CHIPCO_FLASHCTL_BUSY))
++                      return;
++              cpu_relax();
++      }
++      pr_err("SFLASH control command failed (timeout)!\n");
++}
++
 +/* Initialize serial flash access */
 +int ssb_sflash_init(struct ssb_chipcommon *cc)
 +{
++      struct ssb_sflash *sflash = &cc->dev->bus->mipscore.sflash;
++      const struct ssb_sflash_tbl_e *e;
++      u32 id, id2;
++
++      switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++      case SSB_CHIPCO_FLASHT_STSER:
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_DP);
++
++              chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 0);
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
++              id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
++
++              chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 1);
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
++              id2 = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
++
++              switch (id) {
++              case 0xbf:
++                      for (e = ssb_sflash_sst_tbl; e->name; e++) {
++                              if (e->id == id2)
++                                      break;
++                      }
++                      break;
++              case 0x13:
++                      return -ENOTSUPP;
++              default:
++                      for (e = ssb_sflash_st_tbl; e->name; e++) {
++                              if (e->id == id)
++                                      break;
++                      }
++                      break;
++              }
++              if (!e->name) {
++                      pr_err("Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n",
++                             id, id2);
++                      return -ENOTSUPP;
++              }
++
++              break;
++      case SSB_CHIPCO_FLASHT_ATSER:
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
++              id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA) & 0x3c;
++
++              for (e = ssb_sflash_at_tbl; e->name; e++) {
++                      if (e->id == id)
++                              break;
++              }
++              if (!e->name) {
++                      pr_err("Unsupported Atmel serial flash (id: 0x%X)\n",
++                             id);
++                      return -ENOTSUPP;
++              }
++
++              break;
++      default:
++              pr_err("Unsupported flash type\n");
++              return -ENOTSUPP;
++      }
++
++      sflash->window = SSB_FLASH2;
++      sflash->blocksize = e->blocksize;
++      sflash->numblocks = e->numblocks;
++      sflash->size = sflash->blocksize * sflash->numblocks;
++      sflash->present = true;
++
++      pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
++              e->name, e->blocksize, e->numblocks);
++
++      /* Prepare platform device, but don't register it yet. It's too early,
++       * malloc (required by device_private_init) is not available yet. */
++      ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
++                                       sflash->size;
++      ssb_sflash_dev.dev.platform_data = sflash;
++
 +      pr_err("Serial flash support is not implemented yet!\n");
 +
 +      return -ENOTSUPP;
  }
 --- /dev/null
 +++ b/drivers/ssb/driver_gpio.c
-@@ -0,0 +1,176 @@
+@@ -0,0 +1,210 @@
 +/*
 + * Sonics Silicon Backplane
 + * GPIO driver
 +      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->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
 +      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->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
 +
 +      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
-@@ -178,9 +178,9 @@ static void ssb_mips_serial_init(struct
+@@ -10,6 +10,7 @@
+ #include <linux/ssb/ssb.h>
++#include <linux/mtd/physmap.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+@@ -17,6 +18,25 @@
+ #include "ssb_private.h"
++static const char * const part_probes[] = { "bcm47xxpart", NULL };
++
++static struct physmap_flash_data ssb_pflash_data = {
++      .part_probe_types       = part_probes,
++};
++
++static struct resource ssb_pflash_resource = {
++      .name   = "ssb_pflash",
++      .flags  = IORESOURCE_MEM,
++};
++
++struct platform_device ssb_pflash_dev = {
++      .name           = "physmap-flash",
++      .dev            = {
++              .platform_data  = &ssb_pflash_data,
++      },
++      .resource       = &ssb_pflash_resource,
++      .num_resources  = 1,
++};
+ static inline u32 mips_read32(struct ssb_mipscore *mcore,
+                             u16 offset)
+@@ -147,21 +167,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 +199,9 @@ static void ssb_mips_serial_init(struct
  {
        struct ssb_bus *bus = mcore->dev->bus;
  
                mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
        else
                mcore->nr_serial_ports = 0;
-@@ -190,16 +190,33 @@ static void ssb_mips_flash_detect(struct
+@@ -189,17 +210,42 @@ static void ssb_mips_serial_init(struct
+ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
  {
        struct ssb_bus *bus = mcore->dev->bus;
++      struct ssb_pflash *pflash = &mcore->pflash;
  
 -      mcore->flash_buswidth = 2;
 -      if (bus->chipco.dev) {
 -              mcore->flash_window_size = 0x02000000;
 +      /* When there is no chipcommon on the bus there is 4MB flash */
 +      if (!ssb_chipco_available(&bus->chipco)) {
-+              mcore->pflash.present = true;
-+              mcore->pflash.buswidth = 2;
-+              mcore->pflash.window = SSB_FLASH1;
-+              mcore->pflash.window_size = SSB_FLASH1_SZ;
-+              return;
++              pflash->present = true;
++              pflash->buswidth = 2;
++              pflash->window = SSB_FLASH1;
++              pflash->window_size = SSB_FLASH1_SZ;
++              goto ssb_pflash;
 +      }
 +
 +      /* There is ChipCommon, so use it to read info about flash */
 +              break;
 +      case SSB_CHIPCO_FLASHT_PARA:
 +              pr_debug("Found parallel flash\n");
-+              mcore->pflash.present = true;
-+              mcore->pflash.window = SSB_FLASH2;
-+              mcore->pflash.window_size = SSB_FLASH2_SZ;
++              pflash->present = true;
++              pflash->window = SSB_FLASH2;
++              pflash->window_size = SSB_FLASH2_SZ;
                if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
                               & SSB_CHIPCO_CFG_DS16) == 0)
 -                      mcore->flash_buswidth = 1;
 -      } else {
 -              mcore->flash_window = 0x1fc00000;
 -              mcore->flash_window_size = 0x00400000;
-+                      mcore->pflash.buswidth = 1;
++                      pflash->buswidth = 1;
 +              else
-+                      mcore->pflash.buswidth = 2;
++                      pflash->buswidth = 2;
 +              break;
++      }
++
++ssb_pflash:
++      if (pflash->present) {
++              ssb_pflash_data.width = pflash->buswidth;
++              ssb_pflash_resource.start = pflash->window;
++              ssb_pflash_resource.end = pflash->window + pflash->window_size;
        }
  }
  
-@@ -208,9 +225,12 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
+@@ -208,9 +254,12 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
        struct ssb_bus *bus = mcore->dev->bus;
        u32 pll_type, n, m, rate = 0;
  
                ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
        } else
                return 0;
-@@ -246,9 +266,9 @@ void ssb_mipscore_init(struct ssb_mipsco
+@@ -238,7 +287,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 +295,9 @@ void ssb_mipscore_init(struct ssb_mipsco
                hz = 100000000;
        ns = 1000000000 / hz;
  
                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 +335,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 @@
  #include <linux/ssb/ssb.h>
  #include <linux/ssb/ssb_embedded.h>
  #include <linux/ssb/ssb_driver_pci.h>
-@@ -32,6 +34,39 @@ int ssb_watchdog_timer_set(struct ssb_bu
+@@ -32,6 +34,38 @@ int ssb_watchdog_timer_set(struct ssb_bu
  }
  EXPORT_SYMBOL(ssb_watchdog_timer_set);
  
 +                                           bus->busnumber, &wdt,
 +                                           sizeof(wdt));
 +      if (IS_ERR(pdev)) {
-+              ssb_dprintk(KERN_INFO PFX
-+                          "can not register watchdog device, err: %li\n",
-+                          PTR_ERR(pdev));
++              ssb_dbg("can not register watchdog device, err: %li\n",
++                      PTR_ERR(pdev));
 +              return PTR_ERR(pdev);
 +      }
 +
  #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 inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv)
--{
--      if (drv)
--              get_driver(&drv->drv);
--      return drv;
--}
--
--static inline void ssb_driver_put(struct ssb_driver *drv)
--{
--      if (drv)
--              put_driver(&drv->drv);
--}
--
- static int ssb_device_resume(struct device *dev)
- {
-       struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
-@@ -250,11 +238,9 @@ int ssb_devices_freeze(struct ssb_bus *b
-                       ssb_device_put(sdev);
-                       continue;
-               }
--              sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
--              if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
--                      ssb_device_put(sdev);
-+              sdrv = drv_to_ssb_drv(sdev->dev->driver);
-+              if (SSB_WARN_ON(!sdrv->remove))
-                       continue;
--              }
-               sdrv->remove(sdev);
-               ctx->device_frozen[i] = 1;
-       }
-@@ -293,7 +279,6 @@ int ssb_devices_thaw(struct ssb_freeze_c
-                                  dev_name(sdev->dev));
+@@ -289,8 +290,8 @@ 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);
-       }
-@@ -449,6 +434,11 @@ static void ssb_devices_unregister(struc
+               ssb_driver_put(sdrv);
+@@ -449,10 +450,23 @@ static void ssb_devices_unregister(struc
                if (sdev->dev)
                        device_unregister(sdev->dev);
        }
  }
  
  void ssb_bus_unregister(struct ssb_bus *bus)
-@@ -577,6 +567,8 @@ static int __devinit ssb_attach_queued_b
+ {
++      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 +512,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 +551,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;
+@@ -550,6 +561,22 @@ static int ssb_devices_register(struct s
+               dev_idx++;
+       }
++#ifdef CONFIG_SSB_DRIVER_MIPS
++      if (bus->mipscore.pflash.present) {
++              err = platform_device_register(&ssb_pflash_dev);
++              if (err)
++                      pr_err("Error registering parallel flash\n");
++      }
++#endif
++
++#ifdef CONFIG_SSB_SFLASH
++      if (bus->mipscore.sflash.present) {
++              err = platform_device_register(&ssb_sflash_dev);
++              if (err)
++                      pr_err("Error registering serial flash\n");
++      }
++#endif
++
+       return 0;
+ error:
+       /* Unwind the already registered devices. */
+@@ -577,6 +604,8 @@ static int __devinit ssb_attach_queued_b
                if (err)
                        goto error;
                ssb_pcicore_init(&bus->pcicore);
                ssb_bus_may_powerdown(bus);
  
                err = ssb_devices_register(bus);
-@@ -812,7 +804,14 @@ static int __devinit ssb_bus_register(st
+@@ -812,7 +841,13 @@ static int __devinit ssb_bus_register(st
        if (err)
                goto err_pcmcia_exit;
        ssb_chipcommon_init(&bus->chipco);
        ssb_mipscore_init(&bus->mipscore);
 +      err = ssb_gpio_init(bus);
 +      if (err == -ENOTSUPP)
-+              ssb_dprintk(KERN_DEBUG PFX "GPIO driver not activated\n");
++              ssb_dbg("GPIO driver not activated\n");
 +      else if (err)
-+              ssb_dprintk(KERN_ERR PFX
-+                         "Error registering GPIO driver: %i\n", err);
++              ssb_dbg("Error registering GPIO driver: %i\n", err);
        err = ssb_fetch_invariants(bus, get_invariants);
        if (err) {
                ssb_bus_may_powerdown(bus);
-@@ -1094,6 +1093,9 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
+@@ -863,11 +898,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 +923,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 +946,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 +966,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 +1129,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 +1133,7 @@ static u32 ssb_tmslow_reject_bitmask(str
+@@ -1131,8 +1169,7 @@ static u32 ssb_tmslow_reject_bitmask(str
        case SSB_IDLOW_SSBREV_27:     /* same here */
                return SSB_TMSLOW_REJECT;       /* this is a guess */
        default:
        }
        return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
  }
+@@ -1324,7 +1361,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 +1384,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 +1492,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)
  {
-@@ -327,11 +339,25 @@ static s8 r123_extract_antgain(u8 sprom_
+@@ -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 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_r123(struct ssb_sprom *out, const u16 *in)
  {
-       int i;
-       u16 v;
+-      int i;
+-      u16 v;
 -      s8 gain;
        u16 loc[3];
  
        if (out->revision == 3)                 /* rev 3 moved MAC */
-@@ -361,8 +387,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,
-@@ -386,24 +413,19 @@ 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);
  }
  
  /* Revs 4 5 and 8 have partially shared layout */
-@@ -464,14 +486,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 +529,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 +546,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 +627,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 +691,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 +877,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/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -38,7 +38,7 @@ static int ssb_pcihost_resume(struct pci
+       struct ssb_bus *ssb = pci_get_drvdata(dev);
+       int err;
+-      pci_set_power_state(dev, 0);
++      pci_set_power_state(dev, PCI_D0);
+       err = pci_enable_device(dev);
+       if (err)
+               return err;
 --- 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
+@@ -54,7 +54,7 @@ static int hex2sprom(u16 *sprom, const c
+       while (cnt < sprom_size_words) {
+               memcpy(tmp, dump, 4);
+               dump += 4;
+-              err = strict_strtoul(tmp, 16, &parsed);
++              err = kstrtoul(tmp, 16, &parsed);
+               if (err)
+                       return err;
+               sprom[cnt++] = swab16((u16)parsed);
+@@ -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
-@@ -3,6 +3,7 @@
+@@ -3,21 +3,33 @@
  
  #include <linux/ssb/ssb.h>
  #include <linux/types.h>
  
  
  #define PFX   "ssb: "
-@@ -207,4 +208,66 @@ static inline void b43_pci_ssb_bridge_ex
+ #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,79 @@ static inline void b43_pci_ssb_bridge_ex
  }
  #endif /* CONFIG_SSB_B43_PCI_BRIDGE */
  
 +}
 +#endif /* CONFIG_SSB_SFLASH */
 +
++#ifdef CONFIG_SSB_DRIVER_MIPS
++extern struct platform_device ssb_pflash_dev;
++#endif
++
++#ifdef CONFIG_SSB_SFLASH
++extern struct platform_device ssb_sflash_dev;
++#endif
++
 +#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);
 +
 +#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_ */
  
  #include <linux/ssb/ssb_regs.h>
  
-@@ -16,6 +18,12 @@ struct pcmcia_device;
+@@ -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 +34,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. */
  
  /* Vendor-ID values */
  #define SSB_VENDOR_BROADCOM   0x4243
-@@ -354,7 +434,11 @@ struct ssb_bus {
+@@ -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;
  #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
-@@ -13,6 +13,12 @@ struct ssb_serial_port {
+@@ -13,6 +13,24 @@ struct ssb_serial_port {
        unsigned int reg_shift;
  };
  
 +      u32 window;
 +      u32 window_size;
 +};
++
++#ifdef CONFIG_SSB_SFLASH
++struct ssb_sflash {
++      bool present;
++      u32 window;
++      u32 blocksize;
++      u16 numblocks;
++      u32 size;
++
++      void *priv;
++};
++#endif
  
  struct ssb_mipscore {
        struct ssb_device *dev;
-@@ -20,9 +26,7 @@ struct ssb_mipscore {
+@@ -20,9 +38,10 @@ struct ssb_mipscore {
        int nr_serial_ports;
        struct ssb_serial_port serial_ports[4];
  
 -      u32 flash_window;
 -      u32 flash_window_size;
 +      struct ssb_pflash pflash;
++#ifdef CONFIG_SSB_SFLASH
++      struct ssb_sflash sflash;
++#endif
  };
  
  extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
+@@ -41,6 +60,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) */
-@@ -287,11 +289,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_AGAIN01            0x005E  /* Antenna Gain (in dBm Q5.2) */
  #define  SSB_SPROM4_AGAIN0            0x00FF  /* Antenna 0 */
  #define  SSB_SPROM4_AGAIN0_SHIFT      0
-@@ -389,6 +391,11 @@
+@@ -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_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
index d3f9fb0..05d461d 100644 (file)
@@ -1,6 +1,21 @@
+--- 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/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 +24,7 @@
        help
          PCI core hostmode operation (external PCI bus).
  
-@@ -46,6 +46,33 @@ config BCMA_DRIVER_MIPS
+@@ -46,6 +47,33 @@ config BCMA_DRIVER_MIPS
  
          If unsure, say N
  
@@ -60,7 +75,7 @@
  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,
-@@ -22,6 +31,8 @@ int __init bcma_bus_early_register(struc
+@@ -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
  
  /* scan.c */
  int bcma_bus_scan(struct bcma_bus *bus);
-@@ -39,8 +50,32 @@ void bcma_chipco_serial_init(struct bcma
+@@ -36,11 +49,36 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ /* driver_chipcommon.c */
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++extern struct platform_device bcma_pflash_dev;
  #endif /* CONFIG_BCMA_DRIVER_MIPS */
  
  /* driver_chipcommon_pmu.c */
  
  #ifdef CONFIG_BCMA_HOST_PCI
  /* host_pci.c */
-@@ -48,8 +83,24 @@ extern int __init bcma_host_pci_init(voi
+@@ -48,8 +86,29 @@ extern int __init bcma_host_pci_init(voi
  extern void __exit bcma_host_pci_exit(void);
  #endif /* CONFIG_BCMA_HOST_PCI */
  
 +#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);
-@@ -64,7 +65,7 @@ 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);
                for (i = 0; i < 1500; i++) {
                        if (bcma_read32(core, BCMA_CLKCTLST) &
                            BCMA_CLKCTLST_HAVEHT) {
-@@ -74,10 +75,10 @@ void bcma_core_set_clockmode(struct bcma
+@@ -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:
  #include <linux/bcma/bcma.h>
  
  static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
-@@ -22,20 +25,120 @@ static inline u32 bcma_cc_write32_masked
+@@ -22,29 +25,136 @@ static inline u32 bcma_cc_write32_masked
        return value;
  }
  
 +      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);
-@@ -44,7 +147,7 @@ void bcma_core_chipcommon_init(struct bc
+-              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 &&
-@@ -56,15 +159,33 @@ void bcma_core_chipcommon_init(struct bc
+@@ -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)));
        }
  }
  
  void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
-@@ -84,28 +205,99 @@ u32 bcma_chipco_gpio_in(struct bcma_drv_
+@@ -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)
  {
  }
  
  #ifdef CONFIG_BCMA_DRIVER_MIPS
-@@ -118,8 +310,7 @@ void bcma_chipco_serial_init(struct bcma
+@@ -118,8 +317,7 @@ void bcma_chipco_serial_init(struct bcma
        struct bcma_serial_port *ports = cc->serial_ports;
  
        if (ccrev >= 11 && ccrev != 15) {
                if (ccrev >= 21) {
                        /* Turn off UART clock before switching clocksource. */
                        bcma_cc_write32(cc, BCMA_CC_CORECTL,
-@@ -137,8 +328,7 @@ void bcma_chipco_serial_init(struct bcma
+@@ -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);
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon_nflash.c
 @@ -0,0 +1,44 @@
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +
++#include "bcma_private.h"
++
 +#include <linux/platform_device.h>
 +#include <linux/bcma/bcma.h>
 +
-+#include "bcma_private.h"
-+
 +struct platform_device bcma_nflash_dev = {
 +      .name           = "bcma_nflash",
 +      .num_resources  = 0,
 +      struct bcma_bus *bus = cc->core->bus;
 +
 +      if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
-+          cc->core->id.rev != 0x38) {
++          cc->core->id.rev != 38) {
 +              bcma_err(bus, "NAND flash on unsupported board!\n");
 +              return -ENOTSUPP;
 +      }
  
  void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
  {
-@@ -54,38 +56,19 @@ void bcma_chipco_regctl_maskset(struct b
+@@ -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 +76,12 @@ 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:
  }
  
  /* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
-@@ -122,51 +95,69 @@ 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;
        if (cc->pmu.rev == 1)
                bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
                              ~BCMA_CC_PMU_CTL_NOILPONW);
-@@ -174,37 +165,47 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+@@ -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);
        }
        return BCMA_CC_PMU_ALP_CLOCK;
  }
-@@ -212,7 +213,7 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
+@@ -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.
   */
  {
        u32 tmp, div, ndiv, p1, p2, fc;
        struct bcma_bus *bus = cc->core->bus;
-@@ -221,7 +222,8 @@ static u32 bcma_pmu_clock(struct bcma_dr
+@@ -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)
-@@ -240,60 +242,95 @@ 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 */
 +
  /* query bus clock frequency for PMU-enabled chipcommon */
 -u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
-+static u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
++u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
  {
        struct bcma_bus *bus = cc->core->bus;
  
        }
        return BCMA_CC_PMU_HT_CLOCK;
  }
++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)
                        pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
                        break;
                default:
-@@ -301,10 +338,189 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
+@@ -301,10 +462,189 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
                        break;
                }
  
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +
++#include "bcma_private.h"
++
 +#include <linux/platform_device.h>
 +#include <linux/bcma/bcma.h>
 +
-+#include "bcma_private.h"
-+
 +static struct resource bcma_sflash_resource = {
 +      .name   = "bcma_sflash",
 +      .start  = BCMA_SOC_FLASH2,
 +      u16 numblocks;
 +};
 +
-+static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
 +      { "M25P20", 0x11, 0x10000, 4, },
 +      { "M25P40", 0x12, 0x10000, 8, },
 +
 +      { 0 },
 +};
 +
-+static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
 +      { "SST25WF512", 1, 0x1000, 16, },
 +      { "SST25VF512", 0x48, 0x1000, 16, },
 +      { "SST25WF010", 2, 0x1000, 32, },
 +      { 0 },
 +};
 +
-+static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
 +      { "AT45DB011", 0xc, 256, 512, },
 +      { "AT45DB021", 0x14, 256, 1024, },
 +      { "AT45DB041", 0x1c, 256, 2048, },
 +{
 +      struct bcma_bus *bus = cc->core->bus;
 +      struct bcma_sflash *sflash = &cc->sflash;
-+      struct bcma_sflash_tbl_e *e;
++      const struct bcma_sflash_tbl_e *e;
 +      u32 id, id2;
 +
 +      switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 +}
 --- /dev/null
 +++ b/drivers/bcma/driver_gpio.c
-@@ -0,0 +1,98 @@
+@@ -0,0 +1,114 @@
 +/*
 + * Broadcom specific AMBA
 + * GPIO driver
 +      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->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
 +
 +      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 @@
+@@ -14,23 +14,45 @@
+ #include <linux/bcma/bcma.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+ #include <linux/time.h>
++static const char * const part_probes[] = { "bcm47xxpart", NULL };
++
++static struct physmap_flash_data bcma_pflash_data = {
++      .part_probe_types       = part_probes,
++};
++
++static struct resource bcma_pflash_resource = {
++      .name   = "bcma_pflash",
++      .flags  = IORESOURCE_MEM,
++};
++
++struct platform_device bcma_pflash_dev = {
++      .name           = "physmap-flash",
++      .dev            = {
++              .platform_data  = &bcma_pflash_data,
++      },
++      .resource       = &bcma_pflash_resource,
++      .num_resources  = 1,
++};
++
  /* The 47162a0 hangs when reading MIPS DMP registers registers */
  static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
  {
               dev->bus->chipinfo.pkg == 11 &&
               dev->id.id == BCMA_CORE_USB20_HOST;
  }
-@@ -74,11 +74,16 @@ static u32 bcma_core_mips_irqflag(struct
+@@ -74,28 +96,41 @@ static u32 bcma_core_mips_irqflag(struct
                return dev->core_index;
        flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
  
 + * If disabled, 5 is returned.
 + * If not supported, 6 is returned.
   */
- unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+-unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
  {
-@@ -87,13 +92,15 @@ unsigned int bcma_core_mips_irq(struct b
+       struct bcma_device *mdev = dev->bus->drv_mips.core;
+       u32 irqflag;
        unsigned int irq;
  
        irqflag = bcma_core_mips_irqflag(dev);
  
 -      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_mips_irq);
++EXPORT_SYMBOL(bcma_core_irq);
  
-@@ -114,8 +121,8 @@ static void bcma_core_mips_set_irq(struc
+ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+ {
+@@ -114,8 +149,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));
  
        /* assign the new one */
        if (irq == 0) {
-@@ -123,17 +130,17 @@ static void bcma_core_mips_set_irq(struc
+@@ -123,17 +158,17 @@ static void bcma_core_mips_set_irq(struc
                            bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
                            (1 << irqflag));
        } else {
                                        bcma_core_mips_set_irq(core, 0);
                                        break;
                                }
-@@ -143,15 +150,31 @@ static void bcma_core_mips_set_irq(struc
+@@ -143,15 +178,31 @@ static void bcma_core_mips_set_irq(struc
                             1 << irqflag);
        }
  
        for (i = 0; i <= 6; i++)
                printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
        printk("\n");
-@@ -161,7 +184,7 @@ static void bcma_core_mips_dump_irq(stru
+@@ -161,7 +212,7 @@ static void bcma_core_mips_dump_irq(stru
  {
        struct bcma_device *core;
  
                bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
        }
  }
-@@ -171,9 +194,9 @@ u32 bcma_cpu_clock(struct bcma_drv_mips
+@@ -171,9 +222,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 0;
  }
  EXPORT_SYMBOL(bcma_cpu_clock);
-@@ -181,76 +204,109 @@ EXPORT_SYMBOL(bcma_cpu_clock);
+@@ -181,25 +232,81 @@ EXPORT_SYMBOL(bcma_cpu_clock);
  static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
  {
        struct bcma_bus *bus = mcore->core->bus;
 +      struct bcma_drv_cc *cc = &bus->drv_cc;
++      struct bcma_pflash *pflash = &cc->pflash;
  
 -      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
 +      switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 -              bus->drv_cc.pflash.window = 0x1c000000;
 -              bus->drv_cc.pflash.window_size = 0x02000000;
 +              bcma_debug(bus, "Found parallel flash\n");
-+              cc->pflash.present = true;
-+              cc->pflash.window = BCMA_SOC_FLASH2;
-+              cc->pflash.window_size = BCMA_SOC_FLASH2_SZ;
++              pflash->present = true;
++              pflash->window = BCMA_SOC_FLASH2;
++              pflash->window_size = BCMA_SOC_FLASH2_SZ;
  
 -              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
 +              if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
                     BCMA_CC_FLASH_CFG_DS) == 0)
 -                      bus->drv_cc.pflash.buswidth = 1;
-+                      cc->pflash.buswidth = 1;
++                      pflash->buswidth = 1;
                else
 -                      bus->drv_cc.pflash.buswidth = 2;
-+                      cc->pflash.buswidth = 2;
++                      pflash->buswidth = 2;
++
++              bcma_pflash_data.width = pflash->buswidth;
++              bcma_pflash_resource.start = pflash->window;
++              bcma_pflash_resource.end = pflash->window + pflash->window_size;
++
                break;
        default:
 -              pr_err("flash not supported.\n");
 +                      bcma_debug(bus, "Found NAND flash\n");
 +                      bcma_nflash_init(cc);
 +              }
-       }
- }
++      }
++}
++
 +void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
 +{
 +      struct bcma_bus *bus = mcore->core->bus;
 +      mcore->early_setup_done = true;
 +}
 +
- void bcma_core_mips_init(struct bcma_drv_mips *mcore)
- {
-       struct bcma_bus *bus;
++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,48 +316,59 @@ void bcma_core_mips_init(struct bcma_drv
        struct bcma_device *core;
        bus = mcore->core->bus;
  
 -      pr_info("Initializing MIPS core...\n");
 +      if (mcore->setup_done)
 +              return;
-+
-+      bcma_debug(bus, "Initializing MIPS core...\n");
  
 -      if (!mcore->setup_done)
 -              mcore->assigned_irqs = 1;
-+      bcma_core_mips_early_init(mcore);
++      bcma_debug(bus, "Initializing MIPS core...\n");
  
 -      /* Assign IRQs to all cores on the bus */
 -      list_for_each_entry_reverse(core, &bus->cores, list) {
 -                              bcma_core_mips_set_irq(core,
 -                                                     mcore->assigned_irqs++);
 -                      break;
++      bcma_core_mips_early_init(mcore);
++
++      bcma_fix_i2s_irqflag(bus);
++
 +      switch (bus->chipinfo.id) {
 +      case BCMA_CHIP_ID_BCM4716:
 +      case BCMA_CHIP_ID_BCM4748:
 +              break;
 +      default:
 +              list_for_each_entry(core, &bus->cores, list) {
-+                      core->irq = bcma_core_mips_irq(core) + 2;
++                      core->irq = bcma_core_irq(core);
                }
 +              bcma_err(bus,
 +                       "Unknown device (0x%x) found, can not configure IRQs\n",
 +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,600 @@
+@@ -2,13 +2,616 @@
   * Broadcom specific AMBA
   * PCI Core in hostmode
   *
 +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 */
 +              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;
 +      /* Reset RC */
 +      usleep_range(3000, 5000);
 +      pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
-+      usleep_range(1000, 2000);
++      msleep(50);
 +      pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
 +                      BCMA_CORE_PCI_CTL_RST_OE);
 +
 +
 +      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));
 +      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
  static int bcma_host_pci_suspend(struct device *dev)
  {
        struct pci_dev *pdev = to_pci_dev(dev);
-@@ -257,17 +261,20 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bc
+@@ -257,17 +261,21 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bc
                         bcma_host_pci_resume);
  #define BCMA_PM_OPS   (&bcma_pm_ops)
  
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
 +      { 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 +284,7 @@ static struct pci_driver bcma_pci_bridge
+@@ -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,
  {
        struct bcma_device *core;
  
-@@ -65,6 +79,19 @@ static struct bcma_device *bcma_find_cor
+@@ -65,6 +79,38 @@ static struct bcma_device *bcma_find_cor
        }
        return NULL;
  }
 +      }
 +      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 +111,18 @@ static int bcma_register_cores(struct bc
+@@ -84,16 +130,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,41 +140,90 @@ static int bcma_register_cores(struct bc
+@@ -111,41 +164,98 @@ static int bcma_register_cores(struct bc
  
                err = device_register(&core->dev);
                if (err) {
                dev_id++;
        }
  
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      if (bus->drv_cc.pflash.present) {
++              err = platform_device_register(&bcma_pflash_dev);
++              if (err)
++                      bcma_err(bus, "Error registering parallel flash\n");
++      }
++#endif
++
 +#ifdef CONFIG_BCMA_SFLASH
 +      if (bus->drv_cc.sflash.present) {
 +              err = platform_device_register(&bcma_sflash_dev);
        if (core) {
                bus->drv_cc.core = core;
                bcma_core_chipcommon_init(&bus->drv_cc);
-@@ -159,30 +237,47 @@ int bcma_bus_register(struct bcma_bus *b
+@@ -159,30 +269,54 @@ int bcma_bus_register(struct bcma_bus *b
        }
  
        /* Init PCIE core */
  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);
  }
  
  int __init bcma_bus_early_register(struct bcma_bus *bus,
-@@ -196,14 +291,14 @@ int __init bcma_bus_early_register(struc
+@@ -196,14 +330,14 @@ int __init bcma_bus_early_register(struc
        bcma_init_bus(bus);
  
        match.manuf = BCMA_MANUF_BCM;
                return -1;
        }
  
-@@ -215,25 +310,25 @@ int __init bcma_bus_early_register(struc
+@@ -215,25 +349,25 @@ int __init bcma_bus_early_register(struc
        /* Scan for mips core */
        err = bcma_bus_scan_early(bus, &match, core_mips);
        if (err) {
  
        return 0;
  }
-@@ -259,8 +354,7 @@ int bcma_bus_resume(struct bcma_bus *bus
+@@ -259,8 +393,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)
        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,9 +460,12 @@ 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) {
                INIT_LIST_HEAD(&core->list);
                core->bus = bus;
  
-@@ -409,25 +480,28 @@ int bcma_bus_scan(struct bcma_bus *bus)
+@@ -409,25 +482,28 @@ int bcma_bus_scan(struct bcma_bus *bus)
                        } else if (err == -ESPIPE) {
                                break;
                        }
  }
  
  int __init bcma_bus_scan_early(struct bcma_bus *bus,
-@@ -467,21 +541,21 @@ int __init bcma_bus_scan_early(struct bc
+@@ -467,21 +543,21 @@ int __init bcma_bus_scan_early(struct bc
                else if (err == -ESPIPE)
                        break;
                else if (err < 0)
   * 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,107 +216,390 @@ 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);
++      SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
 +
 +      SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
 +           SSB_SPROM4_TXPID2G0_SHIFT);
 +              SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
 +              SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~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(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
 +           SSB_SROM8_FEM_TSSIPOS_SHIFT);
 +      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
 +      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 */
 -      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);
  
-       err = bcma_sprom_valid(sprom);
--      if (err)
+-      bcma_sprom_extract_r8(bus, sprom);
 +      if (err) {
-+              bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
++              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);
-               goto out;
++      } else {
++              bcma_sprom_extract_r8(bus, sprom);
++              kfree(sprom);
 +      }
  
-       bcma_sprom_extract_r8(bus, sprom);
+-out:
+-      kfree(sprom);
+       return err;
+ }
 --- a/include/linux/bcma/bcma.h
 +++ b/include/linux/bcma/bcma.h
 @@ -7,9 +7,10 @@
  #define BCMA_CORE_INVALID             0x700
  #define BCMA_CORE_CHIPCOMMON          0x800
  #define BCMA_CORE_ILINE20             0x801
-@@ -121,10 +134,46 @@ 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_ARM_CR4             0x83e
++#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
 +#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 +185,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 +226,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 +248,18 @@ struct bcma_bus {
+@@ -191,14 +306,18 @@ struct bcma_bus {
  
        struct bcma_chipinfo chipinfo;
  
  
        /* 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 +343,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 +351,7 @@ extern void bcma_core_set_clockmode(stru
+@@ -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);
  #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_NFLASH               0x00000200      /* NAND flash */
++#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
  #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 */
-@@ -240,7 +356,60 @@
+@@ -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) */
  
  /* Divider allocation in 4716/47162/5356 */
  #define BCMA_CC_PMU5_MAINPLL_CPU      1
-@@ -256,6 +425,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 +462,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 +488,25 @@
+@@ -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 */
 +#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)
   */
-@@ -310,11 +517,35 @@ struct bcma_chipcommon_pmu {
+@@ -310,11 +572,36 @@ struct bcma_chipcommon_pmu {
  
  #ifdef CONFIG_BCMA_DRIVER_MIPS
  struct bcma_pflash {
 +      u32 size;
 +
 +      struct mtd_info *mtd;
++      void *priv;
 +};
 +#endif
 +
  struct bcma_serial_port {
        void *regs;
        unsigned long clockspeed;
-@@ -330,15 +561,30 @@ struct bcma_drv_cc {
+@@ -330,15 +617,30 @@ struct bcma_drv_cc {
        u32 capabilities;
        u32 capabilities_ext;
        u8 setup_done:1;
  };
  
  /* Register access */
-@@ -355,14 +601,16 @@ struct bcma_drv_cc {
+@@ -355,14 +657,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);
  
  void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value);
  
-@@ -375,9 +623,12 @@ u32 bcma_chipco_gpio_outen(struct bcma_d
+@@ -375,9 +679,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);
  
  extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
                                  u32 value);
-@@ -387,5 +638,6 @@ extern void bcma_chipco_chipctl_maskset(
+@@ -387,5 +694,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 /* LINUX_BCMA_DRIVER_GMAC_CMN_H_ */
 --- a/include/linux/bcma/bcma_driver_mips.h
 +++ b/include/linux/bcma/bcma_driver_mips.h
-@@ -35,13 +35,15 @@ struct bcma_device;
+@@ -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;
  #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
 +
index 6f9c834..2d13458 100644 (file)
@@ -30,7 +30,7 @@
                                            ARRAY_SIZE(wgt634u_devices));
 --- a/drivers/ssb/Kconfig
 +++ b/drivers/ssb/Kconfig
-@@ -136,6 +136,11 @@ config SSB_DRIVER_MIPS
+@@ -136,10 +136,15 @@ config SSB_DRIVER_MIPS
  
          If unsure, say N
  
  # Assumption: We are on embedded, if we compile the MIPS core.
  config SSB_EMBEDDED
        bool
+-      depends on SSB_DRIVER_MIPS
++      depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
+       default y
+ config SSB_DRIVER_EXTIF
 @@ -160,4 +165,12 @@ config SSB_DRIVER_GIGE
  
          If unsure, say N
  
  #include "ssb_private.h"
  
-@@ -280,10 +282,76 @@ static void calc_fast_powerup_delay(stru
+@@ -280,13 +282,79 @@ static void calc_fast_powerup_delay(stru
        cc->fast_pwrup_delay = tmp;
  }
  
 +
        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_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);
                                /* Turn off UART clock before switching clocksource. */
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
-@@ -346,6 +346,8 @@ static void ssb_pmu_pll_init(struct ssb_
+@@ -110,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) {
+@@ -138,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);
+@@ -249,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) {
+@@ -275,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);
+@@ -346,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",
-@@ -434,6 +436,7 @@ static void ssb_pmu_resources_init(struc
+-              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);
+       }
+ }
+@@ -434,6 +435,7 @@ static void ssb_pmu_resources_init(struc
                 min_msk = 0xCBB;
                 break;
        case 0x4322:
                /* We keep the default settings:
                 * min_msk = 0xCBB
                 * max_msk = 0x7FFFF
-@@ -615,6 +618,33 @@ void ssb_pmu_set_ldo_paref(struct ssb_ch
+@@ -469,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) {
+@@ -523,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,
+@@ -615,6 +616,32 @@ void ssb_pmu_set_ldo_paref(struct ssb_ch
  EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
  EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
  
 +      case 0x5354:
 +              ssb_pmu_get_alp_clock_clk0(cc);
 +      default:
-+              ssb_printk(KERN_ERR PFX
-+                         "ERROR: PMU alp clock unknown for device %04X\n",
-+                         bus->chip_id);
++              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;
-@@ -645,3 +675,32 @@ u32 ssb_pmu_get_controlclock(struct ssb_
+@@ -624,9 +651,8 @@ u32 ssb_pmu_get_cpu_clock(struct ssb_chi
+               /* 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);
++              ssb_err("ERROR: PMU cpu clock unknown for device %04X\n",
++                      bus->chip_id);
+               return 0;
+       }
+ }
+@@ -639,9 +665,52 @@ u32 ssb_pmu_get_controlclock(struct ssb_
+       case 0x5354:
+               return 120000000;
+       default:
+-              ssb_printk(KERN_ERR PFX
+-                         "ERROR: PMU controlclock unknown for device %04X\n",
+-                         bus->chip_id);
++              ssb_err("ERROR: PMU controlclock unknown for device %04X\n",
++                      bus->chip_id);
                return 0;
        }
  }
 +              pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
 +              break;
 +      case 43222:
-+              /* TODO: BCM43222 requires updating PLLs too */
-+              return;
++              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",
 +EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate);
 --- /dev/null
 +++ b/drivers/ssb/driver_chipcommon_sflash.c
-@@ -0,0 +1,18 @@
+@@ -0,0 +1,166 @@
 +/*
 + * Sonics Silicon Backplane
 + * ChipCommon serial flash interface
 +
 +#include "ssb_private.h"
 +
++static struct resource ssb_sflash_resource = {
++      .name   = "ssb_sflash",
++      .start  = SSB_FLASH2,
++      .end    = 0,
++      .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
++};
++
++struct platform_device ssb_sflash_dev = {
++      .name           = "ssb_sflash",
++      .resource       = &ssb_sflash_resource,
++      .num_resources  = 1,
++};
++
++struct ssb_sflash_tbl_e {
++      char *name;
++      u32 id;
++      u32 blocksize;
++      u16 numblocks;
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
++      { "M25P20", 0x11, 0x10000, 4, },
++      { "M25P40", 0x12, 0x10000, 8, },
++
++      { "M25P16", 0x14, 0x10000, 32, },
++      { "M25P32", 0x15, 0x10000, 64, },
++      { "M25P64", 0x16, 0x10000, 128, },
++      { "M25FL128", 0x17, 0x10000, 256, },
++      { 0 },
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
++      { "SST25WF512", 1, 0x1000, 16, },
++      { "SST25VF512", 0x48, 0x1000, 16, },
++      { "SST25WF010", 2, 0x1000, 32, },
++      { "SST25VF010", 0x49, 0x1000, 32, },
++      { "SST25WF020", 3, 0x1000, 64, },
++      { "SST25VF020", 0x43, 0x1000, 64, },
++      { "SST25WF040", 4, 0x1000, 128, },
++      { "SST25VF040", 0x44, 0x1000, 128, },
++      { "SST25VF040B", 0x8d, 0x1000, 128, },
++      { "SST25WF080", 5, 0x1000, 256, },
++      { "SST25VF080B", 0x8e, 0x1000, 256, },
++      { "SST25VF016", 0x41, 0x1000, 512, },
++      { "SST25VF032", 0x4a, 0x1000, 1024, },
++      { "SST25VF064", 0x4b, 0x1000, 2048, },
++      { 0 },
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
++      { "AT45DB011", 0xc, 256, 512, },
++      { "AT45DB021", 0x14, 256, 1024, },
++      { "AT45DB041", 0x1c, 256, 2048, },
++      { "AT45DB081", 0x24, 256, 4096, },
++      { "AT45DB161", 0x2c, 512, 4096, },
++      { "AT45DB321", 0x34, 512, 8192, },
++      { "AT45DB642", 0x3c, 1024, 8192, },
++      { 0 },
++};
++
++static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
++{
++      int i;
++      chipco_write32(cc, SSB_CHIPCO_FLASHCTL,
++                     SSB_CHIPCO_FLASHCTL_START | opcode);
++      for (i = 0; i < 1000; i++) {
++              if (!(chipco_read32(cc, SSB_CHIPCO_FLASHCTL) &
++                    SSB_CHIPCO_FLASHCTL_BUSY))
++                      return;
++              cpu_relax();
++      }
++      pr_err("SFLASH control command failed (timeout)!\n");
++}
++
 +/* Initialize serial flash access */
 +int ssb_sflash_init(struct ssb_chipcommon *cc)
 +{
++      struct ssb_sflash *sflash = &cc->dev->bus->mipscore.sflash;
++      const struct ssb_sflash_tbl_e *e;
++      u32 id, id2;
++
++      switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++      case SSB_CHIPCO_FLASHT_STSER:
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_DP);
++
++              chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 0);
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
++              id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
++
++              chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 1);
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
++              id2 = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
++
++              switch (id) {
++              case 0xbf:
++                      for (e = ssb_sflash_sst_tbl; e->name; e++) {
++                              if (e->id == id2)
++                                      break;
++                      }
++                      break;
++              case 0x13:
++                      return -ENOTSUPP;
++              default:
++                      for (e = ssb_sflash_st_tbl; e->name; e++) {
++                              if (e->id == id)
++                                      break;
++                      }
++                      break;
++              }
++              if (!e->name) {
++                      pr_err("Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n",
++                             id, id2);
++                      return -ENOTSUPP;
++              }
++
++              break;
++      case SSB_CHIPCO_FLASHT_ATSER:
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
++              id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA) & 0x3c;
++
++              for (e = ssb_sflash_at_tbl; e->name; e++) {
++                      if (e->id == id)
++                              break;
++              }
++              if (!e->name) {
++                      pr_err("Unsupported Atmel serial flash (id: 0x%X)\n",
++                             id);
++                      return -ENOTSUPP;
++              }
++
++              break;
++      default:
++              pr_err("Unsupported flash type\n");
++              return -ENOTSUPP;
++      }
++
++      sflash->window = SSB_FLASH2;
++      sflash->blocksize = e->blocksize;
++      sflash->numblocks = e->numblocks;
++      sflash->size = sflash->blocksize * sflash->numblocks;
++      sflash->present = true;
++
++      pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
++              e->name, e->blocksize, e->numblocks);
++
++      /* Prepare platform device, but don't register it yet. It's too early,
++       * malloc (required by device_private_init) is not available yet. */
++      ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
++                                       sflash->size;
++      ssb_sflash_dev.dev.platform_data = sflash;
++
 +      pr_err("Serial flash support is not implemented yet!\n");
 +
 +      return -ENOTSUPP;
  }
 --- /dev/null
 +++ b/drivers/ssb/driver_gpio.c
-@@ -0,0 +1,176 @@
+@@ -0,0 +1,210 @@
 +/*
 + * Sonics Silicon Backplane
 + * GPIO driver
 +      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->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
 +      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->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
 +
 +      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
-@@ -178,9 +178,9 @@ static void ssb_mips_serial_init(struct
+@@ -10,6 +10,7 @@
+ #include <linux/ssb/ssb.h>
++#include <linux/mtd/physmap.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+@@ -17,6 +18,25 @@
+ #include "ssb_private.h"
++static const char * const part_probes[] = { "bcm47xxpart", NULL };
++
++static struct physmap_flash_data ssb_pflash_data = {
++      .part_probe_types       = part_probes,
++};
++
++static struct resource ssb_pflash_resource = {
++      .name   = "ssb_pflash",
++      .flags  = IORESOURCE_MEM,
++};
++
++struct platform_device ssb_pflash_dev = {
++      .name           = "physmap-flash",
++      .dev            = {
++              .platform_data  = &ssb_pflash_data,
++      },
++      .resource       = &ssb_pflash_resource,
++      .num_resources  = 1,
++};
+ static inline u32 mips_read32(struct ssb_mipscore *mcore,
+                             u16 offset)
+@@ -147,21 +167,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 +199,9 @@ static void ssb_mips_serial_init(struct
  {
        struct ssb_bus *bus = mcore->dev->bus;
  
                mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
        else
                mcore->nr_serial_ports = 0;
-@@ -190,16 +190,33 @@ static void ssb_mips_flash_detect(struct
+@@ -189,17 +210,42 @@ static void ssb_mips_serial_init(struct
+ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
  {
        struct ssb_bus *bus = mcore->dev->bus;
++      struct ssb_pflash *pflash = &mcore->pflash;
  
 -      mcore->flash_buswidth = 2;
 -      if (bus->chipco.dev) {
 -              mcore->flash_window_size = 0x02000000;
 +      /* When there is no chipcommon on the bus there is 4MB flash */
 +      if (!ssb_chipco_available(&bus->chipco)) {
-+              mcore->pflash.present = true;
-+              mcore->pflash.buswidth = 2;
-+              mcore->pflash.window = SSB_FLASH1;
-+              mcore->pflash.window_size = SSB_FLASH1_SZ;
-+              return;
++              pflash->present = true;
++              pflash->buswidth = 2;
++              pflash->window = SSB_FLASH1;
++              pflash->window_size = SSB_FLASH1_SZ;
++              goto ssb_pflash;
 +      }
 +
 +      /* There is ChipCommon, so use it to read info about flash */
 +              break;
 +      case SSB_CHIPCO_FLASHT_PARA:
 +              pr_debug("Found parallel flash\n");
-+              mcore->pflash.present = true;
-+              mcore->pflash.window = SSB_FLASH2;
-+              mcore->pflash.window_size = SSB_FLASH2_SZ;
++              pflash->present = true;
++              pflash->window = SSB_FLASH2;
++              pflash->window_size = SSB_FLASH2_SZ;
                if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
                               & SSB_CHIPCO_CFG_DS16) == 0)
 -                      mcore->flash_buswidth = 1;
 -      } else {
 -              mcore->flash_window = 0x1fc00000;
 -              mcore->flash_window_size = 0x00400000;
-+                      mcore->pflash.buswidth = 1;
++                      pflash->buswidth = 1;
 +              else
-+                      mcore->pflash.buswidth = 2;
++                      pflash->buswidth = 2;
 +              break;
++      }
++
++ssb_pflash:
++      if (pflash->present) {
++              ssb_pflash_data.width = pflash->buswidth;
++              ssb_pflash_resource.start = pflash->window;
++              ssb_pflash_resource.end = pflash->window + pflash->window_size;
        }
  }
  
-@@ -211,9 +228,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
+@@ -211,9 +257,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
        if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)
                return ssb_pmu_get_cpu_clock(&bus->chipco);
  
                ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
        } else
                return 0;
-@@ -249,9 +266,9 @@ void ssb_mipscore_init(struct ssb_mipsco
+@@ -241,7 +287,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);
+@@ -249,9 +295,9 @@ void ssb_mipscore_init(struct ssb_mipsco
                hz = 100000000;
        ns = 1000000000 / hz;
  
                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 */
+@@ -289,7 +335,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 @@
  #include <linux/ssb/ssb.h>
  #include <linux/ssb/ssb_embedded.h>
  #include <linux/ssb/ssb_driver_pci.h>
-@@ -32,6 +34,39 @@ int ssb_watchdog_timer_set(struct ssb_bu
+@@ -32,6 +34,38 @@ int ssb_watchdog_timer_set(struct ssb_bu
  }
  EXPORT_SYMBOL(ssb_watchdog_timer_set);
  
 +                                           bus->busnumber, &wdt,
 +                                           sizeof(wdt));
 +      if (IS_ERR(pdev)) {
-+              ssb_dprintk(KERN_INFO PFX
-+                          "can not register watchdog device, err: %li\n",
-+                          PTR_ERR(pdev));
++              ssb_dbg("can not register watchdog device, err: %li\n",
++                      PTR_ERR(pdev));
 +              return PTR_ERR(pdev);
 +      }
 +
  #include <linux/ssb/ssb.h>
  #include <linux/ssb/ssb_regs.h>
  #include <linux/ssb/ssb_driver_gige.h>
-@@ -433,6 +434,11 @@ static void ssb_devices_unregister(struc
+@@ -274,8 +275,8 @@ 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_device_put(sdev);
+@@ -433,10 +434,23 @@ static void ssb_devices_unregister(struc
                if (sdev->dev)
                        device_unregister(sdev->dev);
        }
  }
  
  void ssb_bus_unregister(struct ssb_bus *bus)
-@@ -561,6 +567,8 @@ static int __devinit ssb_attach_queued_b
+ {
++      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);
+@@ -482,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;
+               }
+@@ -522,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;
+@@ -534,6 +545,22 @@ static int ssb_devices_register(struct s
+               dev_idx++;
+       }
++#ifdef CONFIG_SSB_DRIVER_MIPS
++      if (bus->mipscore.pflash.present) {
++              err = platform_device_register(&ssb_pflash_dev);
++              if (err)
++                      pr_err("Error registering parallel flash\n");
++      }
++#endif
++
++#ifdef CONFIG_SSB_SFLASH
++      if (bus->mipscore.sflash.present) {
++              err = platform_device_register(&ssb_sflash_dev);
++              if (err)
++                      pr_err("Error registering serial flash\n");
++      }
++#endif
++
+       return 0;
+ error:
+       /* Unwind the already registered devices. */
+@@ -561,6 +588,8 @@ static int __devinit ssb_attach_queued_b
                if (err)
                        goto error;
                ssb_pcicore_init(&bus->pcicore);
                ssb_bus_may_powerdown(bus);
  
                err = ssb_devices_register(bus);
-@@ -796,7 +804,14 @@ static int __devinit ssb_bus_register(st
+@@ -796,7 +825,13 @@ static int __devinit ssb_bus_register(st
        if (err)
                goto err_pcmcia_exit;
        ssb_chipcommon_init(&bus->chipco);
        ssb_mipscore_init(&bus->mipscore);
 +      err = ssb_gpio_init(bus);
 +      if (err == -ENOTSUPP)
-+              ssb_dprintk(KERN_DEBUG PFX "GPIO driver not activated\n");
++              ssb_dbg("GPIO driver not activated\n");
 +      else if (err)
-+              ssb_dprintk(KERN_ERR PFX
-+                         "Error registering GPIO driver: %i\n", err);
++              ssb_dbg("Error registering GPIO driver: %i\n", err);
        err = ssb_fetch_invariants(bus, get_invariants);
        if (err) {
                ssb_bus_may_powerdown(bus);
-@@ -1118,8 +1133,7 @@ static u32 ssb_tmslow_reject_bitmask(str
+@@ -847,11 +882,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;
+@@ -872,8 +907,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;
+@@ -895,8 +930,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;
+@@ -915,8 +950,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;
+@@ -1118,8 +1153,7 @@ static u32 ssb_tmslow_reject_bitmask(str
        case SSB_IDLOW_SSBREV_27:     /* same here */
                return SSB_TMSLOW_REJECT;       /* this is a guess */
        default:
        }
        return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
  }
+@@ -1311,7 +1345,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);
+@@ -1334,7 +1368,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);
+@@ -1442,15 +1476,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
+@@ -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);
+@@ -231,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 word;
+@@ -278,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;
+@@ -286,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);
+@@ -309,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;
+ }
+@@ -339,10 +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;
+       u16 loc[3];
+       if (out->revision == 3)                 /* rev 3 moved MAC */
+@@ -352,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,
+@@ -372,6 +384,7 @@ 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(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);
+@@ -398,8 +411,7 @@ 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);
++
+       SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
+       SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
+@@ -410,6 +422,8 @@ static void sprom_extract_r123(struct ss
+       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 */
+@@ -454,23 +468,20 @@ 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(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
+               SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
+@@ -530,7 +541,7 @@ static void sprom_extract_r45(struct ssb
+ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
+ {
+       int i;
+-      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
+@@ -539,11 +550,10 @@ static void sprom_extract_r8(struct ssb_
+                       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);
+-      }
++      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);
+@@ -743,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);
+@@ -752,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) {
+@@ -769,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);
+       }
+@@ -791,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! */
+@@ -810,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)
+@@ -835,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);
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -38,7 +38,7 @@ static int ssb_pcihost_resume(struct pci
+       struct ssb_bus *ssb = pci_get_drvdata(dev);
+       int err;
+-      pci_set_power_state(dev, 0);
++      pci_set_power_state(dev, PCI_D0);
+       err = pci_enable_device(dev);
+       if (err)
+               return err;
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -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;
+@@ -700,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;
+@@ -722,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;
+       }
+@@ -733,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;
+ }
+@@ -843,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
+@@ -125,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;
+@@ -152,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;
+@@ -320,15 +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) {
+@@ -370,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;
+                               }
+                       }
+@@ -379,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;
+@@ -388,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;
+@@ -398,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;
+@@ -420,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/sprom.c
++++ b/drivers/ssb/sprom.c
+@@ -54,7 +54,7 @@ static int hex2sprom(u16 *sprom, const c
+       while (cnt < sprom_size_words) {
+               memcpy(tmp, dump, 4);
+               dump += 4;
+-              err = strict_strtoul(tmp, 16, &parsed);
++              err = kstrtoul(tmp, 16, &parsed);
+               if (err)
+                       return err;
+               sprom[cnt++] = swab16((u16)parsed);
+@@ -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
-@@ -3,6 +3,7 @@
+@@ -3,21 +3,33 @@
  
  #include <linux/ssb/ssb.h>
  #include <linux/types.h>
  
  
  #define PFX   "ssb: "
-@@ -210,5 +211,63 @@ static inline void b43_pci_ssb_bridge_ex
+ #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
+@@ -210,5 +222,76 @@ static inline void b43_pci_ssb_bridge_ex
  /* 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);
 +}
 +#endif /* CONFIG_SSB_SFLASH */
 +
++#ifdef CONFIG_SSB_DRIVER_MIPS
++extern struct platform_device ssb_pflash_dev;
++#endif
++
++#ifdef CONFIG_SSB_SFLASH
++extern struct platform_device ssb_sflash_dev;
++#endif
++
 +#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);
 +
 +#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_ */
  
  #include <linux/ssb/ssb_regs.h>
  
-@@ -432,7 +434,11 @@ struct ssb_bus {
+@@ -24,9 +26,9 @@ struct ssb_sprom_core_pwr_info {
+ struct ssb_sprom {
+       u8 revision;
+-      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 */
+@@ -338,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 */
+@@ -432,7 +482,11 @@ struct ssb_bus {
  #ifdef CONFIG_SSB_EMBEDDED
        /* Lock for GPIO register access. */
        spinlock_t gpio_lock;
 +
  #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
+@@ -97,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);
+@@ -175,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
-@@ -13,6 +13,12 @@ struct ssb_serial_port {
+@@ -13,6 +13,24 @@ struct ssb_serial_port {
        unsigned int reg_shift;
  };
  
 +      u32 window;
 +      u32 window_size;
 +};
++
++#ifdef CONFIG_SSB_SFLASH
++struct ssb_sflash {
++      bool present;
++      u32 window;
++      u32 blocksize;
++      u16 numblocks;
++      u32 size;
++
++      void *priv;
++};
++#endif
  
  struct ssb_mipscore {
        struct ssb_device *dev;
-@@ -20,9 +26,7 @@ struct ssb_mipscore {
+@@ -20,9 +38,10 @@ struct ssb_mipscore {
        int nr_serial_ports;
        struct ssb_serial_port serial_ports[4];
  
 -      u32 flash_window;
 -      u32 flash_window_size;
 +      struct ssb_pflash pflash;
++#ifdef CONFIG_SSB_SFLASH
++      struct ssb_sflash sflash;
++#endif
  };
  
  extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
+@@ -41,6 +60,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
-@@ -289,11 +289,11 @@
+@@ -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
+@@ -289,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_AGAIN01            0x005E  /* Antenna Gain (in dBm Q5.2) */
  #define  SSB_SPROM4_AGAIN0            0x00FF  /* Antenna 0 */
  #define  SSB_SPROM4_AGAIN0_SHIFT      0
-@@ -485,7 +485,7 @@
+@@ -485,7 +486,7 @@
  #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
                break;
  #endif
        }
---- a/drivers/ssb/pci.c
-+++ b/drivers/ssb/pci.c
-@@ -339,6 +339,21 @@ 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;
-@@ -398,8 +413,7 @@ 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);
-+
-       SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
-       SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
-@@ -410,6 +424,8 @@ static void sprom_extract_r123(struct ss
-       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 */
index 15f54a7..9ad3ce3 100644 (file)
@@ -1,6 +1,25 @@
+--- 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/drivers/bcma/Kconfig
 +++ b/drivers/bcma/Kconfig
-@@ -48,12 +48,12 @@ config BCMA_DRIVER_MIPS
+@@ -26,6 +26,7 @@ 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"
+@@ -48,12 +49,12 @@ config BCMA_DRIVER_MIPS
  
  config BCMA_SFLASH
        bool
@@ -15,7 +34,7 @@
        default y
  
  config BCMA_DRIVER_GMAC_CMN
-@@ -65,6 +65,14 @@ config BCMA_DRIVER_GMAC_CMN
+@@ -65,6 +66,14 @@ config BCMA_DRIVER_GMAC_CMN
  
          If unsure, say N
  
  obj-$(CONFIG_BCMA)                    += bcma.o
 --- a/drivers/bcma/bcma_private.h
 +++ b/drivers/bcma/bcma_private.h
-@@ -31,6 +31,8 @@ int __init bcma_bus_early_register(struc
+@@ -22,6 +22,8 @@
+ struct bcma_bus;
+ /* main.c */
++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,
+@@ -31,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
  
  /* scan.c */
  int bcma_bus_scan(struct bcma_bus *bus);
-@@ -48,12 +50,13 @@ void bcma_chipco_serial_init(struct bcma
+@@ -45,15 +49,17 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ /* driver_chipcommon.c */
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++extern struct platform_device bcma_pflash_dev;
  #endif /* CONFIG_BCMA_DRIVER_MIPS */
  
  /* driver_chipcommon_pmu.c */
@@ -67,7 +99,7 @@
  #else
  static inline int bcma_sflash_init(struct bcma_drv_cc *cc)
  {
-@@ -65,6 +68,7 @@ static inline int bcma_sflash_init(struc
+@@ -65,6 +71,7 @@ static inline int bcma_sflash_init(struc
  #ifdef CONFIG_BCMA_NFLASH
  /* driver_chipcommon_nflash.c */
  int bcma_nflash_init(struct bcma_drv_cc *cc);
  #else
  static inline int bcma_nflash_init(struct bcma_drv_cc *cc)
  {
-@@ -82,9 +86,21 @@ extern void __exit bcma_host_pci_exit(vo
+@@ -82,9 +89,26 @@ extern void __exit bcma_host_pci_exit(vo
  /* driver_pci.c */
  u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
  
 +#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
-@@ -65,7 +65,7 @@ void bcma_core_set_clockmode(struct bcma
+@@ -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,13 +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);
+@@ -43,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));
+@@ -65,7 +87,7 @@ void bcma_core_set_clockmode(struct bcma
        switch (clkmode) {
        case BCMA_CLKMODE_FAST:
                bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
                for (i = 0; i < 1500; i++) {
                        if (bcma_read32(core, BCMA_CLKCTLST) &
                            BCMA_CLKCTLST_HAVEHT) {
+@@ -104,7 +126,13 @@ void bcma_core_pll_ctl(struct bcma_devic
+               if (i)
+                       bcma_err(core->bus, "PLL enable timeout\n");
+       } else {
+-              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);
 --- a/drivers/bcma/driver_chipcommon.c
 +++ b/drivers/bcma/driver_chipcommon.c
 @@ -4,12 +4,15 @@
  #include <linux/bcma/bcma.h>
  
  static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
-@@ -22,20 +25,120 @@ static inline u32 bcma_cc_write32_masked
+@@ -22,23 +25,130 @@ static inline u32 bcma_cc_write32_masked
        return value;
  }
  
 +      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);
-@@ -56,15 +159,33 @@ void bcma_core_chipcommon_init(struct bc
+-              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)
+@@ -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)));
        }
  }
  
  void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
-@@ -84,28 +205,99 @@ u32 bcma_chipco_gpio_in(struct bcma_drv_
+@@ -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)
  {
  }
  
  #ifdef CONFIG_BCMA_DRIVER_MIPS
-@@ -118,8 +310,7 @@ void bcma_chipco_serial_init(struct bcma
+@@ -118,8 +317,7 @@ void bcma_chipco_serial_init(struct bcma
        struct bcma_serial_port *ports = cc->serial_ports;
  
        if (ccrev >= 11 && ccrev != 15) {
                if (ccrev >= 21) {
                        /* Turn off UART clock before switching clocksource. */
                        bcma_cc_write32(cc, BCMA_CC_CORECTL,
+@@ -141,7 +339,7 @@ void bcma_chipco_serial_init(struct bcma
+               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_nflash.c
 +++ b/drivers/bcma/driver_chipcommon_nflash.c
 @@ -5,15 +5,40 @@
   * Licensed under the GNU/GPL. See COPYING for details.
   */
  
++#include "bcma_private.h"
++
 +#include <linux/platform_device.h>
  #include <linux/bcma/bcma.h>
 -#include <linux/bcma/bcma_driver_chipcommon.h>
 -#include <linux/delay.h>
  
- #include "bcma_private.h"
+-#include "bcma_private.h"
 +struct platform_device bcma_nflash_dev = {
 +      .name           = "bcma_nflash",
 +      .num_resources  = 0,
 +};
-+
  /* Initialize NAND flash access */
  int bcma_nflash_init(struct bcma_drv_cc *cc)
  {
 +      struct bcma_bus *bus = cc->core->bus;
 +
 +      if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
-+          cc->core->id.rev != 0x38) {
++          cc->core->id.rev != 38) {
 +              bcma_err(bus, "NAND flash on unsupported board!\n");
 +              return -ENOTSUPP;
 +      }
  
  void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
  {
-@@ -76,7 +77,10 @@ static void bcma_pmu_resources_init(stru
+@@ -55,6 +56,109 @@ void bcma_chipco_regctl_maskset(struct b
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
++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 BCMA_CHIP_ID_BCM43142:
++              if (xtalfreq == 0)
++                      xtalfreq = 20000;
++              bcma_pmu2_pll_init0(cc, xtalfreq);
++              break;
++      }
++}
++
+ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
+ {
+       struct bcma_bus *bus = cc->core->bus;
+@@ -65,6 +169,25 @@ static void bcma_pmu_resources_init(stru
+               min_msk = 0x200D;
+               max_msk = 0xFFFF;
+               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:
+               bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n",
+                          bus->chipinfo.id);
+@@ -76,7 +199,10 @@ static void bcma_pmu_resources_init(stru
        if (max_msk)
                bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
  
        mdelay(2);
  }
  
-@@ -101,7 +105,7 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
+@@ -101,7 +227,7 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
        bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
  }
  
  {
        struct bcma_bus *bus = cc->core->bus;
  
-@@ -141,7 +145,7 @@ void bcma_pmu_workarounds(struct bcma_dr
+@@ -141,7 +267,7 @@ void bcma_pmu_workarounds(struct bcma_dr
        }
  }
  
  {
        u32 pmucap;
  
-@@ -150,7 +154,10 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+@@ -150,7 +276,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);
        if (cc->pmu.rev == 1)
                bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
                              ~BCMA_CC_PMU_CTL_NOILPONW);
-@@ -162,24 +169,40 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+@@ -158,28 +287,45 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+               bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+                            BCMA_CC_PMU_CTL_NOILPONW);
++      bcma_pmu_pll_init(cc);
+       bcma_pmu_resources_init(cc);
        bcma_pmu_workarounds(cc);
  }
  
        default:
                bcma_warn(bus, "No ALP clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
                          bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
-@@ -190,7 +213,7 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
+@@ -190,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.
   */
  {
        u32 tmp, div, ndiv, p1, p2, fc;
        struct bcma_bus *bus = cc->core->bus;
-@@ -219,14 +242,14 @@ static u32 bcma_pmu_clock(struct bcma_dr
+@@ -219,14 +365,14 @@ static u32 bcma_pmu_clock(struct bcma_dr
        ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
  
        /* Do calculation in Mhz */
  {
        u32 tmp, ndiv, p1div, p2div;
        u32 clock;
-@@ -257,7 +280,7 @@ static u32 bcma_pmu_clock_bcm4706(struct
+@@ -257,7 +403,7 @@ static u32 bcma_pmu_clock_bcm4706(struct
  }
  
  /* query bus clock frequency for PMU-enabled chipcommon */
 -u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
-+static u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
++u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
  {
        struct bcma_bus *bus = cc->core->bus;
  
-@@ -265,40 +288,42 @@ u32 bcma_pmu_get_clockcontrol(struct bcm
+@@ -265,40 +411,43 @@ u32 bcma_pmu_get_clockcontrol(struct bcm
        case BCMA_CHIP_ID_BCM4716:
        case BCMA_CHIP_ID_BCM4748:
        case BCMA_CHIP_ID_BCM47162:
        }
        return BCMA_CC_PMU_HT_CLOCK;
  }
++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)
                                                BCMA_CC_PMU4706_MAINPLL_PLL0,
                                                BCMA_CC_PMU5_MAINPLL_CPU);
                case BCMA_CHIP_ID_BCM5356:
-@@ -313,10 +338,11 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
+@@ -313,10 +462,11 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
                        break;
                }
  
  }
  
  static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
-@@ -362,7 +388,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -362,7 +512,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
                bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
  
                break;
  
        case BCMA_CHIP_ID_BCM4331:
-@@ -383,7 +409,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -383,7 +533,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
                                                     0x03000a08);
                }
                break;
  
        case BCMA_CHIP_ID_BCM43224:
-@@ -416,7 +442,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -416,7 +566,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
                                                     0x88888815);
                }
                break;
  
        case BCMA_CHIP_ID_BCM4716:
-@@ -450,7 +476,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -450,7 +600,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                                                     0x88888815);
                }
  
                break;
  
        case BCMA_CHIP_ID_BCM43227:
-@@ -486,7 +512,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -486,7 +636,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
                                                     0x88888815);
                }
   * Licensed under the GNU/GPL. See COPYING for details.
   */
  
++#include "bcma_private.h"
++
 +#include <linux/platform_device.h>
  #include <linux/bcma/bcma.h>
 -#include <linux/bcma/bcma_driver_chipcommon.h>
 -#include <linux/delay.h>
  
- #include "bcma_private.h"
+-#include "bcma_private.h"
 +static struct resource bcma_sflash_resource = {
 +      .name   = "bcma_sflash",
 +      .start  = BCMA_SOC_FLASH2,
 +      u16 numblocks;
 +};
 +
-+static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
 +      { "M25P20", 0x11, 0x10000, 4, },
 +      { "M25P40", 0x12, 0x10000, 8, },
 +
 +      { 0 },
 +};
 +
-+static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
 +      { "SST25WF512", 1, 0x1000, 16, },
 +      { "SST25VF512", 0x48, 0x1000, 16, },
 +      { "SST25WF010", 2, 0x1000, 32, },
 +      { 0 },
 +};
 +
-+static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
 +      { "AT45DB011", 0xc, 256, 512, },
 +      { "AT45DB021", 0x14, 256, 1024, },
 +      { "AT45DB041", 0x1c, 256, 2048, },
 +      }
 +      bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
 +}
-+
  /* Initialize serial flash access */
  int bcma_sflash_init(struct bcma_drv_cc *cc)
  {
 -      bcma_err(cc->core->bus, "Serial flash support is broken\n");
 +      struct bcma_bus *bus = cc->core->bus;
 +      struct bcma_sflash *sflash = &cc->sflash;
-+      struct bcma_sflash_tbl_e *e;
++      const struct bcma_sflash_tbl_e *e;
 +      u32 id, id2;
 +
 +      switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
  }
 --- /dev/null
 +++ b/drivers/bcma/driver_gpio.c
-@@ -0,0 +1,98 @@
+@@ -0,0 +1,114 @@
 +/*
 + * Broadcom specific AMBA
 + * GPIO driver
 +      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->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
 +
 +      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
-@@ -74,11 +74,16 @@ static u32 bcma_core_mips_irqflag(struct
+@@ -14,11 +14,33 @@
+ #include <linux/bcma/bcma.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+ #include <linux/time.h>
++static const char * const part_probes[] = { "bcm47xxpart", NULL };
++
++static struct physmap_flash_data bcma_pflash_data = {
++      .part_probe_types       = part_probes,
++};
++
++static struct resource bcma_pflash_resource = {
++      .name   = "bcma_pflash",
++      .flags  = IORESOURCE_MEM,
++};
++
++struct platform_device bcma_pflash_dev = {
++      .name           = "physmap-flash",
++      .dev            = {
++              .platform_data  = &bcma_pflash_data,
++      },
++      .resource       = &bcma_pflash_resource,
++      .num_resources  = 1,
++};
++
+ /* The 47162a0 hangs when reading MIPS DMP registers registers */
+ static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+ {
+@@ -74,28 +96,41 @@ static u32 bcma_core_mips_irqflag(struct
                return dev->core_index;
        flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
  
 + * If disabled, 5 is returned.
 + * If not supported, 6 is returned.
   */
- unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+-unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
  {
-@@ -87,13 +92,15 @@ unsigned int bcma_core_mips_irq(struct b
+       struct bcma_device *mdev = dev->bus->drv_mips.core;
+       u32 irqflag;
        unsigned int irq;
  
        irqflag = bcma_core_mips_irqflag(dev);
  
 -      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_mips_irq);
++EXPORT_SYMBOL(bcma_core_irq);
  
-@@ -114,8 +121,8 @@ static void bcma_core_mips_set_irq(struc
+ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+ {
+@@ -114,8 +149,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));
  
        /* assign the new one */
        if (irq == 0) {
-@@ -123,9 +130,9 @@ static void bcma_core_mips_set_irq(struc
+@@ -123,9 +158,9 @@ static void bcma_core_mips_set_irq(struc
                            bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
                            (1 << irqflag));
        } else {
                        struct bcma_device *core;
  
                        /* backplane irq line is in use, find out who uses
-@@ -133,7 +140,7 @@ static void bcma_core_mips_set_irq(struc
+@@ -133,7 +168,7 @@ static void bcma_core_mips_set_irq(struc
                         */
                        list_for_each_entry(core, &bus->cores, list) {
                                if ((1 << bcma_core_mips_irqflag(core)) ==
                                        bcma_core_mips_set_irq(core, 0);
                                        break;
                                }
-@@ -143,15 +150,31 @@ static void bcma_core_mips_set_irq(struc
+@@ -143,15 +178,31 @@ static void bcma_core_mips_set_irq(struc
                             1 << irqflag);
        }
  
        for (i = 0; i <= 6; i++)
                printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
        printk("\n");
-@@ -171,7 +194,7 @@ u32 bcma_cpu_clock(struct bcma_drv_mips
+@@ -171,7 +222,7 @@ u32 bcma_cpu_clock(struct bcma_drv_mips
        struct bcma_bus *bus = mcore->core->bus;
  
        if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
  
        bcma_err(bus, "No PMU available, need this to get the cpu clock\n");
        return 0;
-@@ -181,85 +204,109 @@ EXPORT_SYMBOL(bcma_cpu_clock);
+@@ -181,85 +232,143 @@ EXPORT_SYMBOL(bcma_cpu_clock);
  static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
  {
        struct bcma_bus *bus = mcore->core->bus;
 +      struct bcma_drv_cc *cc = &bus->drv_cc;
++      struct bcma_pflash *pflash = &cc->pflash;
  
 -      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
 +      switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
                bcma_debug(bus, "Found parallel flash\n");
 -              bus->drv_cc.pflash.window = 0x1c000000;
 -              bus->drv_cc.pflash.window_size = 0x02000000;
-+              cc->pflash.present = true;
-+              cc->pflash.window = BCMA_SOC_FLASH2;
-+              cc->pflash.window_size = BCMA_SOC_FLASH2_SZ;
++              pflash->present = true;
++              pflash->window = BCMA_SOC_FLASH2;
++              pflash->window_size = BCMA_SOC_FLASH2_SZ;
  
 -              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
 +              if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
                     BCMA_CC_FLASH_CFG_DS) == 0)
 -                      bus->drv_cc.pflash.buswidth = 1;
-+                      cc->pflash.buswidth = 1;
++                      pflash->buswidth = 1;
                else
 -                      bus->drv_cc.pflash.buswidth = 2;
-+                      cc->pflash.buswidth = 2;
++                      pflash->buswidth = 2;
++
++              bcma_pflash_data.width = pflash->buswidth;
++              bcma_pflash_resource.start = pflash->window;
++              bcma_pflash_resource.end = pflash->window + pflash->window_size;
++
                break;
        default:
                bcma_err(bus, "Flash type not supported\n");
 +      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");
++      }
++}
++
  void bcma_core_mips_init(struct bcma_drv_mips *mcore)
  {
        struct bcma_bus *bus;
 -                      break;
 +      bcma_core_mips_early_init(mcore);
 +
++      bcma_fix_i2s_irqflag(bus);
++
 +      switch (bus->chipinfo.id) {
 +      case BCMA_CHIP_ID_BCM4716:
 +      case BCMA_CHIP_ID_BCM4748:
 +              break;
 +      default:
 +              list_for_each_entry(core, &bus->cores, list) {
-+                      core->irq = bcma_core_mips_irq(core) + 2;
++                      core->irq = bcma_core_irq(core);
                }
 +              bcma_err(bus,
 +                       "Unknown device (0x%x) found, can not configure IRQs\n",
        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
+@@ -99,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 {
+@@ -124,11 +119,9 @@ static int bcma_extpci_read_config(struc
+                       goto out;
+               if (mips_busprobe32(val, mmio)) {
+-                      val = 0xffffffff;
++                      val = 0xFFFFFFFF;
+                       goto unmap;
+               }
+-
+-              val = readl(mmio);
+       }
+       val >>= (8 * (off & 3));
+@@ -156,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;
+@@ -164,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);
+@@ -185,19 +184,17 @@ static int bcma_extpci_write_config(stru
+                       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;
+@@ -205,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);
+@@ -282,7 +280,7 @@ static u8 __devinit bcma_find_pci_capabi
+       /* 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 */
+@@ -396,12 +394,19 @@ void __devinit bcma_core_pci_hostmode_in
  
        bcma_info(bus, "PCIEcore in host mode found\n");
  
        pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
        if (!pc_host)  {
                bcma_err(bus, "can not allocate memory");
-@@ -425,9 +425,9 @@ void __devinit bcma_core_pci_hostmode_in
+               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;
+@@ -425,9 +430,9 @@ void __devinit bcma_core_pci_hostmode_in
        pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
  
        /* Reset RC */
 +      usleep_range(3000, 5000);
        pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
 -      udelay(1000);
-+      usleep_range(1000, 2000);
++      msleep(50);
        pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
                        BCMA_CORE_PCI_CTL_RST_OE);
  
-@@ -452,6 +452,8 @@ void __devinit bcma_core_pci_hostmode_in
+@@ -452,6 +457,8 @@ void __devinit bcma_core_pci_hostmode_in
                        pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
                        pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
                                                    BCMA_SOC_PCI_MEM_SZ - 1;
                        pci_membase_1G = BCMA_SOC_PCIE_DMA_H32;
                        pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
                                        tmp | BCMA_SOC_PCI_MEM);
-@@ -459,6 +461,8 @@ void __devinit bcma_core_pci_hostmode_in
+@@ -459,6 +466,8 @@ void __devinit bcma_core_pci_hostmode_in
                        pc_host->mem_resource.start = BCMA_SOC_PCI1_MEM;
                        pc_host->mem_resource.end = BCMA_SOC_PCI1_MEM +
                                                    BCMA_SOC_PCI_MEM_SZ - 1;
                        pci_membase_1G = BCMA_SOC_PCIE1_DMA_H32;
                        pc_host->host_cfg_addr = BCMA_SOC_PCI1_CFG;
                        pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
-@@ -481,7 +485,7 @@ void __devinit bcma_core_pci_hostmode_in
+@@ -481,10 +490,21 @@ void __devinit bcma_core_pci_hostmode_in
         * before issuing configuration requests to PCI Express
         * devices.
         */
  
        bcma_core_pci_enable_crs(pc);
  
-@@ -501,7 +505,7 @@ void __devinit bcma_core_pci_hostmode_in
++      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));
+@@ -501,7 +521,7 @@ void __devinit bcma_core_pci_hostmode_in
        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. */
        register_pci_controller(&pc_host->pci_controller);
        return;
  }
-@@ -534,7 +538,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_
+@@ -534,7 +554,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_
  static void bcma_core_pci_fixup_addresses(struct pci_dev *dev)
  {
        struct resource *res;
  
        if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
                /* This is not a device on the PCI-core bridge. */
-@@ -547,8 +551,12 @@ static void bcma_core_pci_fixup_addresse
+@@ -547,8 +567,12 @@ static void bcma_core_pci_fixup_addresse
  
        for (pos = 0; pos < 6; pos++) {
                res = &dev->resource[pos];
        }
  }
  DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_addresses);
+@@ -569,7 +593,7 @@ int bcma_core_pci_plat_dev_init(struct p
+       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;
+@@ -588,6 +612,6 @@ int bcma_core_pci_pcibios_map_irq(const
+       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
 +++ b/drivers/bcma/host_pci.c
 @@ -77,8 +77,8 @@ static void bcma_host_pci_write32(struct
  
  static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
-@@ -272,6 +273,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_
+@@ -272,7 +273,9 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
 +      { 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, },
+ };
 --- a/drivers/bcma/host_soc.c
 +++ b/drivers/bcma/host_soc.c
 @@ -143,7 +143,7 @@ static void bcma_host_soc_awrite32(struc
  #include <linux/bcma/bcma.h>
  #include <linux/slab.h>
  
-@@ -80,6 +81,18 @@ struct bcma_device *bcma_find_core(struc
+@@ -80,6 +81,37 @@ struct bcma_device *bcma_find_core(struc
  }
  EXPORT_SYMBOL_GPL(bcma_find_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)
  {
        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
-@@ -136,6 +149,33 @@ static int bcma_register_cores(struct bc
+@@ -107,6 +139,11 @@ static int bcma_register_cores(struct bc
+                       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", bus->num, dev_id);
+@@ -136,6 +173,41 @@ static int bcma_register_cores(struct bc
                dev_id++;
        }
  
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      if (bus->drv_cc.pflash.present) {
++              err = platform_device_register(&bcma_pflash_dev);
++              if (err)
++                      bcma_err(bus, "Error registering parallel flash\n");
++      }
++#endif
++
 +#ifdef CONFIG_BCMA_SFLASH
 +      if (bus->drv_cc.sflash.present) {
 +              err = platform_device_register(&bcma_sflash_dev);
        return 0;
  }
  
-@@ -148,6 +188,8 @@ static void bcma_unregister_cores(struct
+@@ -148,6 +220,8 @@ static void bcma_unregister_cores(struct
                if (core->dev_registered)
                        device_unregister(&core->dev);
        }
  }
  
  int __devinit bcma_bus_register(struct bcma_bus *bus)
-@@ -166,6 +208,20 @@ int __devinit bcma_bus_register(struct b
+@@ -166,6 +240,20 @@ int __devinit bcma_bus_register(struct b
                return -1;
        }
  
        /* Init CC core */
        core = bcma_find_core(bus, bcma_cc_core_id(bus));
        if (core) {
-@@ -181,10 +237,17 @@ int __devinit bcma_bus_register(struct b
+@@ -181,10 +269,17 @@ int __devinit bcma_bus_register(struct b
        }
  
        /* Init PCIE core */
 -      core = bcma_find_core(bus, BCMA_CORE_PCIE);
 +      core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 0);
-+      if (core) {
+       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]);
 +      }
 +
 +      /* Init PCIE core */
 +      core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1);
-       if (core) {
--              bus->drv_pci.core = core;
--              bcma_core_pci_init(&bus->drv_pci);
++      if (core) {
 +              bus->drv_pci[1].core = core;
 +              bcma_core_pci_init(&bus->drv_pci[1]);
        }
  
        /* Init GBIT MAC COMMON core */
-@@ -194,13 +257,6 @@ int __devinit bcma_bus_register(struct b
+@@ -194,13 +289,6 @@ int __devinit bcma_bus_register(struct b
                bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
        }
  
        /* Register found cores */
        bcma_register_cores(bus);
  
-@@ -211,7 +267,17 @@ int __devinit bcma_bus_register(struct b
+@@ -211,7 +299,24 @@ int __devinit bcma_bus_register(struct b
  
  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);
  }
  
  int __init bcma_bus_early_register(struct bcma_bus *bus,
-@@ -248,18 +314,18 @@ int __init bcma_bus_early_register(struc
+@@ -248,18 +353,18 @@ int __init bcma_bus_early_register(struc
                return -1;
        }
  
        }
  
        bcma_info(bus, "Early bus registered\n");
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -84,6 +84,8 @@ static const struct bcma_device_id_name
+       { 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" },
+ };
+@@ -137,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))
+@@ -159,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);
+@@ -175,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) {
+@@ -189,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))
+@@ -199,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;
 --- a/drivers/bcma/sprom.c
 +++ b/drivers/bcma/sprom.c
-@@ -507,7 +507,9 @@ static bool bcma_sprom_onchip_available(
+@@ -72,12 +72,12 @@ fail:
+  * R/W ops.
+  **************************************************/
+-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));
+ }
+ /**************************************************
+@@ -124,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;
+@@ -154,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;
+ }
+@@ -208,15 +212,13 @@ static void bcma_sprom_extract_r8(struct
+       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;
+-
+       for (i = 0; i < 3; i++) {
+               v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
+               *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
+       }
+       SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
++      SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
+       SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
+            SSB_SPROM4_TXPID2G0_SHIFT);
+@@ -501,13 +503,15 @@ static bool bcma_sprom_onchip_available(
+       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;
                present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
                break;
        default:
-@@ -593,8 +595,11 @@ int bcma_sprom_get(struct bcma_bus *bus)
+@@ -547,7 +551,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ {
+       u16 offset = BCMA_CC_SPROM;
+       u16 *sprom;
+-      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;
+@@ -576,29 +582,37 @@ int bcma_sprom_get(struct bcma_bus *bus)
+               }
+       }
+-      sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+-                      GFP_KERNEL);
+-      if (!sprom)
+-              return -ENOMEM;
+-
+       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, false);
+       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;
++
++              kfree(sprom);
++      }
+       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);
  
-       err = bcma_sprom_valid(sprom);
+-      err = bcma_sprom_valid(sprom);
 -      if (err)
+-              goto out;
+-
+-      bcma_sprom_extract_r8(bus, sprom);
 +      if (err) {
-+              bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
++              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);
-               goto out;
++      } else {
++              bcma_sprom_extract_r8(bus, sprom);
++              kfree(sprom);
 +      }
  
-       bcma_sprom_extract_r8(bus, sprom);
+-out:
+-      kfree(sprom);
+       return err;
+ }
 --- a/include/linux/bcma/bcma.h
 +++ b/include/linux/bcma/bcma.h
 @@ -10,7 +10,7 @@
  
  struct bcma_device;
  struct bcma_bus;
-@@ -134,6 +134,7 @@ struct bcma_host_ops {
+@@ -134,12 +134,17 @@ 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_ARM_CR4             0x83e
++#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
-@@ -157,6 +158,7 @@ struct bcma_host_ops {
+ /* 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
+@@ -157,6 +162,7 @@ struct bcma_host_ops {
  
  /* Chip IDs of SoCs */
  #define BCMA_CHIP_ID_BCM4706  0x5300
  #define BCMA_CHIP_ID_BCM4716  0x4716
  #define  BCMA_PKG_ID_BCM4716  8
  #define  BCMA_PKG_ID_BCM4717  9
-@@ -166,7 +168,11 @@ struct bcma_host_ops {
+@@ -166,7 +172,65 @@ struct bcma_host_ops {
  #define BCMA_CHIP_ID_BCM4749  0x4749
  #define BCMA_CHIP_ID_BCM5356  0x5356
  #define BCMA_CHIP_ID_BCM5357  0x5357
 +#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;
-@@ -251,7 +257,7 @@ struct bcma_bus {
+@@ -251,7 +315,7 @@ struct bcma_bus {
        u8 num;
  
        struct bcma_drv_cc drv_cc;
        struct bcma_drv_mips drv_mips;
        struct bcma_drv_gmac_cmn drv_gmac_cmn;
  
-@@ -345,6 +351,7 @@ extern void bcma_core_set_clockmode(stru
+@@ -345,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);
  /** 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      /* NAND flash */
++#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
 @@ -100,6 +103,8 @@
  #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_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 */
-@@ -325,6 +356,60 @@
+@@ -299,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 */
+@@ -324,7 +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 */
 +/* NAND flash MLC controller registers (corerev >= 38) */
 +#define BCMA_CC_NAND_REVISION         0x0C00
  
  /* Divider allocation in 4716/47162/5356 */
  #define BCMA_CC_PMU5_MAINPLL_CPU      1
-@@ -415,6 +500,13 @@
+@@ -350,6 +442,23 @@
+ #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
+ /* HT clock for systems with PMU-enabled chipcommon */
+@@ -415,6 +524,44 @@
  /* 4313 Chip specific ChipControl register bits */
  #define BCMA_CCTRL_4313_12MA_LED_DRIVE                0x00000007      /* 12 mA drive strengh for later 4313 */
  
 +#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)
   */
-@@ -425,11 +517,35 @@ struct bcma_chipcommon_pmu {
+@@ -425,11 +572,36 @@ struct bcma_chipcommon_pmu {
  
  #ifdef CONFIG_BCMA_DRIVER_MIPS
  struct bcma_pflash {
 +      u32 size;
 +
 +      struct mtd_info *mtd;
++      void *priv;
 +};
 +#endif
 +
  struct bcma_serial_port {
        void *regs;
        unsigned long clockspeed;
-@@ -445,15 +561,30 @@ struct bcma_drv_cc {
+@@ -445,15 +617,30 @@ struct bcma_drv_cc {
        u32 capabilities;
        u32 capabilities_ext;
        u8 setup_done:1;
  };
  
  /* Register access */
-@@ -470,14 +601,16 @@ struct bcma_drv_cc {
+@@ -470,14 +657,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);
  
  void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value);
  
-@@ -490,9 +623,12 @@ u32 bcma_chipco_gpio_outen(struct bcma_d
+@@ -490,9 +679,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);
  
  extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
                                  u32 value);
+@@ -504,4 +696,6 @@ 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);
++extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc);
++
+ #endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- a/include/linux/bcma/bcma_driver_mips.h
 +++ b/include/linux/bcma/bcma_driver_mips.h
-@@ -35,13 +35,15 @@ struct bcma_device;
+@@ -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;
  #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
+@@ -179,6 +179,8 @@ struct pci_dev;
+ #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
 --- a/include/linux/bcma/bcma_regs.h
 +++ b/include/linux/bcma/bcma_regs.h
 @@ -11,11 +11,13 @@
index d44c812..54ea356 100644 (file)
@@ -30,7 +30,7 @@
                                            ARRAY_SIZE(wgt634u_devices));
 --- a/drivers/ssb/Kconfig
 +++ b/drivers/ssb/Kconfig
-@@ -136,6 +136,11 @@ config SSB_DRIVER_MIPS
+@@ -136,10 +136,15 @@ config SSB_DRIVER_MIPS
  
          If unsure, say N
  
  # Assumption: We are on embedded, if we compile the MIPS core.
  config SSB_EMBEDDED
        bool
+-      depends on SSB_DRIVER_MIPS
++      depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
+       default y
+ config SSB_DRIVER_EXTIF
 @@ -160,4 +165,12 @@ config SSB_DRIVER_GIGE
  
          If unsure, say N
  
  #include "ssb_private.h"
  
-@@ -280,10 +282,76 @@ static void calc_fast_powerup_delay(stru
+@@ -280,13 +282,79 @@ static void calc_fast_powerup_delay(stru
        cc->fast_pwrup_delay = tmp;
  }
  
 +
        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_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);
                                /* Turn off UART clock before switching clocksource. */
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
-@@ -346,6 +346,8 @@ static void ssb_pmu_pll_init(struct ssb_
+@@ -110,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) {
+@@ -138,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);
+@@ -249,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) {
+@@ -275,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);
+@@ -346,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",
-@@ -434,6 +436,7 @@ static void ssb_pmu_resources_init(struc
+-              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);
+       }
+ }
+@@ -434,6 +435,7 @@ static void ssb_pmu_resources_init(struc
                 min_msk = 0xCBB;
                 break;
        case 0x4322:
                /* We keep the default settings:
                 * min_msk = 0xCBB
                 * max_msk = 0x7FFFF
-@@ -615,6 +618,33 @@ void ssb_pmu_set_ldo_paref(struct ssb_ch
+@@ -469,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) {
+@@ -523,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,
+@@ -615,6 +616,32 @@ void ssb_pmu_set_ldo_paref(struct ssb_ch
  EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
  EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
  
 +      case 0x5354:
 +              ssb_pmu_get_alp_clock_clk0(cc);
 +      default:
-+              ssb_printk(KERN_ERR PFX
-+                         "ERROR: PMU alp clock unknown for device %04X\n",
-+                         bus->chip_id);
++              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;
-@@ -645,3 +675,32 @@ u32 ssb_pmu_get_controlclock(struct ssb_
+@@ -624,9 +651,8 @@ u32 ssb_pmu_get_cpu_clock(struct ssb_chi
+               /* 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);
++              ssb_err("ERROR: PMU cpu clock unknown for device %04X\n",
++                      bus->chip_id);
+               return 0;
+       }
+ }
+@@ -639,9 +665,52 @@ u32 ssb_pmu_get_controlclock(struct ssb_
+       case 0x5354:
+               return 120000000;
+       default:
+-              ssb_printk(KERN_ERR PFX
+-                         "ERROR: PMU controlclock unknown for device %04X\n",
+-                         bus->chip_id);
++              ssb_err("ERROR: PMU controlclock unknown for device %04X\n",
++                      bus->chip_id);
                return 0;
        }
  }
 +              pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
 +              break;
 +      case 43222:
-+              /* TODO: BCM43222 requires updating PLLs too */
-+              return;
++              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",
 +EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate);
 --- /dev/null
 +++ b/drivers/ssb/driver_chipcommon_sflash.c
-@@ -0,0 +1,18 @@
+@@ -0,0 +1,166 @@
 +/*
 + * Sonics Silicon Backplane
 + * ChipCommon serial flash interface
 +
 +#include "ssb_private.h"
 +
++static struct resource ssb_sflash_resource = {
++      .name   = "ssb_sflash",
++      .start  = SSB_FLASH2,
++      .end    = 0,
++      .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
++};
++
++struct platform_device ssb_sflash_dev = {
++      .name           = "ssb_sflash",
++      .resource       = &ssb_sflash_resource,
++      .num_resources  = 1,
++};
++
++struct ssb_sflash_tbl_e {
++      char *name;
++      u32 id;
++      u32 blocksize;
++      u16 numblocks;
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
++      { "M25P20", 0x11, 0x10000, 4, },
++      { "M25P40", 0x12, 0x10000, 8, },
++
++      { "M25P16", 0x14, 0x10000, 32, },
++      { "M25P32", 0x15, 0x10000, 64, },
++      { "M25P64", 0x16, 0x10000, 128, },
++      { "M25FL128", 0x17, 0x10000, 256, },
++      { 0 },
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
++      { "SST25WF512", 1, 0x1000, 16, },
++      { "SST25VF512", 0x48, 0x1000, 16, },
++      { "SST25WF010", 2, 0x1000, 32, },
++      { "SST25VF010", 0x49, 0x1000, 32, },
++      { "SST25WF020", 3, 0x1000, 64, },
++      { "SST25VF020", 0x43, 0x1000, 64, },
++      { "SST25WF040", 4, 0x1000, 128, },
++      { "SST25VF040", 0x44, 0x1000, 128, },
++      { "SST25VF040B", 0x8d, 0x1000, 128, },
++      { "SST25WF080", 5, 0x1000, 256, },
++      { "SST25VF080B", 0x8e, 0x1000, 256, },
++      { "SST25VF016", 0x41, 0x1000, 512, },
++      { "SST25VF032", 0x4a, 0x1000, 1024, },
++      { "SST25VF064", 0x4b, 0x1000, 2048, },
++      { 0 },
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
++      { "AT45DB011", 0xc, 256, 512, },
++      { "AT45DB021", 0x14, 256, 1024, },
++      { "AT45DB041", 0x1c, 256, 2048, },
++      { "AT45DB081", 0x24, 256, 4096, },
++      { "AT45DB161", 0x2c, 512, 4096, },
++      { "AT45DB321", 0x34, 512, 8192, },
++      { "AT45DB642", 0x3c, 1024, 8192, },
++      { 0 },
++};
++
++static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
++{
++      int i;
++      chipco_write32(cc, SSB_CHIPCO_FLASHCTL,
++                     SSB_CHIPCO_FLASHCTL_START | opcode);
++      for (i = 0; i < 1000; i++) {
++              if (!(chipco_read32(cc, SSB_CHIPCO_FLASHCTL) &
++                    SSB_CHIPCO_FLASHCTL_BUSY))
++                      return;
++              cpu_relax();
++      }
++      pr_err("SFLASH control command failed (timeout)!\n");
++}
++
 +/* Initialize serial flash access */
 +int ssb_sflash_init(struct ssb_chipcommon *cc)
 +{
++      struct ssb_sflash *sflash = &cc->dev->bus->mipscore.sflash;
++      const struct ssb_sflash_tbl_e *e;
++      u32 id, id2;
++
++      switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++      case SSB_CHIPCO_FLASHT_STSER:
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_DP);
++
++              chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 0);
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
++              id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
++
++              chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 1);
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
++              id2 = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
++
++              switch (id) {
++              case 0xbf:
++                      for (e = ssb_sflash_sst_tbl; e->name; e++) {
++                              if (e->id == id2)
++                                      break;
++                      }
++                      break;
++              case 0x13:
++                      return -ENOTSUPP;
++              default:
++                      for (e = ssb_sflash_st_tbl; e->name; e++) {
++                              if (e->id == id)
++                                      break;
++                      }
++                      break;
++              }
++              if (!e->name) {
++                      pr_err("Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n",
++                             id, id2);
++                      return -ENOTSUPP;
++              }
++
++              break;
++      case SSB_CHIPCO_FLASHT_ATSER:
++              ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
++              id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA) & 0x3c;
++
++              for (e = ssb_sflash_at_tbl; e->name; e++) {
++                      if (e->id == id)
++                              break;
++              }
++              if (!e->name) {
++                      pr_err("Unsupported Atmel serial flash (id: 0x%X)\n",
++                             id);
++                      return -ENOTSUPP;
++              }
++
++              break;
++      default:
++              pr_err("Unsupported flash type\n");
++              return -ENOTSUPP;
++      }
++
++      sflash->window = SSB_FLASH2;
++      sflash->blocksize = e->blocksize;
++      sflash->numblocks = e->numblocks;
++      sflash->size = sflash->blocksize * sflash->numblocks;
++      sflash->present = true;
++
++      pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
++              e->name, e->blocksize, e->numblocks);
++
++      /* Prepare platform device, but don't register it yet. It's too early,
++       * malloc (required by device_private_init) is not available yet. */
++      ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
++                                       sflash->size;
++      ssb_sflash_dev.dev.platform_data = sflash;
++
 +      pr_err("Serial flash support is not implemented yet!\n");
 +
 +      return -ENOTSUPP;
  }
 --- /dev/null
 +++ b/drivers/ssb/driver_gpio.c
-@@ -0,0 +1,176 @@
+@@ -0,0 +1,210 @@
 +/*
 + * Sonics Silicon Backplane
 + * GPIO driver
 +      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->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
 +      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->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
 +
 +      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
-@@ -178,9 +178,9 @@ static void ssb_mips_serial_init(struct
+@@ -10,6 +10,7 @@
+ #include <linux/ssb/ssb.h>
++#include <linux/mtd/physmap.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+@@ -17,6 +18,25 @@
+ #include "ssb_private.h"
++static const char * const part_probes[] = { "bcm47xxpart", NULL };
++
++static struct physmap_flash_data ssb_pflash_data = {
++      .part_probe_types       = part_probes,
++};
++
++static struct resource ssb_pflash_resource = {
++      .name   = "ssb_pflash",
++      .flags  = IORESOURCE_MEM,
++};
++
++struct platform_device ssb_pflash_dev = {
++      .name           = "physmap-flash",
++      .dev            = {
++              .platform_data  = &ssb_pflash_data,
++      },
++      .resource       = &ssb_pflash_resource,
++      .num_resources  = 1,
++};
+ static inline u32 mips_read32(struct ssb_mipscore *mcore,
+                             u16 offset)
+@@ -147,21 +167,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 +199,9 @@ static void ssb_mips_serial_init(struct
  {
        struct ssb_bus *bus = mcore->dev->bus;
  
                mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
        else
                mcore->nr_serial_ports = 0;
-@@ -191,10 +191,11 @@ static void ssb_mips_flash_detect(struct
+@@ -189,32 +210,43 @@ static void ssb_mips_serial_init(struct
+ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
+ {
        struct ssb_bus *bus = mcore->dev->bus;
++      struct ssb_pflash *pflash = &mcore->pflash;
  
        /* When there is no chipcommon on the bus there is 4MB flash */
 -      if (!bus->chipco.dev) {
 -              mcore->flash_buswidth = 2;
 -              mcore->flash_window = SSB_FLASH1;
 -              mcore->flash_window_size = SSB_FLASH1_SZ;
+-              return;
 +      if (!ssb_chipco_available(&bus->chipco)) {
-+              mcore->pflash.present = true;
-+              mcore->pflash.buswidth = 2;
-+              mcore->pflash.window = SSB_FLASH1;
-+              mcore->pflash.window_size = SSB_FLASH1_SZ;
-               return;
++              pflash->present = true;
++              pflash->buswidth = 2;
++              pflash->window = SSB_FLASH1;
++              pflash->window_size = SSB_FLASH1_SZ;
++              goto ssb_pflash;
        }
  
-@@ -202,17 +203,19 @@ static void ssb_mips_flash_detect(struct
+       /* There is ChipCommon, so use it to read info about flash */
        switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
        case SSB_CHIPCO_FLASHT_STSER:
        case SSB_CHIPCO_FLASHT_ATSER:
                pr_debug("Found parallel flash\n");
 -              mcore->flash_window = SSB_FLASH2;
 -              mcore->flash_window_size = SSB_FLASH2_SZ;
-+              mcore->pflash.present = true;
-+              mcore->pflash.window = SSB_FLASH2;
-+              mcore->pflash.window_size = SSB_FLASH2_SZ;
++              pflash->present = true;
++              pflash->window = SSB_FLASH2;
++              pflash->window_size = SSB_FLASH2_SZ;
                if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
                               & SSB_CHIPCO_CFG_DS16) == 0)
 -                      mcore->flash_buswidth = 1;
-+                      mcore->pflash.buswidth = 1;
++                      pflash->buswidth = 1;
                else
 -                      mcore->flash_buswidth = 2;
-+                      mcore->pflash.buswidth = 2;
++                      pflash->buswidth = 2;
                break;
        }
++
++ssb_pflash:
++      if (pflash->present) {
++              ssb_pflash_data.width = pflash->buswidth;
++              ssb_pflash_resource.start = pflash->window;
++              ssb_pflash_resource.end = pflash->window + pflash->window_size;
++      }
  }
-@@ -225,9 +228,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
+ u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
+@@ -225,9 +257,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
        if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)
                return ssb_pmu_get_cpu_clock(&bus->chipco);
  
                ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
        } else
                return 0;
-@@ -263,9 +266,9 @@ void ssb_mipscore_init(struct ssb_mipsco
+@@ -255,7 +287,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);
+@@ -263,9 +295,9 @@ void ssb_mipscore_init(struct ssb_mipsco
                hz = 100000000;
        ns = 1000000000 / hz;
  
                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 */
+@@ -303,7 +335,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 @@
  #include <linux/ssb/ssb.h>
  #include <linux/ssb/ssb_embedded.h>
  #include <linux/ssb/ssb_driver_pci.h>
-@@ -32,6 +34,39 @@ int ssb_watchdog_timer_set(struct ssb_bu
+@@ -32,6 +34,38 @@ int ssb_watchdog_timer_set(struct ssb_bu
  }
  EXPORT_SYMBOL(ssb_watchdog_timer_set);
  
 +                                           bus->busnumber, &wdt,
 +                                           sizeof(wdt));
 +      if (IS_ERR(pdev)) {
-+              ssb_dprintk(KERN_INFO PFX
-+                          "can not register watchdog device, err: %li\n",
-+                          PTR_ERR(pdev));
++              ssb_dbg("can not register watchdog device, err: %li\n",
++                      PTR_ERR(pdev));
 +              return PTR_ERR(pdev);
 +      }
 +
  #include <linux/ssb/ssb.h>
  #include <linux/ssb/ssb_regs.h>
  #include <linux/ssb/ssb_driver_gige.h>
-@@ -433,6 +434,11 @@ static void ssb_devices_unregister(struc
+@@ -274,8 +275,8 @@ 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_device_put(sdev);
+@@ -433,10 +434,23 @@ static void ssb_devices_unregister(struc
                if (sdev->dev)
                        device_unregister(sdev->dev);
        }
  }
  
  void ssb_bus_unregister(struct ssb_bus *bus)
-@@ -561,6 +567,8 @@ static int __devinit ssb_attach_queued_b
+ {
++      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);
+@@ -482,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;
+               }
+@@ -522,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;
+@@ -534,6 +545,22 @@ static int ssb_devices_register(struct s
+               dev_idx++;
+       }
++#ifdef CONFIG_SSB_DRIVER_MIPS
++      if (bus->mipscore.pflash.present) {
++              err = platform_device_register(&ssb_pflash_dev);
++              if (err)
++                      pr_err("Error registering parallel flash\n");
++      }
++#endif
++
++#ifdef CONFIG_SSB_SFLASH
++      if (bus->mipscore.sflash.present) {
++              err = platform_device_register(&ssb_sflash_dev);
++              if (err)
++                      pr_err("Error registering serial flash\n");
++      }
++#endif
++
+       return 0;
+ error:
+       /* Unwind the already registered devices. */
+@@ -561,6 +588,8 @@ static int __devinit ssb_attach_queued_b
                if (err)
                        goto error;
                ssb_pcicore_init(&bus->pcicore);
                ssb_bus_may_powerdown(bus);
  
                err = ssb_devices_register(bus);
-@@ -796,7 +804,14 @@ static int __devinit ssb_bus_register(st
+@@ -796,7 +825,13 @@ static int __devinit ssb_bus_register(st
        if (err)
                goto err_pcmcia_exit;
        ssb_chipcommon_init(&bus->chipco);
        ssb_mipscore_init(&bus->mipscore);
 +      err = ssb_gpio_init(bus);
 +      if (err == -ENOTSUPP)
-+              ssb_dprintk(KERN_DEBUG PFX "GPIO driver not activated\n");
++              ssb_dbg("GPIO driver not activated\n");
 +      else if (err)
-+              ssb_dprintk(KERN_ERR PFX
-+                         "Error registering GPIO driver: %i\n", err);
++              ssb_dbg("Error registering GPIO driver: %i\n", err);
        err = ssb_fetch_invariants(bus, get_invariants);
        if (err) {
                ssb_bus_may_powerdown(bus);
-@@ -1118,8 +1133,7 @@ static u32 ssb_tmslow_reject_bitmask(str
+@@ -847,11 +882,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;
+@@ -872,8 +907,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;
+@@ -895,8 +930,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;
+@@ -915,8 +950,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;
+@@ -1118,8 +1153,7 @@ static u32 ssb_tmslow_reject_bitmask(str
        case SSB_IDLOW_SSBREV_27:     /* same here */
                return SSB_TMSLOW_REJECT;       /* this is a guess */
        default:
        }
        return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
  }
+@@ -1311,7 +1345,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);
+@@ -1334,7 +1368,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);
+@@ -1442,15 +1476,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
+@@ -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);
+@@ -231,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 word;
+@@ -278,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;
+@@ -286,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);
+@@ -309,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;
+ }
+@@ -339,10 +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;
+       u16 loc[3];
+       if (out->revision == 3)                 /* rev 3 moved MAC */
+@@ -352,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,
+@@ -372,6 +384,7 @@ 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(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);
+@@ -398,8 +411,7 @@ 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);
++
+       SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
+       SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
+@@ -410,6 +422,8 @@ static void sprom_extract_r123(struct ss
+       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 */
+@@ -454,23 +468,20 @@ 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(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
+               SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
+@@ -530,7 +541,7 @@ static void sprom_extract_r45(struct ssb
+ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
+ {
+       int i;
+-      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
+@@ -539,11 +550,10 @@ static void sprom_extract_r8(struct ssb_
+                       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);
+-      }
++      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);
+@@ -743,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);
+@@ -752,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) {
+@@ -769,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);
+       }
+@@ -791,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! */
+@@ -810,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)
+@@ -835,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);
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -38,7 +38,7 @@ static int ssb_pcihost_resume(struct pci
+       struct ssb_bus *ssb = pci_get_drvdata(dev);
+       int err;
+-      pci_set_power_state(dev, 0);
++      pci_set_power_state(dev, PCI_D0);
+       err = pci_enable_device(dev);
+       if (err)
+               return err;
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -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;
+@@ -700,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;
+@@ -722,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;
+       }
+@@ -733,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;
+ }
+@@ -843,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
+@@ -125,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;
+@@ -152,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;
+@@ -320,15 +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) {
+@@ -370,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;
+                               }
+                       }
+@@ -379,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;
+@@ -388,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;
+@@ -398,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;
+@@ -420,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/sprom.c
++++ b/drivers/ssb/sprom.c
+@@ -54,7 +54,7 @@ static int hex2sprom(u16 *sprom, const c
+       while (cnt < sprom_size_words) {
+               memcpy(tmp, dump, 4);
+               dump += 4;
+-              err = strict_strtoul(tmp, 16, &parsed);
++              err = kstrtoul(tmp, 16, &parsed);
+               if (err)
+                       return err;
+               sprom[cnt++] = swab16((u16)parsed);
+@@ -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
-@@ -3,6 +3,7 @@
+@@ -3,21 +3,33 @@
  
  #include <linux/ssb/ssb.h>
  #include <linux/types.h>
  
  
  #define PFX   "ssb: "
-@@ -210,5 +211,63 @@ static inline void b43_pci_ssb_bridge_ex
+ #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
+@@ -210,5 +222,76 @@ static inline void b43_pci_ssb_bridge_ex
  /* 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);
 +}
 +#endif /* CONFIG_SSB_SFLASH */
 +
++#ifdef CONFIG_SSB_DRIVER_MIPS
++extern struct platform_device ssb_pflash_dev;
++#endif
++
++#ifdef CONFIG_SSB_SFLASH
++extern struct platform_device ssb_sflash_dev;
++#endif
++
 +#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);
 +
 +#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_ */
  
  #include <linux/ssb/ssb_regs.h>
  
-@@ -432,7 +434,11 @@ struct ssb_bus {
+@@ -24,9 +26,9 @@ struct ssb_sprom_core_pwr_info {
+ struct ssb_sprom {
+       u8 revision;
+-      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 */
+@@ -338,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 */
+@@ -432,7 +482,11 @@ struct ssb_bus {
  #ifdef CONFIG_SSB_EMBEDDED
        /* Lock for GPIO register access. */
        spinlock_t gpio_lock;
 +
  #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
+@@ -97,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);
+@@ -175,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
-@@ -13,6 +13,12 @@ struct ssb_serial_port {
+@@ -13,6 +13,24 @@ struct ssb_serial_port {
        unsigned int reg_shift;
  };
  
 +      u32 window;
 +      u32 window_size;
 +};
++
++#ifdef CONFIG_SSB_SFLASH
++struct ssb_sflash {
++      bool present;
++      u32 window;
++      u32 blocksize;
++      u16 numblocks;
++      u32 size;
++
++      void *priv;
++};
++#endif
  
  struct ssb_mipscore {
        struct ssb_device *dev;
-@@ -20,9 +26,7 @@ struct ssb_mipscore {
+@@ -20,9 +38,10 @@ struct ssb_mipscore {
        int nr_serial_ports;
        struct ssb_serial_port serial_ports[4];
  
 -      u32 flash_window;
 -      u32 flash_window_size;
 +      struct ssb_pflash pflash;
++#ifdef CONFIG_SSB_SFLASH
++      struct ssb_sflash sflash;
++#endif
  };
  
  extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
+@@ -41,6 +60,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
-@@ -289,11 +289,11 @@
+@@ -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
+@@ -289,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_AGAIN01            0x005E  /* Antenna Gain (in dBm Q5.2) */
  #define  SSB_SPROM4_AGAIN0            0x00FF  /* Antenna 0 */
  #define  SSB_SPROM4_AGAIN0_SHIFT      0
-@@ -485,7 +485,7 @@
+@@ -485,7 +486,7 @@
  #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
                break;
  #endif
        }
---- a/drivers/ssb/pci.c
-+++ b/drivers/ssb/pci.c
-@@ -339,6 +339,21 @@ 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;
-@@ -398,8 +413,7 @@ 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);
-+
-       SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
-       SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
-@@ -410,6 +424,8 @@ static void sprom_extract_r123(struct ss
-       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 */
index 3cba3ca..950ac93 100644 (file)
@@ -1,6 +1,25 @@
+--- 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/drivers/bcma/Kconfig
 +++ b/drivers/bcma/Kconfig
-@@ -65,6 +65,14 @@ config BCMA_DRIVER_GMAC_CMN
+@@ -26,6 +26,7 @@ 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"
+@@ -65,6 +66,14 @@ config BCMA_DRIVER_GMAC_CMN
  
          If unsure, say N
  
  obj-$(CONFIG_BCMA)                    += bcma.o
 --- a/drivers/bcma/bcma_private.h
 +++ b/drivers/bcma/bcma_private.h
-@@ -31,6 +31,8 @@ int __init bcma_bus_early_register(struc
+@@ -22,6 +22,8 @@
+ struct bcma_bus;
+ /* main.c */
++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,
+@@ -31,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
  
  /* scan.c */
  int bcma_bus_scan(struct bcma_bus *bus);
-@@ -48,8 +50,8 @@ void bcma_chipco_serial_init(struct bcma
+@@ -45,11 +49,12 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ /* driver_chipcommon.c */
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++extern struct platform_device bcma_pflash_dev;
  #endif /* CONFIG_BCMA_DRIVER_MIPS */
  
  /* driver_chipcommon_pmu.c */
@@ -47,7 +79,7 @@
  
  #ifdef CONFIG_BCMA_SFLASH
  /* driver_chipcommon_sflash.c */
-@@ -84,9 +86,21 @@ extern void __exit bcma_host_pci_exit(vo
+@@ -84,9 +89,26 @@ extern void __exit bcma_host_pci_exit(vo
  /* driver_pci.c */
  u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
  
 +#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
+@@ -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,13 +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);
+@@ -43,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));
+@@ -104,7 +126,13 @@ void bcma_core_pll_ctl(struct bcma_devic
+               if (i)
+                       bcma_err(core->bus, "PLL enable timeout\n");
+       } else {
+-              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);
 --- a/drivers/bcma/driver_chipcommon.c
 +++ b/drivers/bcma/driver_chipcommon.c
 @@ -4,12 +4,15 @@
  #include <linux/bcma/bcma.h>
  
  static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
-@@ -22,20 +25,120 @@ static inline u32 bcma_cc_write32_masked
+@@ -22,23 +25,130 @@ static inline u32 bcma_cc_write32_masked
        return value;
  }
  
 +      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);
-@@ -56,15 +159,33 @@ void bcma_core_chipcommon_init(struct bc
+-              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)
+@@ -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)));
        }
  }
  
  void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
-@@ -84,28 +205,99 @@ u32 bcma_chipco_gpio_in(struct bcma_drv_
+@@ -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)
  {
  }
  
  #ifdef CONFIG_BCMA_DRIVER_MIPS
-@@ -118,8 +310,7 @@ void bcma_chipco_serial_init(struct bcma
+@@ -118,8 +317,7 @@ void bcma_chipco_serial_init(struct bcma
        struct bcma_serial_port *ports = cc->serial_ports;
  
        if (ccrev >= 11 && ccrev != 15) {
                if (ccrev >= 21) {
                        /* Turn off UART clock before switching clocksource. */
                        bcma_cc_write32(cc, BCMA_CC_CORECTL,
+@@ -141,7 +339,7 @@ void bcma_chipco_serial_init(struct bcma
+               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_nflash.c
 +++ b/drivers/bcma/driver_chipcommon_nflash.c
+@@ -5,11 +5,11 @@
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
++#include "bcma_private.h"
++
+ #include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+-#include "bcma_private.h"
+-
+ struct platform_device bcma_nflash_dev = {
+       .name           = "bcma_nflash",
+       .num_resources  = 0,
+@@ -21,7 +21,7 @@ int bcma_nflash_init(struct bcma_drv_cc
+       struct bcma_bus *bus = cc->core->bus;
+       if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
+-          cc->core->id.rev != 0x38) {
++          cc->core->id.rev != 38) {
+               bcma_err(bus, "NAND flash on unsupported board!\n");
+               return -ENOTSUPP;
+       }
 @@ -32,6 +32,9 @@ int bcma_nflash_init(struct bcma_drv_cc
        }
  
  
  void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
  {
-@@ -144,7 +145,7 @@ static void bcma_pmu_workarounds(struct
+@@ -55,6 +56,109 @@ void bcma_chipco_regctl_maskset(struct b
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
++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 BCMA_CHIP_ID_BCM43142:
++              if (xtalfreq == 0)
++                      xtalfreq = 20000;
++              bcma_pmu2_pll_init0(cc, xtalfreq);
++              break;
++      }
++}
++
+ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
+ {
+       struct bcma_bus *bus = cc->core->bus;
+@@ -65,6 +169,25 @@ static void bcma_pmu_resources_init(stru
+               min_msk = 0x200D;
+               max_msk = 0xFFFF;
+               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:
+               bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n",
+                          bus->chipinfo.id);
+@@ -144,7 +267,7 @@ static void bcma_pmu_workarounds(struct
        }
  }
  
  {
        u32 pmucap;
  
-@@ -153,7 +154,10 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+@@ -153,7 +276,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);
        if (cc->pmu.rev == 1)
                bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
                              ~BCMA_CC_PMU_CTL_NOILPONW);
-@@ -165,24 +169,40 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+@@ -161,28 +287,45 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+               bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+                            BCMA_CC_PMU_CTL_NOILPONW);
++      bcma_pmu_pll_init(cc);
+       bcma_pmu_resources_init(cc);
        bcma_pmu_workarounds(cc);
  }
  
        default:
                bcma_warn(bus, "No ALP clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
                          bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
-@@ -193,7 +213,7 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
+@@ -193,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.
   */
  {
        u32 tmp, div, ndiv, p1, p2, fc;
        struct bcma_bus *bus = cc->core->bus;
-@@ -222,14 +242,14 @@ static u32 bcma_pmu_clock(struct bcma_dr
+@@ -222,14 +365,14 @@ static u32 bcma_pmu_clock(struct bcma_dr
        ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
  
        /* Do calculation in Mhz */
  {
        u32 tmp, ndiv, p1div, p2div;
        u32 clock;
-@@ -260,7 +280,7 @@ static u32 bcma_pmu_clock_bcm4706(struct
+@@ -260,7 +403,7 @@ static u32 bcma_pmu_clock_bcm4706(struct
  }
  
  /* query bus clock frequency for PMU-enabled chipcommon */
 -static u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
-+static u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
++u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
  {
        struct bcma_bus *bus = cc->core->bus;
  
-@@ -268,40 +288,42 @@ static u32 bcma_pmu_get_clockcontrol(str
+@@ -268,40 +411,43 @@ static u32 bcma_pmu_get_clockcontrol(str
        case BCMA_CHIP_ID_BCM4716:
        case BCMA_CHIP_ID_BCM4748:
        case BCMA_CHIP_ID_BCM47162:
        }
        return BCMA_CC_PMU_HT_CLOCK;
  }
++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)
                                                BCMA_CC_PMU4706_MAINPLL_PLL0,
                                                BCMA_CC_PMU5_MAINPLL_CPU);
                case BCMA_CHIP_ID_BCM5356:
-@@ -316,10 +338,11 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
+@@ -316,10 +462,11 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
                        break;
                }
  
  }
  
  static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
-@@ -365,7 +388,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -365,7 +512,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
                bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
  
                break;
  
        case BCMA_CHIP_ID_BCM4331:
-@@ -386,7 +409,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -386,7 +533,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
                                                     0x03000a08);
                }
                break;
  
        case BCMA_CHIP_ID_BCM43224:
-@@ -419,7 +442,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -419,7 +566,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
                                                     0x88888815);
                }
                break;
  
        case BCMA_CHIP_ID_BCM4716:
-@@ -453,7 +476,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -453,7 +600,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                                                     0x88888815);
                }
  
                break;
  
        case BCMA_CHIP_ID_BCM43227:
-@@ -489,7 +512,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -489,7 +636,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
                                                     0x88888815);
                }
                bcma_err(bus, "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
 --- a/drivers/bcma/driver_chipcommon_sflash.c
 +++ b/drivers/bcma/driver_chipcommon_sflash.c
-@@ -12,7 +12,7 @@
+@@ -5,14 +5,14 @@
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
++#include "bcma_private.h"
++
+ #include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
  
+-#include "bcma_private.h"
+-
  static struct resource bcma_sflash_resource = {
        .name   = "bcma_sflash",
 -      .start  = BCMA_SFLASH,
        .end    = 0,
        .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
  };
-@@ -31,15 +31,42 @@ struct bcma_sflash_tbl_e {
+@@ -30,16 +30,43 @@ struct bcma_sflash_tbl_e {
+       u16 numblocks;
  };
  
- static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
+-static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
 -      { "", 0x14, 0x10000, 32, },
++static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
 +      { "M25P20", 0x11, 0x10000, 4, },
 +      { "M25P40", 0x12, 0x10000, 8, },
 +
        { 0 },
  };
  
- static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
+-static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
 +      { "SST25WF512", 1, 0x1000, 16, },
 +      { "SST25VF512", 0x48, 0x1000, 16, },
 +      { "SST25WF010", 2, 0x1000, 32, },
        { 0 },
  };
  
- static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
+-static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
 +      { "AT45DB011", 0xc, 256, 512, },
 +      { "AT45DB021", 0x14, 256, 1024, },
 +      { "AT45DB041", 0x1c, 256, 2048, },
        { 0 },
  };
  
+@@ -62,7 +89,7 @@ int bcma_sflash_init(struct bcma_drv_cc
+ {
+       struct bcma_bus *bus = cc->core->bus;
+       struct bcma_sflash *sflash = &cc->sflash;
+-      struct bcma_sflash_tbl_e *e;
++      const struct bcma_sflash_tbl_e *e;
+       u32 id, id2;
+       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 @@ -84,6 +111,8 @@ int bcma_sflash_init(struct bcma_drv_cc
                                        break;
                        }
        sflash->size = sflash->blocksize * sflash->numblocks;
 --- /dev/null
 +++ b/drivers/bcma/driver_gpio.c
-@@ -0,0 +1,98 @@
+@@ -0,0 +1,114 @@
 +/*
 + * Broadcom specific AMBA
 + * GPIO driver
 +      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->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
 +
 +      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
-@@ -74,11 +74,16 @@ static u32 bcma_core_mips_irqflag(struct
+@@ -14,11 +14,33 @@
+ #include <linux/bcma/bcma.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+ #include <linux/time.h>
++static const char * const part_probes[] = { "bcm47xxpart", NULL };
++
++static struct physmap_flash_data bcma_pflash_data = {
++      .part_probe_types       = part_probes,
++};
++
++static struct resource bcma_pflash_resource = {
++      .name   = "bcma_pflash",
++      .flags  = IORESOURCE_MEM,
++};
++
++struct platform_device bcma_pflash_dev = {
++      .name           = "physmap-flash",
++      .dev            = {
++              .platform_data  = &bcma_pflash_data,
++      },
++      .resource       = &bcma_pflash_resource,
++      .num_resources  = 1,
++};
++
+ /* The 47162a0 hangs when reading MIPS DMP registers registers */
+ static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+ {
+@@ -74,28 +96,41 @@ static u32 bcma_core_mips_irqflag(struct
                return dev->core_index;
        flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
  
 + * If disabled, 5 is returned.
 + * If not supported, 6 is returned.
   */
- unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+-unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
  {
-@@ -87,13 +92,15 @@ unsigned int bcma_core_mips_irq(struct b
+       struct bcma_device *mdev = dev->bus->drv_mips.core;
+       u32 irqflag;
        unsigned int irq;
  
        irqflag = bcma_core_mips_irqflag(dev);
  
 -      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_mips_irq);
++EXPORT_SYMBOL(bcma_core_irq);
  
-@@ -114,7 +121,7 @@ static void bcma_core_mips_set_irq(struc
+ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+ {
+@@ -114,7 +149,7 @@ 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));
                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
  
        /* assign the new one */
-@@ -123,9 +130,9 @@ static void bcma_core_mips_set_irq(struc
+@@ -123,9 +158,9 @@ static void bcma_core_mips_set_irq(struc
                            bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
                            (1 << irqflag));
        } else {
                        struct bcma_device *core;
  
                        /* backplane irq line is in use, find out who uses
-@@ -133,7 +140,7 @@ static void bcma_core_mips_set_irq(struc
+@@ -133,7 +168,7 @@ static void bcma_core_mips_set_irq(struc
                         */
                        list_for_each_entry(core, &bus->cores, list) {
                                if ((1 << bcma_core_mips_irqflag(core)) ==
                                        bcma_core_mips_set_irq(core, 0);
                                        break;
                                }
-@@ -143,15 +150,31 @@ static void bcma_core_mips_set_irq(struc
+@@ -143,15 +178,31 @@ static void bcma_core_mips_set_irq(struc
                             1 << irqflag);
        }
  
        for (i = 0; i <= 6; i++)
                printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
        printk("\n");
-@@ -171,7 +194,7 @@ u32 bcma_cpu_clock(struct bcma_drv_mips
+@@ -171,7 +222,7 @@ u32 bcma_cpu_clock(struct bcma_drv_mips
        struct bcma_bus *bus = mcore->core->bus;
  
        if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
  
        bcma_err(bus, "No PMU available, need this to get the cpu clock\n");
        return 0;
-@@ -181,85 +204,109 @@ EXPORT_SYMBOL(bcma_cpu_clock);
+@@ -181,85 +232,143 @@ EXPORT_SYMBOL(bcma_cpu_clock);
  static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
  {
        struct bcma_bus *bus = mcore->core->bus;
 +      struct bcma_drv_cc *cc = &bus->drv_cc;
++      struct bcma_pflash *pflash = &cc->pflash;
  
 -      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
 +      switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
                bcma_debug(bus, "Found parallel flash\n");
 -              bus->drv_cc.pflash.window = 0x1c000000;
 -              bus->drv_cc.pflash.window_size = 0x02000000;
-+              cc->pflash.present = true;
-+              cc->pflash.window = BCMA_SOC_FLASH2;
-+              cc->pflash.window_size = BCMA_SOC_FLASH2_SZ;
++              pflash->present = true;
++              pflash->window = BCMA_SOC_FLASH2;
++              pflash->window_size = BCMA_SOC_FLASH2_SZ;
  
 -              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
 +              if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
                     BCMA_CC_FLASH_CFG_DS) == 0)
 -                      bus->drv_cc.pflash.buswidth = 1;
-+                      cc->pflash.buswidth = 1;
++                      pflash->buswidth = 1;
                else
 -                      bus->drv_cc.pflash.buswidth = 2;
-+                      cc->pflash.buswidth = 2;
++                      pflash->buswidth = 2;
++
++              bcma_pflash_data.width = pflash->buswidth;
++              bcma_pflash_resource.start = pflash->window;
++              bcma_pflash_resource.end = pflash->window + pflash->window_size;
++
                break;
        default:
                bcma_err(bus, "Flash type not supported\n");
 +      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");
++      }
++}
++
  void bcma_core_mips_init(struct bcma_drv_mips *mcore)
  {
        struct bcma_bus *bus;
 -                      break;
 +      bcma_core_mips_early_init(mcore);
 +
++      bcma_fix_i2s_irqflag(bus);
++
 +      switch (bus->chipinfo.id) {
 +      case BCMA_CHIP_ID_BCM4716:
 +      case BCMA_CHIP_ID_BCM4748:
 +              break;
 +      default:
 +              list_for_each_entry(core, &bus->cores, list) {
-+                      core->irq = bcma_core_mips_irq(core) + 2;
++                      core->irq = bcma_core_irq(core);
                }
 +              bcma_err(bus,
 +                       "Unknown device (0x%x) found, can not configure IRQs\n",
        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
+@@ -99,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 {
+@@ -124,11 +119,9 @@ static int bcma_extpci_read_config(struc
+                       goto out;
+               if (mips_busprobe32(val, mmio)) {
+-                      val = 0xffffffff;
++                      val = 0xFFFFFFFF;
+                       goto unmap;
+               }
+-
+-              val = readl(mmio);
+       }
+       val >>= (8 * (off & 3));
+@@ -156,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;
+@@ -164,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);
+@@ -185,19 +184,17 @@ static int bcma_extpci_write_config(stru
+                       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;
+@@ -205,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);
+@@ -282,7 +280,7 @@ static u8 __devinit bcma_find_pci_capabi
+       /* 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 */
+@@ -396,12 +394,19 @@ void __devinit bcma_core_pci_hostmode_in
  
        bcma_info(bus, "PCIEcore in host mode found\n");
  
        pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
        if (!pc_host)  {
                bcma_err(bus, "can not allocate memory");
-@@ -452,6 +452,8 @@ void __devinit bcma_core_pci_hostmode_in
+               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;
+@@ -427,7 +432,7 @@ void __devinit bcma_core_pci_hostmode_in
+       /* Reset RC */
+       usleep_range(3000, 5000);
+       pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
+-      usleep_range(1000, 2000);
++      msleep(50);
+       pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
+                       BCMA_CORE_PCI_CTL_RST_OE);
+@@ -452,6 +457,8 @@ void __devinit bcma_core_pci_hostmode_in
                        pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
                        pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
                                                    BCMA_SOC_PCI_MEM_SZ - 1;
                        pci_membase_1G = BCMA_SOC_PCIE_DMA_H32;
                        pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
                                        tmp | BCMA_SOC_PCI_MEM);
-@@ -459,6 +461,8 @@ void __devinit bcma_core_pci_hostmode_in
+@@ -459,6 +466,8 @@ void __devinit bcma_core_pci_hostmode_in
                        pc_host->mem_resource.start = BCMA_SOC_PCI1_MEM;
                        pc_host->mem_resource.end = BCMA_SOC_PCI1_MEM +
                                                    BCMA_SOC_PCI_MEM_SZ - 1;
                        pci_membase_1G = BCMA_SOC_PCIE1_DMA_H32;
                        pc_host->host_cfg_addr = BCMA_SOC_PCI1_CFG;
                        pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
-@@ -534,7 +538,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_
+@@ -485,6 +494,17 @@ void __devinit bcma_core_pci_hostmode_in
+       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));
+@@ -534,7 +554,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_
  static void bcma_core_pci_fixup_addresses(struct pci_dev *dev)
  {
        struct resource *res;
  
        if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
                /* This is not a device on the PCI-core bridge. */
-@@ -547,8 +551,12 @@ static void bcma_core_pci_fixup_addresse
+@@ -547,8 +567,12 @@ static void bcma_core_pci_fixup_addresse
  
        for (pos = 0; pos < 6; pos++) {
                res = &dev->resource[pos];
        }
  }
  DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_addresses);
+@@ -569,7 +593,7 @@ int bcma_core_pci_plat_dev_init(struct p
+       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;
+@@ -588,6 +612,6 @@ int bcma_core_pci_pcibios_map_irq(const
+       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
 +++ b/drivers/bcma/host_pci.c
 @@ -238,7 +238,7 @@ static void __devexit bcma_host_pci_remo
  
  static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
+@@ -275,6 +275,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
+       { 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, },
+ };
 --- a/drivers/bcma/main.c
 +++ b/drivers/bcma/main.c
-@@ -81,6 +81,18 @@ struct bcma_device *bcma_find_core(struc
+@@ -81,6 +81,37 @@ struct bcma_device *bcma_find_core(struc
  }
  EXPORT_SYMBOL_GPL(bcma_find_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)
  {
        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
-@@ -152,6 +164,17 @@ static int bcma_register_cores(struct bc
+@@ -108,6 +139,11 @@ static int bcma_register_cores(struct bc
+                       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", bus->num, dev_id);
+@@ -137,6 +173,14 @@ static int bcma_register_cores(struct bc
+               dev_id++;
+       }
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      if (bus->drv_cc.pflash.present) {
++              err = platform_device_register(&bcma_pflash_dev);
++              if (err)
++                      bcma_err(bus, "Error registering parallel flash\n");
++      }
++#endif
++
+ #ifdef CONFIG_BCMA_SFLASH
+       if (bus->drv_cc.sflash.present) {
+               err = platform_device_register(&bcma_sflash_dev);
+@@ -152,6 +196,17 @@ static int bcma_register_cores(struct bc
                        bcma_err(bus, "Error registering NAND flash\n");
        }
  #endif
  
        return 0;
  }
-@@ -165,6 +188,8 @@ static void bcma_unregister_cores(struct
+@@ -165,6 +220,8 @@ static void bcma_unregister_cores(struct
                if (core->dev_registered)
                        device_unregister(&core->dev);
        }
  }
  
  int __devinit bcma_bus_register(struct bcma_bus *bus)
-@@ -183,6 +208,20 @@ int __devinit bcma_bus_register(struct b
+@@ -183,6 +240,20 @@ int __devinit bcma_bus_register(struct b
                return -1;
        }
  
        /* Init CC core */
        core = bcma_find_core(bus, bcma_cc_core_id(bus));
        if (core) {
-@@ -198,10 +237,17 @@ int __devinit bcma_bus_register(struct b
+@@ -198,10 +269,17 @@ int __devinit bcma_bus_register(struct 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);
++      if (core) {
 +              bus->drv_pci[0].core = core;
 +              bcma_core_pci_init(&bus->drv_pci[0]);
 +      }
 +
 +      /* Init PCIE core */
 +      core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1);
-+      if (core) {
+       if (core) {
+-              bus->drv_pci.core = core;
+-              bcma_core_pci_init(&bus->drv_pci);
 +              bus->drv_pci[1].core = core;
 +              bcma_core_pci_init(&bus->drv_pci[1]);
        }
  
        /* Init GBIT MAC COMMON core */
-@@ -211,13 +257,6 @@ int __devinit bcma_bus_register(struct b
+@@ -211,13 +289,6 @@ int __devinit bcma_bus_register(struct b
                bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
        }
  
        /* Register found cores */
        bcma_register_cores(bus);
  
-@@ -275,18 +314,18 @@ int __init bcma_bus_early_register(struc
+@@ -229,6 +300,13 @@ int __devinit bcma_bus_register(struct b
+ 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);
+@@ -275,18 +353,18 @@ int __init bcma_bus_early_register(struc
                return -1;
        }
  
        }
  
        bcma_info(bus, "Early bus registered\n");
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -84,6 +84,8 @@ static const struct bcma_device_id_name
+       { 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" },
+ };
+@@ -137,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))
+@@ -159,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);
+@@ -175,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) {
+@@ -189,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))
+@@ -199,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;
 --- a/drivers/bcma/sprom.c
 +++ b/drivers/bcma/sprom.c
-@@ -595,8 +595,11 @@ int bcma_sprom_get(struct bcma_bus *bus)
+@@ -72,12 +72,12 @@ fail:
+  * R/W ops.
+  **************************************************/
+-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));
+ }
+ /**************************************************
+@@ -124,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;
+@@ -154,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;
+ }
+@@ -208,15 +212,13 @@ static void bcma_sprom_extract_r8(struct
+       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;
+-
+       for (i = 0; i < 3; i++) {
+               v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
+               *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
+       }
+       SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
++      SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
+       SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
+            SSB_SPROM4_TXPID2G0_SHIFT);
+@@ -501,7 +503,7 @@ static bool bcma_sprom_onchip_available(
+       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 */
+@@ -549,7 +551,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ {
+       u16 offset = BCMA_CC_SPROM;
+       u16 *sprom;
+-      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;
+@@ -578,29 +582,37 @@ int bcma_sprom_get(struct bcma_bus *bus)
+               }
+       }
+-      sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+-                      GFP_KERNEL);
+-      if (!sprom)
+-              return -ENOMEM;
+-
+       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, false);
+       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;
++
++              kfree(sprom);
++      }
+       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);
  
-       err = bcma_sprom_valid(sprom);
+-      err = bcma_sprom_valid(sprom);
 -      if (err)
+-              goto out;
+-
+-      bcma_sprom_extract_r8(bus, sprom);
 +      if (err) {
-+              bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
++              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);
-               goto out;
++      } else {
++              bcma_sprom_extract_r8(bus, sprom);
++              kfree(sprom);
 +      }
  
-       bcma_sprom_extract_r8(bus, sprom);
+-out:
+-      kfree(sprom);
+       return err;
+ }
 --- a/include/linux/bcma/bcma.h
 +++ b/include/linux/bcma/bcma.h
-@@ -134,6 +134,7 @@ struct bcma_host_ops {
+@@ -134,12 +134,17 @@ 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_ARM_CR4             0x83e
++#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
-@@ -157,6 +158,7 @@ struct bcma_host_ops {
+ /* 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
+@@ -157,6 +162,7 @@ struct bcma_host_ops {
  
  /* Chip IDs of SoCs */
  #define BCMA_CHIP_ID_BCM4706  0x5300
  #define BCMA_CHIP_ID_BCM4716  0x4716
  #define  BCMA_PKG_ID_BCM4716  8
  #define  BCMA_PKG_ID_BCM4717  9
-@@ -166,7 +168,11 @@ struct bcma_host_ops {
+@@ -166,7 +172,65 @@ struct bcma_host_ops {
  #define BCMA_CHIP_ID_BCM4749  0x4749
  #define BCMA_CHIP_ID_BCM5356  0x5356
  #define BCMA_CHIP_ID_BCM5357  0x5357
 +#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;
-@@ -251,7 +257,7 @@ struct bcma_bus {
+@@ -251,7 +315,7 @@ struct bcma_bus {
        u8 num;
  
        struct bcma_drv_cc drv_cc;
        struct bcma_drv_mips drv_mips;
        struct bcma_drv_gmac_cmn drv_gmac_cmn;
  
-@@ -345,6 +351,7 @@ extern void bcma_core_set_clockmode(stru
+@@ -345,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);
  /** 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      /* NAND flash */
++#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
 @@ -101,6 +104,7 @@
  #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_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 */
-@@ -510,6 +517,7 @@ struct bcma_chipcommon_pmu {
+@@ -323,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 */
+@@ -348,6 +357,11 @@
+ #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 */
+ /* NAND flash MLC controller registers (corerev >= 38) */
+ #define BCMA_CC_NAND_REVISION         0x0C00
+@@ -428,6 +442,23 @@
+ #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
+ /* HT clock for systems with PMU-enabled chipcommon */
+@@ -500,6 +531,37 @@
+ #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)
+  */
+@@ -510,6 +572,7 @@ struct bcma_chipcommon_pmu {
  
  #ifdef CONFIG_BCMA_DRIVER_MIPS
  struct bcma_pflash {
        u8 buswidth;
        u32 window;
        u32 window_size;
-@@ -532,6 +540,7 @@ struct mtd_info;
+@@ -524,6 +587,7 @@ struct bcma_sflash {
+       u32 size;
+       struct mtd_info *mtd;
++      void *priv;
+ };
+ #endif
+@@ -532,6 +596,7 @@ struct mtd_info;
  
  struct bcma_nflash {
        bool present;
  
        struct mtd_info *mtd;
  };
-@@ -552,6 +561,7 @@ struct bcma_drv_cc {
+@@ -552,6 +617,7 @@ struct bcma_drv_cc {
        u32 capabilities;
        u32 capabilities_ext;
        u8 setup_done:1;
        /* Fast Powerup Delay constant */
        u16 fast_pwrup_delay;
        struct bcma_chipcommon_pmu pmu;
-@@ -567,6 +577,14 @@ struct bcma_drv_cc {
+@@ -567,6 +633,14 @@ struct bcma_drv_cc {
        int nr_serial_ports;
        struct bcma_serial_port serial_ports[4];
  #endif /* CONFIG_BCMA_DRIVER_MIPS */
  };
  
  /* Register access */
-@@ -583,14 +601,16 @@ struct bcma_drv_cc {
+@@ -583,14 +657,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);
  
  void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value);
  
-@@ -603,9 +623,12 @@ u32 bcma_chipco_gpio_outen(struct bcma_d
+@@ -603,9 +679,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);
  
  extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
                                  u32 value);
+@@ -617,4 +696,6 @@ 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);
++extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc);
++
+ #endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- a/include/linux/bcma/bcma_driver_mips.h
 +++ b/include/linux/bcma/bcma_driver_mips.h
-@@ -35,13 +35,15 @@ struct bcma_device;
+@@ -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;
  #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
+@@ -179,6 +179,8 @@ struct pci_dev;
+ #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
 --- a/include/linux/bcma/bcma_regs.h
 +++ b/include/linux/bcma/bcma_regs.h
 @@ -37,6 +37,7 @@
index a1b4a1f..22dae59 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/ssb/Kconfig
 +++ b/drivers/ssb/Kconfig
-@@ -136,6 +136,11 @@ config SSB_DRIVER_MIPS
+@@ -136,10 +136,15 @@ config SSB_DRIVER_MIPS
  
          If unsure, say N
  
  # Assumption: We are on embedded, if we compile the MIPS core.
  config SSB_EMBEDDED
        bool
+-      depends on SSB_DRIVER_MIPS
++      depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
+       default y
+ config SSB_DRIVER_EXTIF
 --- a/drivers/ssb/Makefile
 +++ b/drivers/ssb/Makefile
 @@ -11,6 +11,7 @@ ssb-$(CONFIG_SSB_SDIOHOST)           += sdio.o
                           "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
 --- /dev/null
 +++ b/drivers/ssb/driver_chipcommon_sflash.c
-@@ -0,0 +1,140 @@
+@@ -0,0 +1,166 @@
 +/*
 + * Sonics Silicon Backplane
 + * ChipCommon serial flash interface
 +
 +#include "ssb_private.h"
 +
++static struct resource ssb_sflash_resource = {
++      .name   = "ssb_sflash",
++      .start  = SSB_FLASH2,
++      .end    = 0,
++      .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
++};
++
++struct platform_device ssb_sflash_dev = {
++      .name           = "ssb_sflash",
++      .resource       = &ssb_sflash_resource,
++      .num_resources  = 1,
++};
++
 +struct ssb_sflash_tbl_e {
 +      char *name;
 +      u32 id;
 +      u16 numblocks;
 +};
 +
-+static struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
++static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
 +      { "M25P20", 0x11, 0x10000, 4, },
 +      { "M25P40", 0x12, 0x10000, 8, },
 +
 +      { 0 },
 +};
 +
-+static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
++static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
 +      { "SST25WF512", 1, 0x1000, 16, },
 +      { "SST25VF512", 0x48, 0x1000, 16, },
 +      { "SST25WF010", 2, 0x1000, 32, },
 +      { 0 },
 +};
 +
-+static struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
++static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
 +      { "AT45DB011", 0xc, 256, 512, },
 +      { "AT45DB021", 0x14, 256, 1024, },
 +      { "AT45DB041", 0x1c, 256, 2048, },
 +/* Initialize serial flash access */
 +int ssb_sflash_init(struct ssb_chipcommon *cc)
 +{
-+      struct ssb_sflash_tbl_e *e;
++      struct ssb_sflash *sflash = &cc->dev->bus->mipscore.sflash;
++      const struct ssb_sflash_tbl_e *e;
 +      u32 id, id2;
 +
 +      switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
 +              return -ENOTSUPP;
 +      }
 +
++      sflash->window = SSB_FLASH2;
++      sflash->blocksize = e->blocksize;
++      sflash->numblocks = e->numblocks;
++      sflash->size = sflash->blocksize * sflash->numblocks;
++      sflash->present = true;
++
 +      pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
 +              e->name, e->blocksize, e->numblocks);
 +
++      /* Prepare platform device, but don't register it yet. It's too early,
++       * malloc (required by device_private_init) is not available yet. */
++      ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
++                                       sflash->size;
++      ssb_sflash_dev.dev.platform_data = sflash;
++
 +      pr_err("Serial flash support is not implemented yet!\n");
 +
 +      return -ENOTSUPP;
                        /* Set dev to NULL to not unregister
                         * dev on error unwinding. */
                        sdev->dev = NULL;
-@@ -549,6 +545,14 @@ static int ssb_devices_register(struct s
+@@ -549,6 +545,22 @@ static int ssb_devices_register(struct s
                dev_idx++;
        }
  
 +      }
 +#endif
 +
++#ifdef CONFIG_SSB_SFLASH
++      if (bus->mipscore.sflash.present) {
++              err = platform_device_register(&ssb_sflash_dev);
++              if (err)
++                      pr_err("Error registering serial flash\n");
++      }
++#endif
++
        return 0;
  error:
        /* Unwind the already registered devices. */
-@@ -817,10 +821,9 @@ static int ssb_bus_register(struct ssb_b
+@@ -817,10 +829,9 @@ static int ssb_bus_register(struct ssb_b
        ssb_mipscore_init(&bus->mipscore);
        err = ssb_gpio_init(bus);
        if (err == -ENOTSUPP)
        err = ssb_fetch_invariants(bus, get_invariants);
        if (err) {
                ssb_bus_may_powerdown(bus);
-@@ -870,11 +873,11 @@ int ssb_bus_pcibus_register(struct ssb_b
+@@ -870,11 +881,11 @@ int ssb_bus_pcibus_register(struct ssb_b
  
        err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);
        if (!err) {
        }
  
        return err;
-@@ -895,8 +898,8 @@ int ssb_bus_pcmciabus_register(struct ss
+@@ -895,8 +906,8 @@ int ssb_bus_pcmciabus_register(struct ss
  
        err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr);
        if (!err) {
        }
  
        return err;
-@@ -917,8 +920,8 @@ int ssb_bus_sdiobus_register(struct ssb_
+@@ -917,8 +928,8 @@ int ssb_bus_sdiobus_register(struct ssb_
  
        err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0);
        if (!err) {
        }
  
        return err;
-@@ -936,8 +939,8 @@ int ssb_bus_ssbbus_register(struct ssb_b
+@@ -936,8 +947,8 @@ int ssb_bus_ssbbus_register(struct ssb_b
  
        err = ssb_bus_register(bus, get_invariants, baseaddr);
        if (!err) {
        }
  
        return err;
-@@ -1331,7 +1334,7 @@ out:
+@@ -1331,7 +1342,7 @@ out:
  #endif
        return err;
  error:
        goto out;
  }
  EXPORT_SYMBOL(ssb_bus_may_powerdown);
-@@ -1354,7 +1357,7 @@ int ssb_bus_powerup(struct ssb_bus *bus,
+@@ -1354,7 +1365,7 @@ int ssb_bus_powerup(struct ssb_bus *bus,
  
        return 0;
  error:
        return err;
  }
  EXPORT_SYMBOL(ssb_bus_powerup);
-@@ -1462,15 +1465,13 @@ static int __init ssb_modinit(void)
+@@ -1462,15 +1473,13 @@ static int __init ssb_modinit(void)
  
        err = b43_pci_ssb_bridge_init();
        if (err) {
                }
        }
        err = sprom_extract(bus, sprom, buf, bus->sprom_size);
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -38,7 +38,7 @@ static int ssb_pcihost_resume(struct pci
+       struct ssb_bus *ssb = pci_get_drvdata(dev);
+       int err;
+-      pci_set_power_state(dev, 0);
++      pci_set_power_state(dev, PCI_D0);
+       err = pci_enable_device(dev);
+       if (err)
+               return err;
 --- a/drivers/ssb/pcmcia.c
 +++ b/drivers/ssb/pcmcia.c
 @@ -143,7 +143,7 @@ int ssb_pcmcia_switch_coreidx(struct ssb
                        bus->pcicore.dev = dev;
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
+@@ -54,7 +54,7 @@ static int hex2sprom(u16 *sprom, const c
+       while (cnt < sprom_size_words) {
+               memcpy(tmp, dump, 4);
+               dump += 4;
+-              err = strict_strtoul(tmp, 16, &parsed);
++              err = kstrtoul(tmp, 16, &parsed);
+               if (err)
+                       return err;
+               sprom[cnt++] = swab16((u16)parsed);
 @@ -127,13 +127,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_
                goto out_kfree;
        err = ssb_devices_freeze(bus, &freeze);
  #endif
  
  #ifdef CONFIG_SSB_DEBUG
-@@ -217,6 +228,21 @@ extern u32 ssb_chipco_watchdog_timer_set
+@@ -217,6 +228,25 @@ extern u32 ssb_chipco_watchdog_timer_set
                                             u32 ticks);
  extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
  
 +extern struct platform_device ssb_pflash_dev;
 +#endif
 +
++#ifdef CONFIG_SSB_SFLASH
++extern struct platform_device ssb_sflash_dev;
++#endif
++
  #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);
  #endif /* LINUX_SSB_DRIVER_GIGE_H_ */
 --- a/include/linux/ssb/ssb_driver_mips.h
 +++ b/include/linux/ssb/ssb_driver_mips.h
-@@ -45,6 +45,11 @@ void ssb_mipscore_init(struct ssb_mipsco
+@@ -20,6 +20,18 @@ struct ssb_pflash {
+       u32 window_size;
+ };
++#ifdef CONFIG_SSB_SFLASH
++struct ssb_sflash {
++      bool present;
++      u32 window;
++      u32 blocksize;
++      u16 numblocks;
++      u32 size;
++
++      void *priv;
++};
++#endif
++
+ struct ssb_mipscore {
+       struct ssb_device *dev;
+@@ -27,6 +39,9 @@ struct ssb_mipscore {
+       struct ssb_serial_port serial_ports[4];
+       struct ssb_pflash pflash;
++#ifdef CONFIG_SSB_SFLASH
++      struct ssb_sflash sflash;
++#endif
+ };
+ extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
+@@ -45,6 +60,11 @@ void ssb_mipscore_init(struct ssb_mipsco
  {
  }
  
  #endif /* LINUX_SSB_MIPSCORE_H_ */
 --- a/include/linux/ssb/ssb_regs.h
 +++ b/include/linux/ssb/ssb_regs.h
-@@ -289,11 +289,11 @@
+@@ -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
+@@ -289,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 */
index 360ee71..7373c02 100644 (file)
@@ -9,9 +9,28 @@
                p->uartclk = bcma_port->baud_base;
                p->regshift = bcma_port->reg_shift;
                p->iotype = UPIO_MEM;
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -26,6 +26,7 @@ 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"
 --- a/drivers/bcma/bcma_private.h
 +++ b/drivers/bcma/bcma_private.h
-@@ -31,6 +31,8 @@ int __init bcma_bus_early_register(struc
+@@ -22,6 +22,8 @@
+ struct bcma_bus;
+ /* main.c */
++bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
++                   int timeout);
+ int 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,
+@@ -31,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
@@ -20,7 +39,7 @@
  
  /* scan.c */
  int bcma_bus_scan(struct bcma_bus *bus);
-@@ -45,6 +47,7 @@ int bcma_sprom_get(struct bcma_bus *bus)
+@@ -45,6 +49,7 @@ int bcma_sprom_get(struct bcma_bus *bus)
  /* driver_chipcommon.c */
  #ifdef CONFIG_BCMA_DRIVER_MIPS
  void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
  /* driver_chipcommon_pmu.c */
 --- a/drivers/bcma/core.c
 +++ b/drivers/bcma/core.c
-@@ -104,7 +104,13 @@ void bcma_core_pll_ctl(struct bcma_devic
+@@ -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,13 +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);
+@@ -43,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));
+@@ -104,7 +126,13 @@ void bcma_core_pll_ctl(struct bcma_devic
                if (i)
                        bcma_err(core->bus, "PLL enable timeout\n");
        } else {
  
  static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc)
  {
-@@ -213,6 +214,7 @@ u32 bcma_chipco_gpio_out(struct bcma_drv
+@@ -139,8 +140,15 @@ void bcma_core_chipcommon_init(struct bc
+       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)
+@@ -213,6 +221,7 @@ u32 bcma_chipco_gpio_out(struct bcma_drv
  
        return res;
  }
  
  u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
  {
-@@ -225,6 +227,7 @@ u32 bcma_chipco_gpio_outen(struct bcma_d
+@@ -225,6 +234,7 @@ u32 bcma_chipco_gpio_outen(struct bcma_d
  
        return res;
  }
  
  /*
   * If the bit is set to 0, chipcommon controlls this GPIO,
-@@ -329,7 +332,7 @@ void bcma_chipco_serial_init(struct bcma
+@@ -329,7 +339,7 @@ void bcma_chipco_serial_init(struct bcma
                return;
        }
  
        .num_resources  = 0,
 --- a/drivers/bcma/driver_chipcommon_pmu.c
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -174,19 +174,35 @@ u32 bcma_pmu_get_alp_clock(struct bcma_d
+@@ -56,6 +56,109 @@ void bcma_chipco_regctl_maskset(struct b
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
++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 BCMA_CHIP_ID_BCM43142:
++              if (xtalfreq == 0)
++                      xtalfreq = 20000;
++              bcma_pmu2_pll_init0(cc, xtalfreq);
++              break;
++      }
++}
++
+ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
+ {
+       struct bcma_bus *bus = cc->core->bus;
+@@ -66,6 +169,25 @@ static void bcma_pmu_resources_init(stru
+               min_msk = 0x200D;
+               max_msk = 0xFFFF;
+               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:
+               bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n",
+                          bus->chipinfo.id);
+@@ -165,6 +287,7 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+               bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+                            BCMA_CC_PMU_CTL_NOILPONW);
++      bcma_pmu_pll_init(cc);
+       bcma_pmu_resources_init(cc);
+       bcma_pmu_workarounds(cc);
+ }
+@@ -174,19 +297,35 @@ u32 bcma_pmu_get_alp_clock(struct bcma_d
        struct bcma_bus *bus = cc->core->bus;
  
        switch (bus->chipinfo.id) {
        default:
                bcma_warn(bus, "No ALP clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
                          bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
-@@ -264,7 +280,7 @@ static u32 bcma_pmu_pll_clock_bcm4706(st
+@@ -264,7 +403,7 @@ static u32 bcma_pmu_pll_clock_bcm4706(st
  }
  
  /* query bus clock frequency for PMU-enabled chipcommon */
  {
        struct bcma_bus *bus = cc->core->bus;
  
-@@ -293,6 +309,7 @@ static u32 bcma_pmu_get_bus_clock(struct
+@@ -293,6 +432,7 @@ static u32 bcma_pmu_get_bus_clock(struct
        }
        return BCMA_CC_PMU_HT_CLOCK;
  }
  
  /* query cpu clock frequency for PMU-enabled chipcommon */
  u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc)
-@@ -372,7 +389,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -372,7 +512,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
                bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
  
                break;
  
        case BCMA_CHIP_ID_BCM4331:
-@@ -393,7 +410,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -393,7 +533,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
                                                     0x03000a08);
                }
                break;
  
        case BCMA_CHIP_ID_BCM43224:
-@@ -426,7 +443,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -426,7 +566,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
                                                     0x88888815);
                }
                break;
  
        case BCMA_CHIP_ID_BCM4716:
-@@ -460,7 +477,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -460,7 +600,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                                                     0x88888815);
                }
  
                break;
  
        case BCMA_CHIP_ID_BCM43227:
-@@ -496,7 +513,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -496,7 +636,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
                                                     0x88888815);
                }
  static struct resource bcma_sflash_resource = {
        .name   = "bcma_sflash",
        .start  = BCMA_SOC_FLASH2,
+@@ -30,7 +30,7 @@ struct bcma_sflash_tbl_e {
+       u16 numblocks;
+ };
+-static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
+       { "M25P20", 0x11, 0x10000, 4, },
+       { "M25P40", 0x12, 0x10000, 8, },
+@@ -41,7 +41,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
+       { 0 },
+ };
+-static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
+       { "SST25WF512", 1, 0x1000, 16, },
+       { "SST25VF512", 0x48, 0x1000, 16, },
+       { "SST25WF010", 2, 0x1000, 32, },
+@@ -59,7 +59,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
+       { 0 },
+ };
+-static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
+       { "AT45DB011", 0xc, 256, 512, },
+       { "AT45DB021", 0x14, 256, 1024, },
+       { "AT45DB041", 0x1c, 256, 2048, },
+@@ -89,7 +89,7 @@ int bcma_sflash_init(struct bcma_drv_cc
+ {
+       struct bcma_bus *bus = cc->core->bus;
+       struct bcma_sflash *sflash = &cc->sflash;
+-      struct bcma_sflash_tbl_e *e;
++      const struct bcma_sflash_tbl_e *e;
+       u32 id, id2;
+       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 --- a/drivers/bcma/driver_gpio.c
 +++ b/drivers/bcma/driver_gpio.c
 @@ -73,6 +73,16 @@ static void bcma_gpio_free(struct gpio_c
 +      return bcma_core_irq(pc_host->pdev->core);
  }
  EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -275,6 +275,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
+       { 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, },
+ };
 --- a/drivers/bcma/main.c
 +++ b/drivers/bcma/main.c
 @@ -81,8 +81,8 @@ struct bcma_device *bcma_find_core(struc
  {
        struct bcma_device *core;
  
-@@ -120,6 +120,11 @@ static int bcma_register_cores(struct bc
+@@ -93,6 +93,25 @@ static struct bcma_device *bcma_find_cor
+       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)
+ {
+       struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+@@ -120,6 +139,11 @@ static int bcma_register_cores(struct bc
                        continue;
                }
  
                core->dev.release = bcma_release_core_dev;
                core->dev.bus = &bcma_bus_type;
                dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
-@@ -149,6 +154,14 @@ static int bcma_register_cores(struct bc
+@@ -149,6 +173,14 @@ static int bcma_register_cores(struct bc
                dev_id++;
        }
  
                err = platform_device_register(&bcma_sflash_dev);
 --- a/drivers/bcma/scan.c
 +++ b/drivers/bcma/scan.c
-@@ -137,19 +137,19 @@ static void bcma_scan_switch_core(struct
+@@ -84,6 +84,8 @@ static const struct bcma_device_id_name
+       { 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" },
+ };
+@@ -137,19 +139,19 @@ static void bcma_scan_switch_core(struct
                                       addr);
  }
  
  {
        u32 ent = bcma_erom_get_ent(bus, eromptr);
        if (!(ent & SCAN_ER_VALID))
-@@ -159,14 +159,14 @@ static s32 bcma_erom_get_ci(struct bcma_
+@@ -159,14 +161,14 @@ static s32 bcma_erom_get_ci(struct bcma_
        return ent;
  }
  
  {
        u32 ent = bcma_erom_get_ent(bus, eromptr);
        bcma_erom_push_ent(eromptr);
-@@ -175,7 +175,7 @@ static bool bcma_erom_is_bridge(struct b
+@@ -175,7 +177,7 @@ static bool bcma_erom_is_bridge(struct b
                ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
  }
  
  {
        u32 ent;
        while (1) {
-@@ -189,7 +189,7 @@ static void bcma_erom_skip_component(str
+@@ -189,7 +191,7 @@ static void bcma_erom_skip_component(str
        bcma_erom_push_ent(eromptr);
  }
  
  {
        u32 ent = bcma_erom_get_ent(bus, eromptr);
        if (!(ent & SCAN_ER_VALID))
-@@ -199,7 +199,7 @@ static s32 bcma_erom_get_mst_port(struct
+@@ -199,7 +201,7 @@ static s32 bcma_erom_get_mst_port(struct
        return ent;
  }
  
        u32 addrl, addrh, sizel, sizeh = 0;
 --- a/drivers/bcma/sprom.c
 +++ b/drivers/bcma/sprom.c
-@@ -217,6 +217,7 @@ static void bcma_sprom_extract_r8(struct
+@@ -72,12 +72,12 @@ fail:
+  * R/W ops.
+  **************************************************/
+-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));
+ }
+ /**************************************************
+@@ -124,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;
+@@ -154,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;
+ }
+@@ -208,15 +212,13 @@ static void bcma_sprom_extract_r8(struct
+       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;
+-
+       for (i = 0; i < 3; i++) {
+               v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
+               *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
        }
  
        SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
  
        SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
             SSB_SPROM4_TXPID2G0_SHIFT);
+@@ -501,7 +503,7 @@ static bool bcma_sprom_onchip_available(
+       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 */
+@@ -549,7 +551,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ {
+       u16 offset = BCMA_CC_SPROM;
+       u16 *sprom;
+-      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;
+@@ -578,32 +582,37 @@ int bcma_sprom_get(struct bcma_bus *bus)
+               }
+       }
+-      sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+-                      GFP_KERNEL);
+-      if (!sprom)
+-              return -ENOMEM;
+-
+       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, false);
+       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;
++
++              kfree(sprom);
++      }
+       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);
+-      err = bcma_sprom_valid(sprom);
+       if (err) {
+-              bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
++              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);
+-              goto out;
++      } else {
++              bcma_sprom_extract_r8(bus, sprom);
++              kfree(sprom);
+       }
+-      bcma_sprom_extract_r8(bus, sprom);
+-
+-out:
+-      kfree(sprom);
+       return err;
+ }
 --- a/include/linux/bcma/bcma.h
 +++ b/include/linux/bcma/bcma.h
-@@ -134,6 +134,7 @@ struct bcma_host_ops {
+@@ -134,12 +134,17 @@ 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_ARM_CR4             0x83e
++#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
-@@ -173,6 +174,60 @@ struct bcma_host_ops {
+ /* 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
+@@ -173,6 +178,60 @@ struct bcma_host_ops {
  #define BCMA_CHIP_ID_BCM53572 53572
  #define  BCMA_PKG_ID_BCM47188 9
  
  #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 */
-@@ -528,6 +532,7 @@ struct bcma_sflash {
+@@ -326,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 */
+@@ -351,6 +357,11 @@
+ #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 */
+ /* NAND flash MLC controller registers (corerev >= 38) */
+ #define BCMA_CC_NAND_REVISION         0x0C00
+@@ -431,6 +442,23 @@
+ #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
+ /* HT clock for systems with PMU-enabled chipcommon */
+@@ -503,6 +531,37 @@
+ #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)
+  */
+@@ -528,6 +587,7 @@ struct bcma_sflash {
        u32 size;
  
        struct mtd_info *mtd;
  };
  #endif
  
-@@ -606,6 +611,8 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
+@@ -606,6 +666,8 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
  
  extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
  
  void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value);
  
  u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask);
-@@ -634,4 +641,6 @@ extern void bcma_chipco_regctl_maskset(s
+@@ -634,4 +696,6 @@ 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);
  
index c87c2f6..9908d69 100644 (file)
@@ -1,3 +1,14 @@
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -144,7 +144,7 @@ config SSB_SFLASH
+ # Assumption: We are on embedded, if we compile the MIPS core.
+ config SSB_EMBEDDED
+       bool
+-      depends on SSB_DRIVER_MIPS
++      depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
+       default y
+ config SSB_DRIVER_EXTIF
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
 @@ -354,7 +354,7 @@ void ssb_chipcommon_init(struct ssb_chip
        default:
                ssb_printk(KERN_ERR PFX
                           "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
+--- a/drivers/ssb/driver_chipcommon_sflash.c
++++ b/drivers/ssb/driver_chipcommon_sflash.c
+@@ -9,6 +9,19 @@
+ #include "ssb_private.h"
++static struct resource ssb_sflash_resource = {
++      .name   = "ssb_sflash",
++      .start  = SSB_FLASH2,
++      .end    = 0,
++      .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
++};
++
++struct platform_device ssb_sflash_dev = {
++      .name           = "ssb_sflash",
++      .resource       = &ssb_sflash_resource,
++      .num_resources  = 1,
++};
++
+ struct ssb_sflash_tbl_e {
+       char *name;
+       u32 id;
+@@ -16,7 +29,7 @@ struct ssb_sflash_tbl_e {
+       u16 numblocks;
+ };
+-static struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
++static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
+       { "M25P20", 0x11, 0x10000, 4, },
+       { "M25P40", 0x12, 0x10000, 8, },
+@@ -27,7 +40,7 @@ static struct ssb_sflash_tbl_e ssb_sflas
+       { 0 },
+ };
+-static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
++static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
+       { "SST25WF512", 1, 0x1000, 16, },
+       { "SST25VF512", 0x48, 0x1000, 16, },
+       { "SST25WF010", 2, 0x1000, 32, },
+@@ -45,7 +58,7 @@ static struct ssb_sflash_tbl_e ssb_sflas
+       { 0 },
+ };
+-static struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
++static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
+       { "AT45DB011", 0xc, 256, 512, },
+       { "AT45DB021", 0x14, 256, 1024, },
+       { "AT45DB041", 0x1c, 256, 2048, },
+@@ -73,7 +86,8 @@ static void ssb_sflash_cmd(struct ssb_ch
+ /* Initialize serial flash access */
+ int ssb_sflash_init(struct ssb_chipcommon *cc)
+ {
+-      struct ssb_sflash_tbl_e *e;
++      struct ssb_sflash *sflash = &cc->dev->bus->mipscore.sflash;
++      const struct ssb_sflash_tbl_e *e;
+       u32 id, id2;
+       switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
+@@ -131,9 +145,21 @@ int ssb_sflash_init(struct ssb_chipcommo
+               return -ENOTSUPP;
+       }
++      sflash->window = SSB_FLASH2;
++      sflash->blocksize = e->blocksize;
++      sflash->numblocks = e->numblocks;
++      sflash->size = sflash->blocksize * sflash->numblocks;
++      sflash->present = true;
++
+       pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
+               e->name, e->blocksize, e->numblocks);
++      /* Prepare platform device, but don't register it yet. It's too early,
++       * malloc (required by device_private_init) is not available yet. */
++      ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
++                                       sflash->size;
++      ssb_sflash_dev.dev.platform_data = sflash;
++
+       pr_err("Serial flash support is not implemented yet!\n");
+       return -ENOTSUPP;
 --- a/drivers/ssb/driver_mipscore.c
 +++ b/drivers/ssb/driver_mipscore.c
 @@ -167,21 +167,22 @@ static void set_irq(struct ssb_device *d
                        /* Set dev to NULL to not unregister
                         * dev on error unwinding. */
                        sdev->dev = NULL;
-@@ -825,10 +821,9 @@ static int ssb_bus_register(struct ssb_b
+@@ -557,6 +553,14 @@ static int ssb_devices_register(struct s
+       }
+ #endif
++#ifdef CONFIG_SSB_SFLASH
++      if (bus->mipscore.sflash.present) {
++              err = platform_device_register(&ssb_sflash_dev);
++              if (err)
++                      pr_err("Error registering serial flash\n");
++      }
++#endif
++
+       return 0;
+ error:
+       /* Unwind the already registered devices. */
+@@ -825,10 +829,9 @@ static int ssb_bus_register(struct ssb_b
        ssb_mipscore_init(&bus->mipscore);
        err = ssb_gpio_init(bus);
        if (err == -ENOTSUPP)
        err = ssb_fetch_invariants(bus, get_invariants);
        if (err) {
                ssb_bus_may_powerdown(bus);
-@@ -878,11 +873,11 @@ int ssb_bus_pcibus_register(struct ssb_b
+@@ -878,11 +881,11 @@ int ssb_bus_pcibus_register(struct ssb_b
  
        err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);
        if (!err) {
        }
  
        return err;
-@@ -903,8 +898,8 @@ int ssb_bus_pcmciabus_register(struct ss
+@@ -903,8 +906,8 @@ int ssb_bus_pcmciabus_register(struct ss
  
        err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr);
        if (!err) {
        }
  
        return err;
-@@ -925,8 +920,8 @@ int ssb_bus_sdiobus_register(struct ssb_
+@@ -925,8 +928,8 @@ int ssb_bus_sdiobus_register(struct ssb_
  
        err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0);
        if (!err) {
        }
  
        return err;
-@@ -944,8 +939,8 @@ int ssb_bus_ssbbus_register(struct ssb_b
+@@ -944,8 +947,8 @@ int ssb_bus_ssbbus_register(struct ssb_b
  
        err = ssb_bus_register(bus, get_invariants, baseaddr);
        if (!err) {
        }
  
        return err;
-@@ -1339,7 +1334,7 @@ out:
+@@ -1339,7 +1342,7 @@ out:
  #endif
        return err;
  error:
        goto out;
  }
  EXPORT_SYMBOL(ssb_bus_may_powerdown);
-@@ -1362,7 +1357,7 @@ int ssb_bus_powerup(struct ssb_bus *bus,
+@@ -1362,7 +1365,7 @@ int ssb_bus_powerup(struct ssb_bus *bus,
  
        return 0;
  error:
        return err;
  }
  EXPORT_SYMBOL(ssb_bus_powerup);
-@@ -1470,15 +1465,13 @@ static int __init ssb_modinit(void)
+@@ -1470,15 +1473,13 @@ static int __init ssb_modinit(void)
  
        err = b43_pci_ssb_bridge_init();
        if (err) {
                }
        }
        err = sprom_extract(bus, sprom, buf, bus->sprom_size);
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -38,7 +38,7 @@ static int ssb_pcihost_resume(struct pci
+       struct ssb_bus *ssb = pci_get_drvdata(dev);
+       int err;
+-      pci_set_power_state(dev, 0);
++      pci_set_power_state(dev, PCI_D0);
+       err = pci_enable_device(dev);
+       if (err)
+               return err;
 --- a/drivers/ssb/pcmcia.c
 +++ b/drivers/ssb/pcmcia.c
 @@ -143,7 +143,7 @@ int ssb_pcmcia_switch_coreidx(struct ssb
                        bus->pcicore.dev = dev;
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
+@@ -54,7 +54,7 @@ static int hex2sprom(u16 *sprom, const c
+       while (cnt < sprom_size_words) {
+               memcpy(tmp, dump, 4);
+               dump += 4;
+-              err = strict_strtoul(tmp, 16, &parsed);
++              err = kstrtoul(tmp, 16, &parsed);
+               if (err)
+                       return err;
+               sprom[cnt++] = swab16((u16)parsed);
 @@ -127,13 +127,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_
                goto out_kfree;
        err = ssb_devices_freeze(bus, &freeze);
  #endif
  
  #ifdef CONFIG_SSB_DEBUG
+@@ -232,6 +243,10 @@ static inline int ssb_sflash_init(struct
+ extern struct platform_device ssb_pflash_dev;
+ #endif
++#ifdef CONFIG_SSB_SFLASH
++extern struct platform_device ssb_sflash_dev;
++#endif
++
+ #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);
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
 @@ -26,9 +26,9 @@ struct ssb_sprom_core_pwr_info {
  /* chip_package */
  #define SSB_CHIPPACK_BCM4712S 1       /* Small 200pin 4712 */
  #define SSB_CHIPPACK_BCM4712M 2       /* Medium 225pin 4712 */
+--- a/include/linux/ssb/ssb_driver_mips.h
++++ b/include/linux/ssb/ssb_driver_mips.h
+@@ -20,6 +20,18 @@ struct ssb_pflash {
+       u32 window_size;
+ };
++#ifdef CONFIG_SSB_SFLASH
++struct ssb_sflash {
++      bool present;
++      u32 window;
++      u32 blocksize;
++      u16 numblocks;
++      u32 size;
++
++      void *priv;
++};
++#endif
++
+ struct ssb_mipscore {
+       struct ssb_device *dev;
+@@ -27,6 +39,9 @@ struct ssb_mipscore {
+       struct ssb_serial_port serial_ports[4];
+       struct ssb_pflash pflash;
++#ifdef CONFIG_SSB_SFLASH
++      struct ssb_sflash sflash;
++#endif
+ };
+ extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
 --- a/include/linux/ssb/ssb_regs.h
 +++ b/include/linux/ssb/ssb_regs.h
-@@ -289,11 +289,11 @@
+@@ -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
+@@ -289,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 */
index a1a1ebc..04a4573 100644 (file)
@@ -1,6 +1,80 @@
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -26,6 +26,7 @@ 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"
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -22,6 +22,8 @@
+ struct bcma_bus;
+ /* main.c */
++bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
++                   int timeout);
+ int 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,
 --- a/drivers/bcma/core.c
 +++ b/drivers/bcma/core.c
-@@ -104,7 +104,13 @@ void bcma_core_pll_ctl(struct bcma_devic
+@@ -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,13 +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);
+@@ -43,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));
+@@ -104,7 +126,13 @@ void bcma_core_pll_ctl(struct bcma_devic
                if (i)
                        bcma_err(core->bus, "PLL enable timeout\n");
        } else {
  
  static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc)
  {
-@@ -213,6 +214,7 @@ u32 bcma_chipco_gpio_out(struct bcma_drv
+@@ -139,8 +140,15 @@ void bcma_core_chipcommon_init(struct bc
+       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)
+@@ -213,6 +221,7 @@ u32 bcma_chipco_gpio_out(struct bcma_drv
  
        return res;
  }
  
  u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
  {
-@@ -225,6 +227,7 @@ u32 bcma_chipco_gpio_outen(struct bcma_d
+@@ -225,6 +234,7 @@ u32 bcma_chipco_gpio_outen(struct bcma_d
  
        return res;
  }
   * If the bit is set to 0, chipcommon controlls this GPIO,
 --- a/drivers/bcma/driver_chipcommon_pmu.c
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -174,19 +174,35 @@ u32 bcma_pmu_get_alp_clock(struct bcma_d
+@@ -56,6 +56,109 @@ void bcma_chipco_regctl_maskset(struct b
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
++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 BCMA_CHIP_ID_BCM43142:
++              if (xtalfreq == 0)
++                      xtalfreq = 20000;
++              bcma_pmu2_pll_init0(cc, xtalfreq);
++              break;
++      }
++}
++
+ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
+ {
+       struct bcma_bus *bus = cc->core->bus;
+@@ -66,6 +169,25 @@ static void bcma_pmu_resources_init(stru
+               min_msk = 0x200D;
+               max_msk = 0xFFFF;
+               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:
+               bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n",
+                          bus->chipinfo.id);
+@@ -165,6 +287,7 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+               bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+                            BCMA_CC_PMU_CTL_NOILPONW);
++      bcma_pmu_pll_init(cc);
+       bcma_pmu_resources_init(cc);
+       bcma_pmu_workarounds(cc);
+ }
+@@ -174,19 +297,35 @@ u32 bcma_pmu_get_alp_clock(struct bcma_d
        struct bcma_bus *bus = cc->core->bus;
  
        switch (bus->chipinfo.id) {
        default:
                bcma_warn(bus, "No ALP clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
                          bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
-@@ -373,7 +389,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -373,7 +512,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
                bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
  
                break;
  
        case BCMA_CHIP_ID_BCM4331:
-@@ -394,7 +410,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -394,7 +533,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
                                                     0x03000a08);
                }
                break;
  
        case BCMA_CHIP_ID_BCM43224:
-@@ -427,7 +443,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -427,7 +566,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
                                                     0x88888815);
                }
                break;
  
        case BCMA_CHIP_ID_BCM4716:
-@@ -461,7 +477,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -461,7 +600,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                                                     0x88888815);
                }
  
                break;
  
        case BCMA_CHIP_ID_BCM43227:
-@@ -497,7 +513,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+@@ -497,7 +636,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
                        bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
                                                     0x88888815);
                }
                break;
        default:
                bcma_err(bus, "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
+--- a/drivers/bcma/driver_chipcommon_sflash.c
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -30,7 +30,7 @@ struct bcma_sflash_tbl_e {
+       u16 numblocks;
+ };
+-static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
+       { "M25P20", 0x11, 0x10000, 4, },
+       { "M25P40", 0x12, 0x10000, 8, },
+@@ -41,7 +41,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
+       { 0 },
+ };
+-static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
+       { "SST25WF512", 1, 0x1000, 16, },
+       { "SST25VF512", 0x48, 0x1000, 16, },
+       { "SST25WF010", 2, 0x1000, 32, },
+@@ -59,7 +59,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
+       { 0 },
+ };
+-static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
+       { "AT45DB011", 0xc, 256, 512, },
+       { "AT45DB021", 0x14, 256, 1024, },
+       { "AT45DB041", 0x1c, 256, 2048, },
+@@ -89,7 +89,7 @@ int bcma_sflash_init(struct bcma_drv_cc
+ {
+       struct bcma_bus *bus = cc->core->bus;
+       struct bcma_sflash *sflash = &cc->sflash;
+-      struct bcma_sflash_tbl_e *e;
++      const struct bcma_sflash_tbl_e *e;
+       u32 id, id2;
+       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -275,6 +275,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
+       { 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, },
+ };
 --- a/drivers/bcma/main.c
 +++ b/drivers/bcma/main.c
-@@ -120,6 +120,11 @@ static int bcma_register_cores(struct bc
+@@ -93,6 +93,25 @@ struct bcma_device *bcma_find_core_unit(
+       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)
+ {
+       struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+@@ -120,6 +139,11 @@ static int bcma_register_cores(struct bc
                        continue;
                }
  
                dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
 --- a/drivers/bcma/scan.c
 +++ b/drivers/bcma/scan.c
-@@ -137,19 +137,19 @@ static void bcma_scan_switch_core(struct
+@@ -84,6 +84,8 @@ static const struct bcma_device_id_name
+       { 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" },
+ };
+@@ -137,19 +139,19 @@ static void bcma_scan_switch_core(struct
                                       addr);
  }
  
  {
        u32 ent = bcma_erom_get_ent(bus, eromptr);
        if (!(ent & SCAN_ER_VALID))
-@@ -159,14 +159,14 @@ static s32 bcma_erom_get_ci(struct bcma_
+@@ -159,14 +161,14 @@ static s32 bcma_erom_get_ci(struct bcma_
        return ent;
  }
  
  {
        u32 ent = bcma_erom_get_ent(bus, eromptr);
        bcma_erom_push_ent(eromptr);
-@@ -175,7 +175,7 @@ static bool bcma_erom_is_bridge(struct b
+@@ -175,7 +177,7 @@ static bool bcma_erom_is_bridge(struct b
                ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
  }
  
  {
        u32 ent;
        while (1) {
-@@ -189,7 +189,7 @@ static void bcma_erom_skip_component(str
+@@ -189,7 +191,7 @@ static void bcma_erom_skip_component(str
        bcma_erom_push_ent(eromptr);
  }
  
  {
        u32 ent = bcma_erom_get_ent(bus, eromptr);
        if (!(ent & SCAN_ER_VALID))
-@@ -199,7 +199,7 @@ static s32 bcma_erom_get_mst_port(struct
+@@ -199,7 +201,7 @@ static s32 bcma_erom_get_mst_port(struct
        return ent;
  }
  
        u32 addrl, addrh, sizel, sizeh = 0;
 --- a/drivers/bcma/sprom.c
 +++ b/drivers/bcma/sprom.c
-@@ -217,6 +217,7 @@ static void bcma_sprom_extract_r8(struct
+@@ -72,12 +72,12 @@ fail:
+  * R/W ops.
+  **************************************************/
+-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));
+ }
+ /**************************************************
+@@ -124,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;
+@@ -154,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;
+ }
+@@ -208,15 +212,13 @@ static void bcma_sprom_extract_r8(struct
+       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;
+-
+       for (i = 0; i < 3; i++) {
+               v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
+               *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
        }
  
        SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
  
        SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
             SSB_SPROM4_TXPID2G0_SHIFT);
+@@ -501,7 +503,7 @@ static bool bcma_sprom_onchip_available(
+       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 */
+@@ -549,7 +551,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ {
+       u16 offset = BCMA_CC_SPROM;
+       u16 *sprom;
+-      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;
+@@ -578,32 +582,37 @@ int bcma_sprom_get(struct bcma_bus *bus)
+               }
+       }
+-      sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+-                      GFP_KERNEL);
+-      if (!sprom)
+-              return -ENOMEM;
+-
+       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, false);
+       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;
++
++              kfree(sprom);
++      }
+       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);
+-      err = bcma_sprom_valid(sprom);
+       if (err) {
+-              bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
++              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);
+-              goto out;
++      } else {
++              bcma_sprom_extract_r8(bus, sprom);
++              kfree(sprom);
+       }
+-      bcma_sprom_extract_r8(bus, sprom);
+-
+-out:
+-      kfree(sprom);
+       return err;
+ }
 --- a/include/linux/bcma/bcma.h
 +++ b/include/linux/bcma/bcma.h
-@@ -134,6 +134,7 @@ struct bcma_host_ops {
+@@ -134,12 +134,17 @@ 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_ARM_CR4             0x83e
++#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
-@@ -173,6 +174,60 @@ struct bcma_host_ops {
+ /* 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
+@@ -173,6 +178,60 @@ struct bcma_host_ops {
  #define BCMA_CHIP_ID_BCM53572 53572
  #define  BCMA_PKG_ID_BCM47188 9
  
  #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 */
-@@ -607,6 +611,8 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
+@@ -326,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 */
+@@ -351,6 +357,11 @@
+ #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 */
+ /* NAND flash MLC controller registers (corerev >= 38) */
+ #define BCMA_CC_NAND_REVISION         0x0C00
+@@ -431,6 +442,23 @@
+ #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
+ /* HT clock for systems with PMU-enabled chipcommon */
+@@ -503,6 +531,37 @@
+ #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)
+  */
+@@ -607,6 +666,8 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
  
  extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);