From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Thu, 29 May 2014 19:25:40 +0000 (+0000)
Subject: bcm53xx: add support for the PCIe controller
X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=cdc7ea333719e9896da1440f6bf0f0178023797e;p=openwrt%2Fstaging%2Fynezz.git

bcm53xx: add support for the PCIe controller

This patch adds support for the PCIe controller
In addition to the PCIe controller a sprom is now provided by a device
tree driver to bcma from some nvram.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

SVN-Revision: 40880
---

diff --git a/target/linux/bcm53xx/config-3.14 b/target/linux/bcm53xx/config-3.14
index e4f27a4e20..48759e964b 100644
--- a/target/linux/bcm53xx/config-3.14
+++ b/target/linux/bcm53xx/config-3.14
@@ -40,6 +40,8 @@ CONFIG_B53=y
 # CONFIG_B53_MMAP_DRIVER is not set
 # CONFIG_B53_PHY_DRIVER is not set
 CONFIG_B53_SRAB_DRIVER=y
+CONFIG_BCM47XX_NVRAM=y
+CONFIG_BCM53XX_SPROM=y
 CONFIG_BCMA=y
 CONFIG_BCMA_BLOCKIO=y
 CONFIG_BCMA_DEBUG=y
@@ -188,6 +190,8 @@ CONFIG_OUTER_CACHE_SYNC=y
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PCI=y
+CONFIG_PCI_BCMA=y
+CONFIG_PCI_DOMAINS=y
 CONFIG_PERF_USE_VMALLOC=y
 CONFIG_PHYLIB=y
 # CONFIG_PL310_ERRATA_588369 is not set
diff --git a/target/linux/bcm53xx/patches-3.14/052-bcm53xx-register-bcma-bus.patch b/target/linux/bcm53xx/patches-3.14/052-bcm53xx-register-bcma-bus.patch
deleted file mode 100644
index aa2414df84..0000000000
--- a/target/linux/bcm53xx/patches-3.14/052-bcm53xx-register-bcma-bus.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 22b90bcf616578abe09845c72317ce53312f7faf Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 25 Jan 2014 17:03:07 +0100
-Subject: [PATCH 8/8] ARM: BCM5301X: register bcma bus
-
----
- arch/arm/boot/dts/bcm4708.dtsi |   43 ++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 43 insertions(+)
-
---- a/arch/arm/boot/dts/bcm4708.dtsi
-+++ b/arch/arm/boot/dts/bcm4708.dtsi
-@@ -31,4 +31,47 @@
- 		};
- 	};
- 
-+	aix@18000000 {
-+		compatible = "brcm,bus-aix";
-+		reg = <0x18000000 0x1000>;
-+		ranges = <0x00000000 0x18000000 0x00100000>;
-+		#address-cells = <1>;
-+		#size-cells = <1>;
-+
-+		usb2@0 {
-+			compatible = "brcm,northstar-usb2";
-+			reg = <0x18021000 0x1000>;
-+			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
-+		};
-+
-+		usb3@0 {
-+			compatible = "brcm,northstar-usb3";
-+			reg = <0x18023000 0x1000>;
-+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
-+		};
-+
-+		gmac@0 {
-+			compatible = "brcm,northstar-gmac";
-+			reg = <0x18024000 0x1000>;
-+			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
-+		};
-+
-+		gmac@1 {
-+			compatible = "brcm,northstar-gmac";
-+			reg = <0x18025000 0x1000>;
-+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-+		};
-+
-+		gmac@2 {
-+			compatible = "brcm,northstar-gmac";
-+			reg = <0x18026000 0x1000>;
-+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
-+		};
-+
-+		gmac@3 {
-+			compatible = "brcm,northstar-gmac";
-+			reg = <0x18027000 0x1000>;
-+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
-+		};
-+	};
- };
diff --git a/target/linux/bcm53xx/patches-3.14/110-bcm47xx-move-the-nvram-header-file-into-common-space.patch b/target/linux/bcm53xx/patches-3.14/110-bcm47xx-move-the-nvram-header-file-into-common-space.patch
new file mode 100644
index 0000000000..85b9ab38bd
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/110-bcm47xx-move-the-nvram-header-file-into-common-space.patch
@@ -0,0 +1,270 @@
+From bd489dfe8c0d7495645cbc8b8c283217ba816fab Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 4 May 2014 16:35:42 +0200
+Subject: [PATCH 02/15] bcm47xx: move the nvram header file into common space
+
+Moving mach-bcm47xx/bcm47xx_nvram.h makes it possible to reuse this
+header on the arm bcm47xx (BCM5301X) devices. This way a driver gets
+the correct functions to access the nvram depending on the SoC it boots
+for.
+---
+ arch/mips/bcm47xx/board.c                          |  2 +-
+ arch/mips/bcm47xx/nvram.c                          |  2 +-
+ arch/mips/bcm47xx/setup.c                          |  2 +-
+ arch/mips/bcm47xx/sprom.c                          |  2 +-
+ arch/mips/bcm47xx/time.c                           |  2 +-
+ arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h | 53 ------------------
+ drivers/net/ethernet/broadcom/b44.c                |  8 +--
+ drivers/net/ethernet/broadcom/bgmac.c              |  2 +-
+ drivers/ssb/driver_chipcommon_pmu.c                |  6 +-
+ include/linux/bcm47xx_nvram.h                      | 65 ++++++++++++++++++++++
+ 10 files changed, 73 insertions(+), 71 deletions(-)
+ delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
+ create mode 100644 include/linux/bcm47xx_nvram.h
+
+--- a/arch/mips/bcm47xx/board.c
++++ b/arch/mips/bcm47xx/board.c
+@@ -2,7 +2,7 @@
+ #include <linux/export.h>
+ #include <linux/string.h>
+ #include <bcm47xx_board.h>
+-#include <bcm47xx_nvram.h>
++#include <linux/bcm47xx_nvram.h>
+ 
+ struct bcm47xx_board_type {
+ 	const enum bcm47xx_board board;
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -17,7 +17,7 @@
+ #include <linux/kernel.h>
+ #include <linux/string.h>
+ #include <asm/addrspace.h>
+-#include <bcm47xx_nvram.h>
++#include <linux/bcm47xx_nvram.h>
+ #include <asm/mach-bcm47xx/bcm47xx.h>
+ 
+ static char nvram_buf[NVRAM_SPACE];
+--- a/arch/mips/bcm47xx/setup.c
++++ b/arch/mips/bcm47xx/setup.c
+@@ -42,7 +42,7 @@
+ #include <asm/reboot.h>
+ #include <asm/time.h>
+ #include <bcm47xx.h>
+-#include <bcm47xx_nvram.h>
++#include <linux/bcm47xx_nvram.h>
+ #include <bcm47xx_board.h>
+ 
+ union bcm47xx_bus bcm47xx_bus;
+--- a/arch/mips/bcm47xx/sprom.c
++++ b/arch/mips/bcm47xx/sprom.c
+@@ -27,7 +27,7 @@
+  */
+ 
+ #include <bcm47xx.h>
+-#include <bcm47xx_nvram.h>
++#include <linux/bcm47xx_nvram.h>
+ 
+ static void create_key(const char *prefix, const char *postfix,
+ 		       const char *name, char *buf, int len)
+--- a/arch/mips/bcm47xx/time.c
++++ b/arch/mips/bcm47xx/time.c
+@@ -27,7 +27,7 @@
+ #include <linux/ssb/ssb.h>
+ #include <asm/time.h>
+ #include <bcm47xx.h>
+-#include <bcm47xx_nvram.h>
++#include <linux/bcm47xx_nvram.h>
+ #include <bcm47xx_board.h>
+ 
+ void __init plat_time_init(void)
+--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/*
+- *  Copyright (C) 2005, Broadcom Corporation
+- *  Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
+- *
+- *  This program is free software; you can redistribute  it and/or modify it
+- *  under  the terms of  the GNU General  Public License as published by the
+- *  Free Software Foundation;  either version 2 of the  License, or (at your
+- *  option) any later version.
+- */
+-
+-#ifndef __BCM47XX_NVRAM_H
+-#define __BCM47XX_NVRAM_H
+-
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-
+-struct nvram_header {
+-	u32 magic;
+-	u32 len;
+-	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+-	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
+-	u32 config_ncdl;	/* ncdl values for memc */
+-};
+-
+-#define NVRAM_HEADER		0x48534C46	/* 'FLSH' */
+-#define NVRAM_VERSION		1
+-#define NVRAM_HEADER_SIZE	20
+-#define NVRAM_SPACE		0x8000
+-
+-#define FLASH_MIN		0x00020000	/* Minimum flash size */
+-
+-#define NVRAM_MAX_VALUE_LEN 255
+-#define NVRAM_MAX_PARAM_LEN 64
+-
+-extern int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len);
+-
+-static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
+-{
+-	if (strchr(buf, ':'))
+-		sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
+-			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+-			&macaddr[5]);
+-	else if (strchr(buf, '-'))
+-		sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
+-			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+-			&macaddr[5]);
+-	else
+-		printk(KERN_WARNING "Can not parse mac address: %s\n", buf);
+-}
+-
+-int bcm47xx_nvram_gpio_pin(const char *name);
+-
+-#endif /* __BCM47XX_NVRAM_H */
+--- a/drivers/net/ethernet/broadcom/b44.c
++++ b/drivers/net/ethernet/broadcom/b44.c
+@@ -31,6 +31,7 @@
+ #include <linux/ssb/ssb.h>
+ #include <linux/slab.h>
+ #include <linux/phy.h>
++#include <linux/bcm47xx_nvram.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+@@ -399,8 +400,6 @@ static void b44_set_flow_ctrl(struct b44
+ 	__b44_set_flow_ctrl(bp, pause_enab);
+ }
+ 
+-#ifdef CONFIG_BCM47XX
+-#include <bcm47xx_nvram.h>
+ static void b44_wap54g10_workaround(struct b44 *bp)
+ {
+ 	char buf[20];
+@@ -429,11 +428,6 @@ static void b44_wap54g10_workaround(stru
+ error:
+ 	pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
+ }
+-#else
+-static inline void b44_wap54g10_workaround(struct b44 *bp)
+-{
+-}
+-#endif
+ 
+ static int b44_setup_phy(struct b44 *bp)
+ {
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -17,7 +17,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/platform_data/b53.h>
+-#include <bcm47xx_nvram.h>
++#include <linux/bcm47xx_nvram.h>
+ 
+ static const struct bcma_device_id bgmac_bcma_tbl[] = {
+ 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
+--- a/drivers/ssb/driver_chipcommon_pmu.c
++++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -13,9 +13,7 @@
+ #include <linux/ssb/ssb_driver_chipcommon.h>
+ #include <linux/delay.h>
+ #include <linux/export.h>
+-#ifdef CONFIG_BCM47XX
+-#include <bcm47xx_nvram.h>
+-#endif
++#include <linux/bcm47xx_nvram.h>
+ 
+ #include "ssb_private.h"
+ 
+@@ -320,11 +318,9 @@ static void ssb_pmu_pll_init(struct ssb_
+ 	u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */
+ 
+ 	if (bus->bustype == SSB_BUSTYPE_SSB) {
+-#ifdef CONFIG_BCM47XX
+ 		char buf[20];
+ 		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
+ 			crystalfreq = simple_strtoul(buf, NULL, 0);
+-#endif
+ 	}
+ 
+ 	switch (bus->chip_id) {
+--- /dev/null
++++ b/include/linux/bcm47xx_nvram.h
+@@ -0,0 +1,65 @@
++/*
++ *  Copyright (C) 2005, Broadcom Corporation
++ *  Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
++ *  Copyright (C) 2014 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ *  This program is free software; you can redistribute  it and/or modify it
++ *  under  the terms of  the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the  License, or (at your
++ *  option) any later version.
++ */
++
++#ifndef __BCM47XX_NVRAM_H
++#define __BCM47XX_NVRAM_H
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++struct nvram_header {
++	u32 magic;
++	u32 len;
++	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
++	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
++	u32 config_ncdl;	/* ncdl values for memc */
++};
++
++#define NVRAM_HEADER		0x48534C46	/* 'FLSH' */
++#define NVRAM_VERSION		1
++#define NVRAM_HEADER_SIZE	20
++#define NVRAM_SPACE		0x8000
++
++#define FLASH_MIN		0x00020000	/* Minimum flash size */
++
++#define NVRAM_MAX_VALUE_LEN 255
++#define NVRAM_MAX_PARAM_LEN 64
++
++#ifdef CONFIG_BCM47XX
++int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
++
++int bcm47xx_nvram_gpio_pin(const char *name);
++#else
++static inline int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
++{
++	return -ENXIO;
++}
++
++static inline int bcm47xx_nvram_gpio_pin(const char *name)
++{
++	return -ENXIO;
++}
++#endif
++
++static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
++{
++	if (strchr(buf, ':'))
++		sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
++			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
++			&macaddr[5]);
++	else if (strchr(buf, '-'))
++		sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
++			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
++			&macaddr[5]);
++	else
++		pr_warn("Can not parse mac address: %s\n", buf);
++}
++#endif /* __BCM47XX_NVRAM_H */
diff --git a/target/linux/bcm53xx/patches-3.14/111-bcm47xx-nvram-add-new-nvram-driver-with-dt-support.patch b/target/linux/bcm53xx/patches-3.14/111-bcm47xx-nvram-add-new-nvram-driver-with-dt-support.patch
new file mode 100644
index 0000000000..a53e86d4b5
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/111-bcm47xx-nvram-add-new-nvram-driver-with-dt-support.patch
@@ -0,0 +1,520 @@
+From 60a413ed5bc7917f1612df441240f458163b10c1 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 3 May 2014 22:54:59 +0200
+Subject: [PATCH 03/15] bcm47xx-nvram: add new nvram driver with dt support
+
+This adds a new nvrm driver which uses device tree to provide nvram
+access to other drivers. You have to specify the memory ranges where
+the flash chip is mapped and this driver will search there for some
+nvram and parse it. Other drivers can use this driver to access the
+device nvram. The nvram is used to store board configurations like the
+mac address and also for configuration values in the vendor firmware.
+---
+ arch/mips/bcm47xx/board.c             |  36 +++---
+ arch/mips/bcm47xx/nvram.c             |   7 +-
+ arch/mips/bcm47xx/setup.c             |   4 +-
+ arch/mips/bcm47xx/sprom.c             |   4 +-
+ arch/mips/bcm47xx/time.c              |   2 +-
+ drivers/misc/Kconfig                  |   5 +
+ drivers/misc/Makefile                 |   1 +
+ drivers/misc/bcm47xx-nvram.c          | 211 ++++++++++++++++++++++++++++++++++
+ drivers/net/ethernet/broadcom/b44.c   |   2 +-
+ drivers/net/ethernet/broadcom/bgmac.c |   4 +-
+ drivers/ssb/driver_chipcommon_pmu.c   |   2 +-
+ include/linux/bcm47xx_nvram.h         |  16 ++-
+ 12 files changed, 259 insertions(+), 35 deletions(-)
+ create mode 100644 drivers/misc/bcm47xx-nvram.c
+
+--- a/arch/mips/bcm47xx/board.c
++++ b/arch/mips/bcm47xx/board.c
+@@ -196,50 +196,50 @@ static __init const struct bcm47xx_board
+ 	const struct bcm47xx_board_type_list2 *e2;
+ 	const struct bcm47xx_board_type_list3 *e3;
+ 
+-	if (bcm47xx_nvram_getenv("model_name", buf1, sizeof(buf1)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "model_name", buf1, sizeof(buf1)) >= 0) {
+ 		for (e1 = bcm47xx_board_list_model_name; e1->value1; e1++) {
+ 			if (!strcmp(buf1, e1->value1))
+ 				return &e1->board;
+ 		}
+ 	}
+ 
+-	if (bcm47xx_nvram_getenv("model_no", buf1, sizeof(buf1)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "model_no", buf1, sizeof(buf1)) >= 0) {
+ 		for (e1 = bcm47xx_board_list_model_no; e1->value1; e1++) {
+ 			if (strstarts(buf1, e1->value1))
+ 				return &e1->board;
+ 		}
+ 	}
+ 
+-	if (bcm47xx_nvram_getenv("machine_name", buf1, sizeof(buf1)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "machine_name", buf1, sizeof(buf1)) >= 0) {
+ 		for (e1 = bcm47xx_board_list_machine_name; e1->value1; e1++) {
+ 			if (strstarts(buf1, e1->value1))
+ 				return &e1->board;
+ 		}
+ 	}
+ 
+-	if (bcm47xx_nvram_getenv("hardware_version", buf1, sizeof(buf1)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "hardware_version", buf1, sizeof(buf1)) >= 0) {
+ 		for (e1 = bcm47xx_board_list_hardware_version; e1->value1; e1++) {
+ 			if (strstarts(buf1, e1->value1))
+ 				return &e1->board;
+ 		}
+ 	}
+ 
+-	if (bcm47xx_nvram_getenv("productid", buf1, sizeof(buf1)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "productid", buf1, sizeof(buf1)) >= 0) {
+ 		for (e1 = bcm47xx_board_list_productid; e1->value1; e1++) {
+ 			if (!strcmp(buf1, e1->value1))
+ 				return &e1->board;
+ 		}
+ 	}
+ 
+-	if (bcm47xx_nvram_getenv("ModelId", buf1, sizeof(buf1)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "ModelId", buf1, sizeof(buf1)) >= 0) {
+ 		for (e1 = bcm47xx_board_list_ModelId; e1->value1; e1++) {
+ 			if (!strcmp(buf1, e1->value1))
+ 				return &e1->board;
+ 		}
+ 	}
+ 
+-	if (bcm47xx_nvram_getenv("melco_id", buf1, sizeof(buf1)) >= 0 ||
+-	    bcm47xx_nvram_getenv("buf1falo_id", buf1, sizeof(buf1)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "melco_id", buf1, sizeof(buf1)) >= 0 ||
++	    bcm47xx_nvram_getenv(NULL, "buf1falo_id", buf1, sizeof(buf1)) >= 0) {
+ 		/* buffalo hardware, check id for specific hardware matches */
+ 		for (e1 = bcm47xx_board_list_melco_id; e1->value1; e1++) {
+ 			if (!strcmp(buf1, e1->value1))
+@@ -247,8 +247,8 @@ static __init const struct bcm47xx_board
+ 		}
+ 	}
+ 
+-	if (bcm47xx_nvram_getenv("boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
+-	    bcm47xx_nvram_getenv("boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
++	    bcm47xx_nvram_getenv(NULL, "boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
+ 		for (e2 = bcm47xx_board_list_boot_hw; e2->value1; e2++) {
+ 			if (!strcmp(buf1, e2->value1) &&
+ 			    !strcmp(buf2, e2->value2))
+@@ -256,16 +256,16 @@ static __init const struct bcm47xx_board
+ 		}
+ 	}
+ 
+-	if (bcm47xx_nvram_getenv("board_id", buf1, sizeof(buf1)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "board_id", buf1, sizeof(buf1)) >= 0) {
+ 		for (e1 = bcm47xx_board_list_board_id; e1->value1; e1++) {
+ 			if (!strcmp(buf1, e1->value1))
+ 				return &e1->board;
+ 		}
+ 	}
+ 
+-	if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
+-	    bcm47xx_nvram_getenv("boardnum", buf2, sizeof(buf2)) >= 0 &&
+-	    bcm47xx_nvram_getenv("boardrev", buf3, sizeof(buf3)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "boardtype", buf1, sizeof(buf1)) >= 0 &&
++	    bcm47xx_nvram_getenv(NULL, "boardnum", buf2, sizeof(buf2)) >= 0 &&
++	    bcm47xx_nvram_getenv(NULL, "boardrev", buf3, sizeof(buf3)) >= 0) {
+ 		for (e3 = bcm47xx_board_list_board; e3->value1; e3++) {
+ 			if (!strcmp(buf1, e3->value1) &&
+ 			    !strcmp(buf2, e3->value2) &&
+@@ -286,7 +286,7 @@ void __init bcm47xx_board_detect(void)
+ 		return;
+ 
+ 	/* check if the nvram is available */
+-	err = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf));
++	err = bcm47xx_nvram_getenv(NULL, "boardtype", buf, sizeof(buf));
+ 
+ 	/* init of nvram failed, probably too early now */
+ 	if (err == -ENXIO) {
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -158,7 +158,8 @@ static int nvram_init(void)
+ 	return -ENXIO;
+ }
+ 
+-int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)
++int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
++			 size_t val_len)
+ {
+ 	char *var, *value, *end, *eq;
+ 	int err;
+@@ -190,7 +191,7 @@ int bcm47xx_nvram_getenv(char *name, cha
+ }
+ EXPORT_SYMBOL(bcm47xx_nvram_getenv);
+ 
+-int bcm47xx_nvram_gpio_pin(const char *name)
++int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
+ {
+ 	int i, err;
+ 	char nvram_var[10];
+@@ -200,7 +201,7 @@ int bcm47xx_nvram_gpio_pin(const char *n
+ 		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
+ 		if (err <= 0)
+ 			continue;
+-		err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
++		err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
+ 		if (err <= 0)
+ 			continue;
+ 		if (!strcmp(name, buf))
+--- a/arch/mips/bcm47xx/setup.c
++++ b/arch/mips/bcm47xx/setup.c
+@@ -123,7 +123,7 @@ static int bcm47xx_get_invariants(struct
+ 	memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
+ 	bcm47xx_fill_sprom(&iv->sprom, NULL, false);
+ 
+-	if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
++	if (bcm47xx_nvram_getenv(NULL, "cardbus", buf, sizeof(buf)) >= 0)
+ 		iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
+ 
+ 	return 0;
+@@ -146,7 +146,7 @@ static void __init bcm47xx_register_ssb(
+ 		panic("Failed to initialize SSB bus (err %d)", err);
+ 
+ 	mcore = &bcm47xx_bus.ssb.mipscore;
+-	if (bcm47xx_nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
++	if (bcm47xx_nvram_getenv(NULL, "kernel_args", buf, sizeof(buf)) >= 0) {
+ 		if (strstr(buf, "console=ttyS1")) {
+ 			struct ssb_serial_port port;
+ 
+--- a/arch/mips/bcm47xx/sprom.c
++++ b/arch/mips/bcm47xx/sprom.c
+@@ -50,10 +50,10 @@ static int get_nvram_var(const char *pre
+ 
+ 	create_key(prefix, postfix, name, key, sizeof(key));
+ 
+-	err = bcm47xx_nvram_getenv(key, buf, len);
++	err = bcm47xx_nvram_getenv(NULL, key, buf, len);
+ 	if (fallback && err == -ENOENT && prefix) {
+ 		create_key(NULL, postfix, name, key, sizeof(key));
+-		err = bcm47xx_nvram_getenv(key, buf, len);
++		err = bcm47xx_nvram_getenv(NULL, key, buf, len);
+ 	}
+ 	return err;
+ }
+--- a/arch/mips/bcm47xx/time.c
++++ b/arch/mips/bcm47xx/time.c
+@@ -61,7 +61,7 @@ void __init plat_time_init(void)
+ 	}
+ 
+ 	if (chip_id == 0x5354) {
+-		len = bcm47xx_nvram_getenv("clkfreq", buf, sizeof(buf));
++		len = bcm47xx_nvram_getenv(NULL, "clkfreq", buf, sizeof(buf));
+ 		if (len >= 0 && !strncmp(buf, "200", 4))
+ 			hz = 100000000;
+ 	}
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -515,6 +515,11 @@ config SRAM
+ 	  the genalloc API. It is supposed to be used for small on-chip SRAM
+ 	  areas found on many SoCs.
+ 
++config BCM47XX_NVRAM
++	tristate "BCM47XX nvram driver"
++	help
++		This adds support for the brcm47xx nvram driver.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -54,3 +54,4 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lat
+ obj-$(CONFIG_SRAM)		+= sram.o
+ obj-y				+= mic/
+ obj-$(CONFIG_GENWQE)		+= genwqe/
++obj-$(CONFIG_BCM47XX_NVRAM)	+= bcm47xx-nvram.o
+--- /dev/null
++++ b/drivers/misc/bcm47xx-nvram.c
+@@ -0,0 +1,211 @@
++/*
++ * BCM947xx nvram variable access
++ *
++ * Copyright (C) 2005 Broadcom Corporation
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2010-2014 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * This program is free software; you can redistribute	it and/or modify it
++ * under  the terms of	the GNU General	 Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/of_address.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/bcm47xx_nvram.h>
++
++struct bcm47xx_nvram {
++	size_t nvram_len;
++	char *nvram_buf;
++};
++
++static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
++
++static u32 find_nvram_size(void __iomem *end)
++{
++	struct nvram_header *header;
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
++		header = (struct nvram_header *)(end - nvram_sizes[i]);
++		if (header->magic == NVRAM_HEADER)
++			return nvram_sizes[i];
++	}
++
++	return 0;
++}
++
++/* Probe for NVRAM header */
++static int nvram_find_and_copy(struct device *dev, void __iomem *base,
++			       size_t len, char **nvram_buf,
++			       size_t *nvram_len)
++{
++	struct nvram_header *header;
++	int i;
++	u32 off;
++	u32 *src, *dst;
++	u32 size;
++
++	/* TODO: when nvram is on nand flash check for bad blocks first. */
++	off = FLASH_MIN;
++	while (off <= len) {
++		/* Windowed flash access */
++		size = find_nvram_size(base + off);
++		if (size) {
++			header = (struct nvram_header *)(base + off - size);
++			goto found;
++		}
++		off <<= 1;
++	}
++
++	/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
++	header = (struct nvram_header *)(base + 4096);
++	if (header->magic == NVRAM_HEADER) {
++		size = NVRAM_SPACE;
++		goto found;
++	}
++
++	header = (struct nvram_header *)(base + 1024);
++	if (header->magic == NVRAM_HEADER) {
++		size = NVRAM_SPACE;
++		goto found;
++	}
++
++	*nvram_buf = NULL;
++	*nvram_len = 0;
++	pr_err("no nvram found\n");
++	return -ENXIO;
++
++found:
++	if (header->len > size)
++		pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n");
++	*nvram_len = min_t(u32, header->len, size);
++
++	*nvram_buf = devm_kzalloc(dev, *nvram_len, GFP_KERNEL);
++	if (!*nvram_buf)
++		return -ENOMEM;
++
++	src = (u32 *) header;
++	dst = (u32 *) *nvram_buf;
++	for (i = 0; i < sizeof(struct nvram_header); i += 4)
++		*dst++ = *src++;
++	for (; i < *nvram_len; i += 4)
++		*dst++ = le32_to_cpu(*src++);
++
++	return 0;
++}
++
++int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val, size_t val_len)
++{
++	char *var, *value, *end, *eq;
++	struct bcm47xx_nvram *nvram;
++
++	if (!dev)
++		return -ENODEV;
++
++	nvram = dev_get_drvdata(dev);
++
++	if (!name || !nvram || !nvram->nvram_len)
++		return -EINVAL;
++
++	/* Look for name=value and return value */
++	var = nvram->nvram_buf + sizeof(struct nvram_header);
++	end = nvram->nvram_buf + nvram->nvram_len - 2;
++	end[0] = end[1] = '\0';
++	for (; *var; var = value + strlen(value) + 1) {
++		eq = strchr(var, '=');
++		if (!eq)
++			break;
++		value = eq + 1;
++		if ((eq - var) == strlen(name) &&
++			strncmp(var, name, (eq - var)) == 0) {
++			return snprintf(val, val_len, "%s", value);
++		}
++	}
++	return -ENOENT;
++}
++EXPORT_SYMBOL(bcm47xx_nvram_getenv);
++
++int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
++{
++	int i, err;
++	char nvram_var[10];
++	char buf[30];
++
++	if (!dev)
++		return -ENODEV;
++
++	for (i = 0; i < 32; i++) {
++		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
++		if (err <= 0)
++			continue;
++		err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
++		if (err <= 0)
++			continue;
++		if (!strcmp(name, buf))
++			return i;
++	}
++	return -ENOENT;
++}
++EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
++
++static int bcm47xx_nvram_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *np = dev->of_node;
++	struct bcm47xx_nvram *nvram;
++	int err;
++	struct resource flash_mem;
++	void __iomem *mmio;
++
++	/* Alloc */
++	nvram = devm_kzalloc(dev, sizeof(*nvram), GFP_KERNEL);
++	if (!nvram)
++		return -ENOMEM;
++
++	err = of_address_to_resource(np, 0, &flash_mem);
++	if (err)
++		return err;
++
++	mmio = ioremap_nocache(flash_mem.start, resource_size(&flash_mem));
++	if (!mmio)
++		return -ENOMEM;
++
++	err = nvram_find_and_copy(dev, mmio, resource_size(&flash_mem), &nvram->nvram_buf, &nvram->nvram_len);
++	if (err)
++		goto err_unmap_mmio;
++
++	platform_set_drvdata(pdev, nvram);
++
++err_unmap_mmio:
++	iounmap(mmio);
++	return err;
++}
++
++static const struct of_device_id bcm47xx_nvram_of_match_table[] = {
++	{ .compatible = "brcm,bcm47xx-nvram", },
++	{},
++};
++MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
++
++static struct platform_driver bcm47xx_nvram_driver = {
++	.driver = {
++		.owner = THIS_MODULE,
++		.name = "bcm47xx-nvram",
++		.of_match_table = bcm47xx_nvram_of_match_table,
++		/* driver unloading/unbinding currently not supported */
++		.suppress_bind_attrs = true,
++	},
++	.probe = bcm47xx_nvram_probe,
++};
++module_platform_driver(bcm47xx_nvram_driver);
++
++MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
++MODULE_LICENSE("GPLv2");
+--- a/drivers/net/ethernet/broadcom/b44.c
++++ b/drivers/net/ethernet/broadcom/b44.c
+@@ -411,7 +411,7 @@ static void b44_wap54g10_workaround(stru
+ 	 * see https://dev.openwrt.org/ticket/146
+ 	 * check and reset bit "isolate"
+ 	 */
+-	if (bcm47xx_nvram_getenv("boardnum", buf, sizeof(buf)) < 0)
++	if (bcm47xx_nvram_getenv(NULL, "boardnum", buf, sizeof(buf)) < 0)
+ 		return;
+ 	if (simple_strtoul(buf, NULL, 0) == 2) {
+ 		err = __b44_readphy(bp, 0, MII_BMCR, &val);
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -974,7 +974,7 @@ static void bgmac_chip_reset(struct bgma
+ 			     BGMAC_CHIPCTL_1_IF_TYPE_MII;
+ 		char buf[4];
+ 
+-		if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
++		if (bcm47xx_nvram_getenv(NULL, "et_swtype", buf, sizeof(buf)) > 0) {
+ 			if (kstrtou8(buf, 0, &et_swtype))
+ 				bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
+ 					  buf);
+@@ -1534,7 +1534,7 @@ static int bgmac_probe(struct bcma_devic
+ 	}
+ 
+ 	bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
+-	if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0)
++	if (bcm47xx_nvram_getenv(NULL, "et0_no_txint", NULL, 0) == 0)
+ 		bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
+ 
+ 	/* TODO: reset the external phy. Specs are needed */
+--- a/drivers/ssb/driver_chipcommon_pmu.c
++++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -319,7 +319,7 @@ static void ssb_pmu_pll_init(struct ssb_
+ 
+ 	if (bus->bustype == SSB_BUSTYPE_SSB) {
+ 		char buf[20];
+-		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
++		if (bcm47xx_nvram_getenv(NULL, "xtalfreq", buf, sizeof(buf)) >= 0)
+ 			crystalfreq = simple_strtoul(buf, NULL, 0);
+ 	}
+ 
+--- a/include/linux/bcm47xx_nvram.h
++++ b/include/linux/bcm47xx_nvram.h
+@@ -15,6 +15,8 @@
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ 
++struct device;
++
+ struct nvram_header {
+ 	u32 magic;
+ 	u32 len;
+@@ -33,17 +35,21 @@ struct nvram_header {
+ #define NVRAM_MAX_VALUE_LEN 255
+ #define NVRAM_MAX_PARAM_LEN 64
+ 
+-#ifdef CONFIG_BCM47XX
+-int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
++#if defined(CONFIG_BCM47XX) || defined(CONFIG_BCM47XX_NVRAM)
++int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
++			 size_t val_len);
+ 
+-int bcm47xx_nvram_gpio_pin(const char *name);
++int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name);
+ #else
+-static inline int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
++static inline int bcm47xx_nvram_getenv(const struct device *dev,
++				       const char *name, char *val,
++				       size_t val_len)
+ {
+ 	return -ENXIO;
+ }
+ 
+-static inline int bcm47xx_nvram_gpio_pin(const char *name)
++static inline int bcm47xx_nvram_gpio_pin(const struct device *dev,
++					 const char *name)
+ {
+ 	return -ENXIO;
+ }
diff --git a/target/linux/bcm53xx/patches-3.14/111-bcma-register-bcma-as-device-tree-driver.patch b/target/linux/bcm53xx/patches-3.14/111-bcma-register-bcma-as-device-tree-driver.patch
deleted file mode 100644
index fe44827082..0000000000
--- a/target/linux/bcm53xx/patches-3.14/111-bcma-register-bcma-as-device-tree-driver.patch
+++ /dev/null
@@ -1,115 +0,0 @@
-From c046c19fc8f1af7cf253fea5b0253143c159948a Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Mon, 6 Jan 2014 23:29:15 +0100
-Subject: [PATCH 6/8] bcma: register bcma as device tree driver
-
-This driver is used by the bcm53xx ARM SoC code.Now it is possible to
-give the address of the chipcommon core in device tree.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/host_soc.c   |   70 +++++++++++++++++++++++++++++++++++++++++++++
- include/linux/bcma/bcma.h |    2 ++
- 2 files changed, 72 insertions(+)
-
---- a/drivers/bcma/host_soc.c
-+++ b/drivers/bcma/host_soc.c
-@@ -7,6 +7,9 @@
- 
- #include "bcma_private.h"
- #include "scan.h"
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/of_address.h>
- #include <linux/bcma/bcma.h>
- #include <linux/bcma/bcma_soc.h>
- 
-@@ -173,6 +176,7 @@ int __init bcma_host_soc_register(struct
- 	/* Host specific */
- 	bus->hosttype = BCMA_HOSTTYPE_SOC;
- 	bus->ops = &bcma_host_soc_ops;
-+	bus->host_pdev = NULL;
- 
- 	/* Register */
- 	err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
-@@ -181,3 +185,69 @@ int __init bcma_host_soc_register(struct
- 
- 	return err;
- }
-+
-+#ifdef CONFIG_OF
-+static int bcma_host_soc_probe(struct platform_device *pdev)
-+{
-+	struct device *dev = &pdev->dev;
-+	struct device_node *np = dev->of_node;
-+	struct bcma_bus *bus;
-+	int err;
-+
-+	/* Alloc */
-+	bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL);
-+	if (!bus)
-+		return -ENOMEM;
-+
-+	/* Map MMIO */
-+	bus->mmio = of_iomap(np, 0);
-+	if (!bus->mmio)
-+		return -ENOMEM;
-+
-+	/* Host specific */
-+	bus->hosttype = BCMA_HOSTTYPE_SOC;
-+	bus->ops = &bcma_host_soc_ops;
-+	bus->host_pdev = pdev;
-+
-+	/* Register */
-+	err = bcma_bus_register(bus);
-+	if (err)
-+		goto err_unmap_mmio;
-+
-+	platform_set_drvdata(pdev, bus);
-+
-+	return err;
-+
-+err_unmap_mmio:
-+	iounmap(bus->mmio);
-+	return err;
-+}
-+
-+static int bcma_host_soc_remove(struct platform_device *pdev)
-+{
-+	struct bcma_bus *bus = platform_get_drvdata(pdev);
-+
-+	bcma_bus_unregister(bus);
-+	iounmap(bus->mmio);
-+	platform_set_drvdata(pdev, NULL);
-+
-+	return 0;
-+}
-+
-+static const struct of_device_id bcma_host_soc_of_match[] = {
-+	{ .compatible = "brcm,bus-aix", },
-+	{},
-+};
-+MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match);
-+
-+static struct platform_driver bcma_host_soc_driver = {
-+	.driver = {
-+		.name = "bcma-host-soc",
-+		.owner = THIS_MODULE,
-+		.of_match_table = bcma_host_soc_of_match,
-+	},
-+	.probe		= bcma_host_soc_probe,
-+	.remove		= bcma_host_soc_remove,
-+};
-+module_platform_driver(bcma_host_soc_driver);
-+#endif /* CONFIG_OF */
---- a/include/linux/bcma/bcma.h
-+++ b/include/linux/bcma/bcma.h
-@@ -319,6 +319,8 @@ struct bcma_bus {
- 		struct pci_dev *host_pci;
- 		/* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
- 		struct sdio_func *host_sdio;
-+		/* Pointer to platform device (only for BCMA_HOSTTYPE_SOC) */
-+		struct platform_device *host_pdev;
- 	};
- 
- 	struct bcma_chipinfo chipinfo;
diff --git a/target/linux/bcm53xx/patches-3.14/112-bcm53xx-sprom-add-sprom-driver.patch b/target/linux/bcm53xx/patches-3.14/112-bcm53xx-sprom-add-sprom-driver.patch
new file mode 100644
index 0000000000..d8cdeb563a
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/112-bcm53xx-sprom-add-sprom-driver.patch
@@ -0,0 +1,667 @@
+From b113f9d3e140f18e63cbf3408b3dcde372242dc8 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 4 May 2014 13:19:20 +0200
+Subject: [PATCH 04/15] bcm53xx-sprom: add sprom driver
+
+This driver needs an nvram driver and fetches the sprom values from the
+sprom and provides it to any other driver. The calibration data for the
+wifi chip the mac address and some more board description data is
+stores in the sprom.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/misc/Kconfig         |   5 +
+ drivers/misc/Makefile        |   1 +
+ drivers/misc/bcm53xx-sprom.c | 625 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 631 insertions(+)
+ create mode 100644 drivers/misc/bcm53xx-sprom.c
+
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -520,6 +520,11 @@ config BCM47XX_NVRAM
+ 	help
+ 		This adds support for the brcm47xx nvram driver.
+ 
++config BCM53XX_SPROM
++	tristate "BCM53XX sprom driver"
++	help
++		This adds support for the brcm53xx sprom driver.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM)		+= sram.o
+ obj-y				+= mic/
+ obj-$(CONFIG_GENWQE)		+= genwqe/
+ obj-$(CONFIG_BCM47XX_NVRAM)	+= bcm47xx-nvram.o
++obj-$(CONFIG_BCM53XX_SPROM)	+= bcm53xx-sprom.o
+--- /dev/null
++++ b/drivers/misc/bcm53xx-sprom.c
+@@ -0,0 +1,625 @@
++/*
++ * BCM947xx nvram variable access
++ *
++ * Copyright (C) 2005 Broadcom Corporation
++ * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
++ * Copyright (C) 2006 Michael Buesch <m@bues.ch>
++ * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2010-2014 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * This program is free software; you can redistribute	it and/or modify it
++ * under  the terms of	the GNU General	 Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/of_address.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/of_platform.h>
++#include <linux/io.h>
++#include <linux/ssb/ssb.h>
++#include <linux/bcm47xx_nvram.h>
++
++struct bcm53xx_sprom_fill {
++	const char *prefix;
++	bool fallback;
++	int (*getenv)(const struct bcm53xx_sprom_fill *fill, const char *name, char *val, size_t val_len);
++	const void *priv;
++};
++
++static void create_key(const char *prefix, const char *postfix,
++		       const char *name, char *buf, int len)
++{
++	if (prefix && postfix)
++		snprintf(buf, len, "%s%s%s", prefix, name, postfix);
++	else if (prefix)
++		snprintf(buf, len, "%s%s", prefix, name);
++	else if (postfix)
++		snprintf(buf, len, "%s%s", name, postfix);
++	else
++		snprintf(buf, len, "%s", name);
++}
++
++static int get_nvram_var(const struct bcm53xx_sprom_fill *fill, const char *postfix,
++			 const char *name, char *buf, int len)
++{
++	char key[40];
++	int err;
++
++	create_key(fill->prefix, postfix, name, key, sizeof(key));
++
++	err = fill->getenv(fill, key, buf, len);
++	if (fill->fallback && err == -ENOENT && fill->prefix) {
++		create_key(NULL, postfix, name, key, sizeof(key));
++		err = fill->getenv(fill, key, buf, len);
++	}
++	return err;
++}
++
++#define NVRAM_READ_VAL(type)						\
++static void nvram_read_ ## type (const struct bcm53xx_sprom_fill *fill,	\
++				 const char *postfix, const char *name, \
++				 type *val, type allset)		\
++{									\
++	char buf[100];							\
++	int err;							\
++	type var;							\
++									\
++	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
++	if (err < 0)							\
++		return;							\
++	err = kstrto ## type(strim(buf), 0, &var);			\
++	if (err) {							\
++		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
++			fill->prefix, name, postfix, buf, err);		\
++		return;							\
++	}								\
++	if (allset && var == allset)					\
++		return;							\
++	*val = var;							\
++}
++
++NVRAM_READ_VAL(u8)
++NVRAM_READ_VAL(s8)
++NVRAM_READ_VAL(u16)
++NVRAM_READ_VAL(u32)
++
++#undef NVRAM_READ_VAL
++
++static void nvram_read_u32_2(const struct bcm53xx_sprom_fill *fill, const char *name,
++			     u16 *val_lo, u16 *val_hi)
++{
++	char buf[100];
++	int err;
++	u32 val;
++
++	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
++	if (err < 0)
++		return;
++	err = kstrtou32(strim(buf), 0, &val);
++	if (err) {
++		pr_warn("can not parse nvram name %s%s with value %s got %i\n",
++			fill->prefix, name, buf, err);
++		return;
++	}
++	*val_lo = (val & 0x0000FFFFU);
++	*val_hi = (val & 0xFFFF0000U) >> 16;
++}
++
++static void nvram_read_leddc(const struct bcm53xx_sprom_fill *fill, const char *name,
++			     u8 *leddc_on_time, u8 *leddc_off_time)
++{
++	char buf[100];
++	int err;
++	u32 val;
++
++	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
++	if (err < 0)
++		return;
++	err = kstrtou32(strim(buf), 0, &val);
++	if (err) {
++		pr_warn("can not parse nvram name %s%s with value %s got %i\n",
++			fill->prefix, name, buf, err);
++		return;
++	}
++
++	if (val == 0xffff || val == 0xffffffff)
++		return;
++
++	*leddc_on_time = val & 0xff;
++	*leddc_off_time = (val >> 16) & 0xff;
++}
++
++static void nvram_read_macaddr(const struct bcm53xx_sprom_fill *fill, const char *name,
++			       u8 val[6])
++{
++	char buf[100];
++	int err;
++
++	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
++	if (err < 0)
++		return;
++
++	bcm47xx_nvram_parse_macaddr(buf, val);
++}
++
++static void nvram_read_alpha2(const struct bcm53xx_sprom_fill *fill, const char *name,
++			     char val[2])
++{
++	char buf[10];
++	int err;
++
++	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
++	if (err < 0)
++		return;
++	if (buf[0] == '0')
++		return;
++	if (strlen(buf) > 2) {
++		pr_warn("alpha2 is too long %s\n", buf);
++		return;
++	}
++	memcpy(val, buf, 2);
++}
++
++static void bcm53xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
++					const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
++	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
++	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
++	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
++	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
++	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
++	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
++	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
++	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
++}
++
++static void bcm53xx_sprom_fill_r12389(struct ssb_sprom *sprom,
++				      const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u16(fill, NULL, "pa0b0", &sprom->pa0b0, 0);
++	nvram_read_u16(fill, NULL, "pa0b1", &sprom->pa0b1, 0);
++	nvram_read_u16(fill, NULL, "pa0b2", &sprom->pa0b2, 0);
++	nvram_read_u8(fill, NULL, "pa0itssit", &sprom->itssi_bg, 0);
++	nvram_read_u8(fill, NULL, "pa0maxpwr", &sprom->maxpwr_bg, 0);
++	nvram_read_u16(fill, NULL, "pa1b0", &sprom->pa1b0, 0);
++	nvram_read_u16(fill, NULL, "pa1b1", &sprom->pa1b1, 0);
++	nvram_read_u16(fill, NULL, "pa1b2", &sprom->pa1b2, 0);
++	nvram_read_u8(fill, NULL, "pa1itssit", &sprom->itssi_a, 0);
++	nvram_read_u8(fill, NULL, "pa1maxpwr", &sprom->maxpwr_a, 0);
++}
++
++static void bcm53xx_sprom_fill_r1(struct ssb_sprom *sprom,
++				  const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u16(fill, NULL, "boardflags", &sprom->boardflags_lo, 0);
++	nvram_read_u8(fill, NULL, "cc", &sprom->country_code, 0);
++}
++
++static void bcm53xx_sprom_fill_r2389(struct ssb_sprom *sprom,
++				     const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u8(fill, NULL, "opo", &sprom->opo, 0);
++	nvram_read_u16(fill, NULL, "pa1lob0", &sprom->pa1lob0, 0);
++	nvram_read_u16(fill, NULL, "pa1lob1", &sprom->pa1lob1, 0);
++	nvram_read_u16(fill, NULL, "pa1lob2", &sprom->pa1lob2, 0);
++	nvram_read_u16(fill, NULL, "pa1hib0", &sprom->pa1hib0, 0);
++	nvram_read_u16(fill, NULL, "pa1hib1", &sprom->pa1hib1, 0);
++	nvram_read_u16(fill, NULL, "pa1hib2", &sprom->pa1hib2, 0);
++	nvram_read_u8(fill, NULL, "pa1lomaxpwr", &sprom->maxpwr_al, 0);
++	nvram_read_u8(fill, NULL, "pa1himaxpwr", &sprom->maxpwr_ah, 0);
++}
++
++static void bcm53xx_sprom_fill_r389(struct ssb_sprom *sprom,
++				    const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u8(fill, NULL, "bxa2g", &sprom->bxa2g, 0);
++	nvram_read_u8(fill, NULL, "rssisav2g", &sprom->rssisav2g, 0);
++	nvram_read_u8(fill, NULL, "rssismc2g", &sprom->rssismc2g, 0);
++	nvram_read_u8(fill, NULL, "rssismf2g", &sprom->rssismf2g, 0);
++	nvram_read_u8(fill, NULL, "bxa5g", &sprom->bxa5g, 0);
++	nvram_read_u8(fill, NULL, "rssisav5g", &sprom->rssisav5g, 0);
++	nvram_read_u8(fill, NULL, "rssismc5g", &sprom->rssismc5g, 0);
++	nvram_read_u8(fill, NULL, "rssismf5g", &sprom->rssismf5g, 0);
++	nvram_read_u8(fill, NULL, "tri2g", &sprom->tri2g, 0);
++	nvram_read_u8(fill, NULL, "tri5g", &sprom->tri5g, 0);
++	nvram_read_u8(fill, NULL, "tri5gl", &sprom->tri5gl, 0);
++	nvram_read_u8(fill, NULL, "tri5gh", &sprom->tri5gh, 0);
++	nvram_read_s8(fill, NULL, "rxpo2g", &sprom->rxpo2g, 0);
++	nvram_read_s8(fill, NULL, "rxpo5g", &sprom->rxpo5g, 0);
++}
++
++static void bcm53xx_sprom_fill_r3(struct ssb_sprom *sprom,
++				  const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
++	nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
++			 &sprom->leddc_off_time);
++}
++
++static void bcm53xx_sprom_fill_r4589(struct ssb_sprom *sprom,
++				     const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
++	nvram_read_s8(fill, NULL, "ag2", &sprom->antenna_gain.a2, 0);
++	nvram_read_s8(fill, NULL, "ag3", &sprom->antenna_gain.a3, 0);
++	nvram_read_u8(fill, NULL, "txchain", &sprom->txchain, 0xf);
++	nvram_read_u8(fill, NULL, "rxchain", &sprom->rxchain, 0xf);
++	nvram_read_u8(fill, NULL, "antswitch", &sprom->antswitch, 0xff);
++	nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
++			 &sprom->leddc_off_time);
++}
++
++static void bcm53xx_sprom_fill_r458(struct ssb_sprom *sprom,
++				    const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u16(fill, NULL, "cck2gpo", &sprom->cck2gpo, 0);
++	nvram_read_u32(fill, NULL, "ofdm2gpo", &sprom->ofdm2gpo, 0);
++	nvram_read_u32(fill, NULL, "ofdm5gpo", &sprom->ofdm5gpo, 0);
++	nvram_read_u32(fill, NULL, "ofdm5glpo", &sprom->ofdm5glpo, 0);
++	nvram_read_u32(fill, NULL, "ofdm5ghpo", &sprom->ofdm5ghpo, 0);
++	nvram_read_u16(fill, NULL, "cddpo", &sprom->cddpo, 0);
++	nvram_read_u16(fill, NULL, "stbcpo", &sprom->stbcpo, 0);
++	nvram_read_u16(fill, NULL, "bw40po", &sprom->bw40po, 0);
++	nvram_read_u16(fill, NULL, "bwduppo", &sprom->bwduppo, 0);
++	nvram_read_u16(fill, NULL, "mcs2gpo0", &sprom->mcs2gpo[0], 0);
++	nvram_read_u16(fill, NULL, "mcs2gpo1", &sprom->mcs2gpo[1], 0);
++	nvram_read_u16(fill, NULL, "mcs2gpo2", &sprom->mcs2gpo[2], 0);
++	nvram_read_u16(fill, NULL, "mcs2gpo3", &sprom->mcs2gpo[3], 0);
++	nvram_read_u16(fill, NULL, "mcs2gpo4", &sprom->mcs2gpo[4], 0);
++	nvram_read_u16(fill, NULL, "mcs2gpo5", &sprom->mcs2gpo[5], 0);
++	nvram_read_u16(fill, NULL, "mcs2gpo6", &sprom->mcs2gpo[6], 0);
++	nvram_read_u16(fill, NULL, "mcs2gpo7", &sprom->mcs2gpo[7], 0);
++	nvram_read_u16(fill, NULL, "mcs5gpo0", &sprom->mcs5gpo[0], 0);
++	nvram_read_u16(fill, NULL, "mcs5gpo1", &sprom->mcs5gpo[1], 0);
++	nvram_read_u16(fill, NULL, "mcs5gpo2", &sprom->mcs5gpo[2], 0);
++	nvram_read_u16(fill, NULL, "mcs5gpo3", &sprom->mcs5gpo[3], 0);
++	nvram_read_u16(fill, NULL, "mcs5gpo4", &sprom->mcs5gpo[4], 0);
++	nvram_read_u16(fill, NULL, "mcs5gpo5", &sprom->mcs5gpo[5], 0);
++	nvram_read_u16(fill, NULL, "mcs5gpo6", &sprom->mcs5gpo[6], 0);
++	nvram_read_u16(fill, NULL, "mcs5gpo7", &sprom->mcs5gpo[7], 0);
++	nvram_read_u16(fill, NULL, "mcs5glpo0", &sprom->mcs5glpo[0], 0);
++	nvram_read_u16(fill, NULL, "mcs5glpo1", &sprom->mcs5glpo[1], 0);
++	nvram_read_u16(fill, NULL, "mcs5glpo2", &sprom->mcs5glpo[2], 0);
++	nvram_read_u16(fill, NULL, "mcs5glpo3", &sprom->mcs5glpo[3], 0);
++	nvram_read_u16(fill, NULL, "mcs5glpo4", &sprom->mcs5glpo[4], 0);
++	nvram_read_u16(fill, NULL, "mcs5glpo5", &sprom->mcs5glpo[5], 0);
++	nvram_read_u16(fill, NULL, "mcs5glpo6", &sprom->mcs5glpo[6], 0);
++	nvram_read_u16(fill, NULL, "mcs5glpo7", &sprom->mcs5glpo[7], 0);
++	nvram_read_u16(fill, NULL, "mcs5ghpo0", &sprom->mcs5ghpo[0], 0);
++	nvram_read_u16(fill, NULL, "mcs5ghpo1", &sprom->mcs5ghpo[1], 0);
++	nvram_read_u16(fill, NULL, "mcs5ghpo2", &sprom->mcs5ghpo[2], 0);
++	nvram_read_u16(fill, NULL, "mcs5ghpo3", &sprom->mcs5ghpo[3], 0);
++	nvram_read_u16(fill, NULL, "mcs5ghpo4", &sprom->mcs5ghpo[4], 0);
++	nvram_read_u16(fill, NULL, "mcs5ghpo5", &sprom->mcs5ghpo[5], 0);
++	nvram_read_u16(fill, NULL, "mcs5ghpo6", &sprom->mcs5ghpo[6], 0);
++	nvram_read_u16(fill, NULL, "mcs5ghpo7", &sprom->mcs5ghpo[7], 0);
++}
++
++static void bcm53xx_sprom_fill_r45(struct ssb_sprom *sprom,
++				   const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u8(fill, NULL, "txpid2ga0", &sprom->txpid2g[0], 0);
++	nvram_read_u8(fill, NULL, "txpid2ga1", &sprom->txpid2g[1], 0);
++	nvram_read_u8(fill, NULL, "txpid2ga2", &sprom->txpid2g[2], 0);
++	nvram_read_u8(fill, NULL, "txpid2ga3", &sprom->txpid2g[3], 0);
++	nvram_read_u8(fill, NULL, "txpid5ga0", &sprom->txpid5g[0], 0);
++	nvram_read_u8(fill, NULL, "txpid5ga1", &sprom->txpid5g[1], 0);
++	nvram_read_u8(fill, NULL, "txpid5ga2", &sprom->txpid5g[2], 0);
++	nvram_read_u8(fill, NULL, "txpid5ga3", &sprom->txpid5g[3], 0);
++	nvram_read_u8(fill, NULL, "txpid5gla0", &sprom->txpid5gl[0], 0);
++	nvram_read_u8(fill, NULL, "txpid5gla1", &sprom->txpid5gl[1], 0);
++	nvram_read_u8(fill, NULL, "txpid5gla2", &sprom->txpid5gl[2], 0);
++	nvram_read_u8(fill, NULL, "txpid5gla3", &sprom->txpid5gl[3], 0);
++	nvram_read_u8(fill, NULL, "txpid5gha0", &sprom->txpid5gh[0], 0);
++	nvram_read_u8(fill, NULL, "txpid5gha1", &sprom->txpid5gh[1], 0);
++	nvram_read_u8(fill, NULL, "txpid5gha2", &sprom->txpid5gh[2], 0);
++	nvram_read_u8(fill, NULL, "txpid5gha3", &sprom->txpid5gh[3], 0);
++}
++
++static void bcm53xx_sprom_fill_r89(struct ssb_sprom *sprom,
++				   const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u8(fill, NULL, "tssipos2g", &sprom->fem.ghz2.tssipos, 0);
++	nvram_read_u8(fill, NULL, "extpagain2g", &sprom->fem.ghz2.extpa_gain, 0);
++	nvram_read_u8(fill, NULL, "pdetrange2g", &sprom->fem.ghz2.pdet_range, 0);
++	nvram_read_u8(fill, NULL, "triso2g", &sprom->fem.ghz2.tr_iso, 0);
++	nvram_read_u8(fill, NULL, "antswctl2g", &sprom->fem.ghz2.antswlut, 0);
++	nvram_read_u8(fill, NULL, "tssipos5g", &sprom->fem.ghz5.tssipos, 0);
++	nvram_read_u8(fill, NULL, "extpagain5g", &sprom->fem.ghz5.extpa_gain, 0);
++	nvram_read_u8(fill, NULL, "pdetrange5g", &sprom->fem.ghz5.pdet_range, 0);
++	nvram_read_u8(fill, NULL, "triso5g", &sprom->fem.ghz5.tr_iso, 0);
++	nvram_read_u8(fill, NULL, "antswctl5g", &sprom->fem.ghz5.antswlut, 0);
++	nvram_read_u8(fill, NULL, "tempthresh", &sprom->tempthresh, 0);
++	nvram_read_u8(fill, NULL, "tempoffset", &sprom->tempoffset, 0);
++	nvram_read_u16(fill, NULL, "rawtempsense", &sprom->rawtempsense, 0);
++	nvram_read_u8(fill, NULL, "measpower", &sprom->measpower, 0);
++	nvram_read_u8(fill, NULL, "tempsense_slope", &sprom->tempsense_slope, 0);
++	nvram_read_u8(fill, NULL, "tempcorrx", &sprom->tempcorrx, 0);
++	nvram_read_u8(fill, NULL, "tempsense_option", &sprom->tempsense_option, 0);
++	nvram_read_u8(fill, NULL, "freqoffset_corr", &sprom->freqoffset_corr, 0);
++	nvram_read_u8(fill, NULL, "iqcal_swp_dis", &sprom->iqcal_swp_dis, 0);
++	nvram_read_u8(fill, NULL, "hw_iqcal_en", &sprom->hw_iqcal_en, 0);
++	nvram_read_u8(fill, NULL, "elna2g", &sprom->elna2g, 0);
++	nvram_read_u8(fill, NULL, "elna5g", &sprom->elna5g, 0);
++	nvram_read_u8(fill, NULL, "phycal_tempdelta", &sprom->phycal_tempdelta, 0);
++	nvram_read_u8(fill, NULL, "temps_period", &sprom->temps_period, 0);
++	nvram_read_u8(fill, NULL, "temps_hysteresis", &sprom->temps_hysteresis, 0);
++	nvram_read_u8(fill, NULL, "measpower1", &sprom->measpower1, 0);
++	nvram_read_u8(fill, NULL, "measpower2", &sprom->measpower2, 0);
++	nvram_read_u8(fill, NULL, "rxgainerr2ga0", &sprom->rxgainerr2ga[0], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr2ga1", &sprom->rxgainerr2ga[1], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr2ga2", &sprom->rxgainerr2ga[2], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gla0", &sprom->rxgainerr5gla[0], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gla1", &sprom->rxgainerr5gla[1], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gla2", &sprom->rxgainerr5gla[2], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gma0", &sprom->rxgainerr5gma[0], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gma1", &sprom->rxgainerr5gma[1], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gma2", &sprom->rxgainerr5gma[2], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gha0", &sprom->rxgainerr5gha[0], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gha1", &sprom->rxgainerr5gha[1], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gha2", &sprom->rxgainerr5gha[2], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gua0", &sprom->rxgainerr5gua[0], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gua1", &sprom->rxgainerr5gua[1], 0);
++	nvram_read_u8(fill, NULL, "rxgainerr5gua2", &sprom->rxgainerr5gua[2], 0);
++	nvram_read_u8(fill, NULL, "noiselvl2ga0", &sprom->noiselvl2ga[0], 0);
++	nvram_read_u8(fill, NULL, "noiselvl2ga1", &sprom->noiselvl2ga[1], 0);
++	nvram_read_u8(fill, NULL, "noiselvl2ga2", &sprom->noiselvl2ga[2], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gla0", &sprom->noiselvl5gla[0], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gla1", &sprom->noiselvl5gla[1], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gla2", &sprom->noiselvl5gla[2], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gma0", &sprom->noiselvl5gma[0], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gma1", &sprom->noiselvl5gma[1], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gma2", &sprom->noiselvl5gma[2], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gha0", &sprom->noiselvl5gha[0], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gha1", &sprom->noiselvl5gha[1], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gha2", &sprom->noiselvl5gha[2], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gua0", &sprom->noiselvl5gua[0], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gua1", &sprom->noiselvl5gua[1], 0);
++	nvram_read_u8(fill, NULL, "noiselvl5gua2", &sprom->noiselvl5gua[2], 0);
++	nvram_read_u8(fill, NULL, "pcieingress_war", &sprom->pcieingress_war, 0);
++}
++
++static void bcm53xx_sprom_fill_r9(struct ssb_sprom *sprom,
++				  const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u16(fill, NULL, "cckbw202gpo", &sprom->cckbw202gpo, 0);
++	nvram_read_u16(fill, NULL, "cckbw20ul2gpo", &sprom->cckbw20ul2gpo, 0);
++	nvram_read_u32(fill, NULL, "legofdmbw202gpo", &sprom->legofdmbw202gpo, 0);
++	nvram_read_u32(fill, NULL, "legofdmbw20ul2gpo", &sprom->legofdmbw20ul2gpo, 0);
++	nvram_read_u32(fill, NULL, "legofdmbw205glpo", &sprom->legofdmbw205glpo, 0);
++	nvram_read_u32(fill, NULL, "legofdmbw20ul5glpo", &sprom->legofdmbw20ul5glpo, 0);
++	nvram_read_u32(fill, NULL, "legofdmbw205gmpo", &sprom->legofdmbw205gmpo, 0);
++	nvram_read_u32(fill, NULL, "legofdmbw20ul5gmpo", &sprom->legofdmbw20ul5gmpo, 0);
++	nvram_read_u32(fill, NULL, "legofdmbw205ghpo", &sprom->legofdmbw205ghpo, 0);
++	nvram_read_u32(fill, NULL, "legofdmbw20ul5ghpo", &sprom->legofdmbw20ul5ghpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw202gpo", &sprom->mcsbw202gpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw20ul2gpo", &sprom->mcsbw20ul2gpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw402gpo", &sprom->mcsbw402gpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw205glpo", &sprom->mcsbw205glpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw20ul5glpo", &sprom->mcsbw20ul5glpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw405glpo", &sprom->mcsbw405glpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw205gmpo", &sprom->mcsbw205gmpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw20ul5gmpo", &sprom->mcsbw20ul5gmpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw405gmpo", &sprom->mcsbw405gmpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw205ghpo", &sprom->mcsbw205ghpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw20ul5ghpo", &sprom->mcsbw20ul5ghpo, 0);
++	nvram_read_u32(fill, NULL, "mcsbw405ghpo", &sprom->mcsbw405ghpo, 0);
++	nvram_read_u16(fill, NULL, "mcs32po", &sprom->mcs32po, 0);
++	nvram_read_u16(fill, NULL, "legofdm40duppo", &sprom->legofdm40duppo, 0);
++	nvram_read_u8(fill, NULL, "sar2g", &sprom->sar2g, 0);
++	nvram_read_u8(fill, NULL, "sar5g", &sprom->sar5g, 0);
++}
++
++static void bcm53xx_sprom_fill_path_r4589(struct ssb_sprom *sprom,
++					  const struct bcm53xx_sprom_fill *fill)
++{
++	char postfix[2];
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
++		struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
++		snprintf(postfix, sizeof(postfix), "%i", i);
++		nvram_read_u8(fill, postfix, "maxp2ga", &pwr_info->maxpwr_2g, 0);
++		nvram_read_u8(fill, postfix, "itt2ga", &pwr_info->itssi_2g, 0);
++		nvram_read_u8(fill, postfix, "itt5ga", &pwr_info->itssi_5g, 0);
++		nvram_read_u16(fill, postfix, "pa2gw0a", &pwr_info->pa_2g[0], 0);
++		nvram_read_u16(fill, postfix, "pa2gw1a", &pwr_info->pa_2g[1], 0);
++		nvram_read_u16(fill, postfix, "pa2gw2a", &pwr_info->pa_2g[2], 0);
++		nvram_read_u8(fill, postfix, "maxp5ga", &pwr_info->maxpwr_5g, 0);
++		nvram_read_u8(fill, postfix, "maxp5gha", &pwr_info->maxpwr_5gh, 0);
++		nvram_read_u8(fill, postfix, "maxp5gla", &pwr_info->maxpwr_5gl, 0);
++		nvram_read_u16(fill, postfix, "pa5gw0a", &pwr_info->pa_5g[0], 0);
++		nvram_read_u16(fill, postfix, "pa5gw1a", &pwr_info->pa_5g[1], 0);
++		nvram_read_u16(fill, postfix, "pa5gw2a", &pwr_info->pa_5g[2], 0);
++		nvram_read_u16(fill, postfix, "pa5glw0a", &pwr_info->pa_5gl[0], 0);
++		nvram_read_u16(fill, postfix, "pa5glw1a", &pwr_info->pa_5gl[1], 0);
++		nvram_read_u16(fill, postfix, "pa5glw2a", &pwr_info->pa_5gl[2], 0);
++		nvram_read_u16(fill, postfix, "pa5ghw0a", &pwr_info->pa_5gh[0], 0);
++		nvram_read_u16(fill, postfix, "pa5ghw1a", &pwr_info->pa_5gh[1], 0);
++		nvram_read_u16(fill, postfix, "pa5ghw2a", &pwr_info->pa_5gh[2], 0);
++	}
++}
++
++static void bcm53xx_sprom_fill_path_r45(struct ssb_sprom *sprom,
++					const struct bcm53xx_sprom_fill *fill)
++{
++	char postfix[2];
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
++		struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
++		snprintf(postfix, sizeof(postfix), "%i", i);
++		nvram_read_u16(fill, postfix, "pa2gw3a", &pwr_info->pa_2g[3], 0);
++		nvram_read_u16(fill, postfix, "pa5gw3a", &pwr_info->pa_5g[3], 0);
++		nvram_read_u16(fill, postfix, "pa5glw3a", &pwr_info->pa_5gl[3], 0);
++		nvram_read_u16(fill, postfix, "pa5ghw3a", &pwr_info->pa_5gh[3], 0);
++	}
++}
++
++static void bcm53xx_sprom_fill_ethernet(struct ssb_sprom *sprom,
++					const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_macaddr(fill, "et0macaddr", sprom->et0mac);
++	nvram_read_u8(fill, NULL, "et0mdcport", &sprom->et0mdcport, 0);
++	nvram_read_u8(fill, NULL, "et0phyaddr", &sprom->et0phyaddr, 0);
++
++	nvram_read_macaddr(fill, "et1macaddr", sprom->et1mac);
++	nvram_read_u8(fill, NULL, "et1mdcport", &sprom->et1mdcport, 0);
++	nvram_read_u8(fill, NULL, "et1phyaddr", &sprom->et1phyaddr, 0);
++
++	nvram_read_macaddr(fill, "macaddr", sprom->il0mac);
++	nvram_read_macaddr(fill, "il0macaddr", sprom->il0mac);
++}
++
++static void bcm53xx_sprom_fill_board_data(struct ssb_sprom *sprom,
++					  const struct bcm53xx_sprom_fill *fill)
++{
++	nvram_read_u16(fill, NULL, "boardrev", &sprom->board_rev, 0);
++	nvram_read_u16(fill, NULL, "boardnum", &sprom->board_num, 0);
++	nvram_read_u16(fill, NULL, "boardtype", &sprom->board_type, 0);
++	nvram_read_u32_2(fill, "boardflags", &sprom->boardflags_lo,
++			 &sprom->boardflags_hi);
++	nvram_read_u32_2(fill, "boardflags2", &sprom->boardflags2_lo,
++			 &sprom->boardflags2_hi);
++}
++
++static void bcm53xx_sprom_fill(struct ssb_sprom *sprom,
++			const struct bcm53xx_sprom_fill *fill)
++{
++	bcm53xx_sprom_fill_ethernet(sprom, fill);
++	bcm53xx_sprom_fill_board_data(sprom, fill);
++
++	nvram_read_u8(fill, NULL, "sromrev", &sprom->revision, 0);
++
++	switch (sprom->revision) {
++	case 1:
++		bcm53xx_sprom_fill_r1234589(sprom, fill);
++		bcm53xx_sprom_fill_r12389(sprom, fill);
++		bcm53xx_sprom_fill_r1(sprom, fill);
++		break;
++	case 2:
++		bcm53xx_sprom_fill_r1234589(sprom, fill);
++		bcm53xx_sprom_fill_r12389(sprom, fill);
++		bcm53xx_sprom_fill_r2389(sprom, fill);
++		break;
++	case 3:
++		bcm53xx_sprom_fill_r1234589(sprom, fill);
++		bcm53xx_sprom_fill_r12389(sprom, fill);
++		bcm53xx_sprom_fill_r2389(sprom, fill);
++		bcm53xx_sprom_fill_r389(sprom, fill);
++		bcm53xx_sprom_fill_r3(sprom, fill);
++		break;
++	case 4:
++	case 5:
++		bcm53xx_sprom_fill_r1234589(sprom, fill);
++		bcm53xx_sprom_fill_r4589(sprom, fill);
++		bcm53xx_sprom_fill_r458(sprom, fill);
++		bcm53xx_sprom_fill_r45(sprom, fill);
++		bcm53xx_sprom_fill_path_r4589(sprom, fill);
++		bcm53xx_sprom_fill_path_r45(sprom, fill);
++		break;
++	case 8:
++		bcm53xx_sprom_fill_r1234589(sprom, fill);
++		bcm53xx_sprom_fill_r12389(sprom, fill);
++		bcm53xx_sprom_fill_r2389(sprom, fill);
++		bcm53xx_sprom_fill_r389(sprom, fill);
++		bcm53xx_sprom_fill_r4589(sprom, fill);
++		bcm53xx_sprom_fill_r458(sprom, fill);
++		bcm53xx_sprom_fill_r89(sprom, fill);
++		bcm53xx_sprom_fill_path_r4589(sprom, fill);
++		break;
++	case 9:
++		bcm53xx_sprom_fill_r1234589(sprom, fill);
++		bcm53xx_sprom_fill_r12389(sprom, fill);
++		bcm53xx_sprom_fill_r2389(sprom, fill);
++		bcm53xx_sprom_fill_r389(sprom, fill);
++		bcm53xx_sprom_fill_r4589(sprom, fill);
++		bcm53xx_sprom_fill_r89(sprom, fill);
++		bcm53xx_sprom_fill_r9(sprom, fill);
++		bcm53xx_sprom_fill_path_r4589(sprom, fill);
++		break;
++	default:
++		pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
++			sprom->revision);
++		sprom->revision = 1;
++		bcm53xx_sprom_fill_r1234589(sprom, fill);
++		bcm53xx_sprom_fill_r12389(sprom, fill);
++		bcm53xx_sprom_fill_r1(sprom, fill);
++	}
++}
++
++static int bcm53xx_sprom_getenv(const struct bcm53xx_sprom_fill *fill,
++				const char *name, char *val, size_t val_len)
++{
++	const struct platform_device *nvram_dev = fill->priv;
++
++	return bcm47xx_nvram_getenv(&nvram_dev->dev, name, val, val_len);
++};
++
++static int bcm53xx_sprom_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *np = dev->of_node;
++	struct ssb_sprom *sprom;
++	const phandle *handle;
++	struct device_node *nvram_node;
++	struct platform_device *nvram_dev;
++	struct bcm53xx_sprom_fill fill;
++
++	/* Alloc */
++	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
++	if (!sprom)
++		return -ENOMEM;
++
++	handle = of_get_property(np, "nvram", NULL);
++	if (!handle)
++		return -ENOMEM;
++
++	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));
++	if (!nvram_node)
++		return -ENOMEM;
++
++	nvram_dev = of_find_device_by_node(nvram_node);
++	if (!nvram_dev)
++		return -ENOMEM;
++
++	fill.prefix = NULL;
++	fill.fallback = false;
++	fill.getenv = bcm53xx_sprom_getenv;
++	fill.priv = nvram_dev;
++
++	bcm53xx_sprom_fill(sprom, &fill);
++
++	platform_set_drvdata(pdev, sprom);
++
++	return 0;
++}
++
++static const struct of_device_id bcm53xx_sprom_of_match_table[] = {
++	{ .compatible = "brcm,bcm53xx-sprom", },
++	{},
++};
++MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
++
++static struct platform_driver bcm53xx_sprom_driver = {
++	.driver = {
++		.owner = THIS_MODULE,
++		.name = "bcm53xx-sprom",
++		.of_match_table = bcm53xx_sprom_of_match_table,
++		/* driver unloading/unbinding currently not supported */
++		.suppress_bind_attrs = true,
++	},
++	.probe = bcm53xx_sprom_probe,
++};
++module_platform_driver(bcm53xx_sprom_driver);
++
++MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
++MODULE_LICENSE("GPLv2");
diff --git a/target/linux/bcm53xx/patches-3.14/112-bcma-get-irqs-from-dt.patch b/target/linux/bcm53xx/patches-3.14/112-bcma-get-irqs-from-dt.patch
deleted file mode 100644
index 89faea227f..0000000000
--- a/target/linux/bcm53xx/patches-3.14/112-bcma-get-irqs-from-dt.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From 06a21484198df9a4d34fe5062878d3bf4fc14340 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Thu, 9 Jan 2014 19:40:14 +0100
-Subject: [PATCH 7/8] bcma: get irqs from dt
-
----
- drivers/bcma/main.c |   42 +++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 41 insertions(+), 1 deletion(-)
-
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -10,6 +10,8 @@
- #include <linux/platform_device.h>
- #include <linux/bcma/bcma.h>
- #include <linux/slab.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_address.h>
- 
- MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
- MODULE_LICENSE("GPL");
-@@ -120,6 +122,38 @@ static void bcma_release_core_dev(struct
- 	kfree(core);
- }
- 
-+static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
-+						     struct bcma_device *core)
-+{
-+	struct device_node *node;
-+	u64 size;
-+	const __be32 *reg;
-+
-+	if (!parent || !parent->dev.of_node)
-+		return NULL;
-+
-+	for_each_child_of_node(parent->dev.of_node, node) {
-+		reg = of_get_address(node, 0, &size, 0);
-+		if (!reg)
-+			continue;
-+		if (be32_to_cpup(reg) == core->addr)
-+			return node;
-+	}
-+	return NULL;
-+}
-+
-+static void bcma_of_fill_device(struct platform_device *parent,
-+				struct bcma_device *core)
-+{
-+	struct device_node *node;
-+
-+	node = bcma_of_find_child_device(parent, core);
-+	if (!node)
-+		return;
-+	core->dev.of_node = node;
-+	core->irq = irq_of_parse_and_map(node, 0);
-+}
-+
- static int bcma_register_cores(struct bcma_bus *bus)
- {
- 	struct bcma_device *core;
-@@ -154,7 +188,13 @@ static int bcma_register_cores(struct bc
- 			break;
- 		case BCMA_HOSTTYPE_SOC:
- 			core->dev.dma_mask = &core->dev.coherent_dma_mask;
--			core->dma_dev = &core->dev;
-+			if (bus->host_pdev) {
-+				core->dma_dev = &bus->host_pdev->dev;
-+				core->dev.parent = &bus->host_pdev->dev;
-+				bcma_of_fill_device(bus->host_pdev, core);
-+			} else {
-+				core->dma_dev = &core->dev;
-+			}
- 			break;
- 		case BCMA_HOSTTYPE_SDIO:
- 			break;
diff --git a/target/linux/bcm53xx/patches-3.14/120-bcma-register-bcma-as-device-tree-driver.patch b/target/linux/bcm53xx/patches-3.14/120-bcma-register-bcma-as-device-tree-driver.patch
new file mode 100644
index 0000000000..d885c5c4e8
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/120-bcma-register-bcma-as-device-tree-driver.patch
@@ -0,0 +1,115 @@
+From bb5d497aeceb8d9f36a1d990538389b54748dfcd Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 6 Jan 2014 23:29:15 +0100
+Subject: [PATCH 05/15] bcma: register bcma as device tree driver
+
+This driver is used by the bcm53xx ARM SoC code.Now it is possible to
+give the address of the chipcommon core in device tree.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/host_soc.c   | 70 +++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/bcma/bcma.h |  2 ++
+ 2 files changed, 72 insertions(+)
+
+--- a/drivers/bcma/host_soc.c
++++ b/drivers/bcma/host_soc.c
+@@ -7,6 +7,9 @@
+ 
+ #include "bcma_private.h"
+ #include "scan.h"
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
+ #include <linux/bcma/bcma.h>
+ #include <linux/bcma/bcma_soc.h>
+ 
+@@ -173,6 +176,7 @@ int __init bcma_host_soc_register(struct
+ 	/* Host specific */
+ 	bus->hosttype = BCMA_HOSTTYPE_SOC;
+ 	bus->ops = &bcma_host_soc_ops;
++	bus->host_pdev = NULL;
+ 
+ 	/* Register */
+ 	err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
+@@ -181,3 +185,69 @@ int __init bcma_host_soc_register(struct
+ 
+ 	return err;
+ }
++
++#ifdef CONFIG_OF
++static int bcma_host_soc_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *np = dev->of_node;
++	struct bcma_bus *bus;
++	int err;
++
++	/* Alloc */
++	bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL);
++	if (!bus)
++		return -ENOMEM;
++
++	/* Map MMIO */
++	bus->mmio = of_iomap(np, 0);
++	if (!bus->mmio)
++		return -ENOMEM;
++
++	/* Host specific */
++	bus->hosttype = BCMA_HOSTTYPE_SOC;
++	bus->ops = &bcma_host_soc_ops;
++	bus->host_pdev = pdev;
++
++	/* Register */
++	err = bcma_bus_register(bus);
++	if (err)
++		goto err_unmap_mmio;
++
++	platform_set_drvdata(pdev, bus);
++
++	return err;
++
++err_unmap_mmio:
++	iounmap(bus->mmio);
++	return err;
++}
++
++static int bcma_host_soc_remove(struct platform_device *pdev)
++{
++	struct bcma_bus *bus = platform_get_drvdata(pdev);
++
++	bcma_bus_unregister(bus);
++	iounmap(bus->mmio);
++	platform_set_drvdata(pdev, NULL);
++
++	return 0;
++}
++
++static const struct of_device_id bcma_host_soc_of_match[] = {
++	{ .compatible = "brcm,bus-aix", },
++	{},
++};
++MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match);
++
++static struct platform_driver bcma_host_soc_driver = {
++	.driver = {
++		.name = "bcma-host-soc",
++		.owner = THIS_MODULE,
++		.of_match_table = bcma_host_soc_of_match,
++	},
++	.probe		= bcma_host_soc_probe,
++	.remove		= bcma_host_soc_remove,
++};
++module_platform_driver(bcma_host_soc_driver);
++#endif /* CONFIG_OF */
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -319,6 +319,8 @@ struct bcma_bus {
+ 		struct pci_dev *host_pci;
+ 		/* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
+ 		struct sdio_func *host_sdio;
++		/* Pointer to platform device (only for BCMA_HOSTTYPE_SOC) */
++		struct platform_device *host_pdev;
+ 	};
+ 
+ 	struct bcma_chipinfo chipinfo;
diff --git a/target/linux/bcm53xx/patches-3.14/121-bcma-get-irqs-from-dt.patch b/target/linux/bcm53xx/patches-3.14/121-bcma-get-irqs-from-dt.patch
new file mode 100644
index 0000000000..28ad8d514c
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/121-bcma-get-irqs-from-dt.patch
@@ -0,0 +1,76 @@
+From 3e59da41882a408064cd23f4c9124a7938bdb91f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 9 Jan 2014 19:40:14 +0100
+Subject: [PATCH 06/15] bcma: get irqs from dt
+
+If bcma was registered with device tree it will search for some nodes
+with the irq number and add it to the core configuration.
+---
+ drivers/bcma/main.c | 42 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 41 insertions(+), 1 deletion(-)
+
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -10,6 +10,8 @@
+ #include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+ #include <linux/slab.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
+ 
+ MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
+ MODULE_LICENSE("GPL");
+@@ -120,6 +122,38 @@ static void bcma_release_core_dev(struct
+ 	kfree(core);
+ }
+ 
++static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
++						     struct bcma_device *core)
++{
++	struct device_node *node;
++	u64 size;
++	const __be32 *reg;
++
++	if (!parent || !parent->dev.of_node)
++		return NULL;
++
++	for_each_child_of_node(parent->dev.of_node, node) {
++		reg = of_get_address(node, 0, &size, 0);
++		if (!reg)
++			continue;
++		if (be32_to_cpup(reg) == core->addr)
++			return node;
++	}
++	return NULL;
++}
++
++static void bcma_of_fill_device(struct platform_device *parent,
++				struct bcma_device *core)
++{
++	struct device_node *node;
++
++	node = bcma_of_find_child_device(parent, core);
++	if (!node)
++		return;
++	core->dev.of_node = node;
++	core->irq = irq_of_parse_and_map(node, 0);
++}
++
+ static int bcma_register_cores(struct bcma_bus *bus)
+ {
+ 	struct bcma_device *core;
+@@ -154,7 +188,13 @@ static int bcma_register_cores(struct bc
+ 			break;
+ 		case BCMA_HOSTTYPE_SOC:
+ 			core->dev.dma_mask = &core->dev.coherent_dma_mask;
+-			core->dma_dev = &core->dev;
++			if (bus->host_pdev) {
++				core->dma_dev = &bus->host_pdev->dev;
++				core->dev.parent = &bus->host_pdev->dev;
++				bcma_of_fill_device(bus->host_pdev, core);
++			} else {
++				core->dma_dev = &core->dev;
++			}
+ 			break;
+ 		case BCMA_HOSTTYPE_SDIO:
+ 			break;
diff --git a/target/linux/bcm53xx/patches-3.14/123-bcma-get-sprom-from-devicetree.patch b/target/linux/bcm53xx/patches-3.14/123-bcma-get-sprom-from-devicetree.patch
new file mode 100644
index 0000000000..e071641088
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/123-bcma-get-sprom-from-devicetree.patch
@@ -0,0 +1,88 @@
+From 5d94449a92e4121b408e7cb8931a47984135eeea Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 4 May 2014 14:34:31 +0200
+Subject: [PATCH 07/15] bcma: get sprom from devicetree
+
+This patch make it possible to device an sprom provider in device tree
+and get the sprom from this driver. Every time there is such a provider
+it gets asked for a sprom.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/sprom.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 50 insertions(+), 1 deletion(-)
+
+--- a/drivers/bcma/sprom.c
++++ b/drivers/bcma/sprom.c
+@@ -15,6 +15,8 @@
+ #include <linux/io.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
+ 
+ static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
+ 
+@@ -46,6 +48,46 @@ int bcma_arch_register_fallback_sprom(in
+ 	return 0;
+ }
+ 
++#ifdef CONFIG_OF
++static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
++				   struct ssb_sprom *out)
++{
++	const phandle *handle;
++	struct device_node *sprom_node;
++	struct platform_device *sprom_dev;
++	struct ssb_sprom *sprom;
++
++	if (!bus->host_pdev || !bus->host_pdev->dev.of_node)
++		return -ENOENT;
++
++	handle = of_get_property(bus->host_pdev->dev.of_node, "sprom", NULL);
++	if (!handle)
++		return -ENOENT;
++
++	sprom_node = of_find_node_by_phandle(be32_to_cpup(handle));
++	if (!sprom_node)
++		return -ENOENT;
++
++	sprom_dev = of_find_device_by_node(sprom_node);
++	if (!sprom_dev)
++		return -ENOENT;
++
++	sprom = platform_get_drvdata(sprom_dev);
++	if (!sprom)
++		return -ENOENT;
++
++	memcpy(out, sprom, sizeof(*out));
++
++	return 0;
++}
++#else
++static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
++				   struct ssb_sprom *out)
++{
++	return -ENOENT;
++}
++#endif
++
+ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
+ 					 struct ssb_sprom *out)
+ {
+@@ -553,7 +595,14 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ 	u16 *sprom;
+ 	size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
+ 				 SSB_SPROMSIZE_WORDS_R10, };
+-	int i, err = 0;
++	int i, err;
++
++	err = bcma_fill_sprom_with_dt(bus, &bus->sprom);
++	if (err == 0) {
++		bcma_info(bus, "Found sprom from device tree provider\n");
++		return 0;
++	}
++	err = 0;
+ 
+ 	if (!bus->drv_cc.core)
+ 		return -EOPNOTSUPP;
diff --git a/target/linux/bcm53xx/patches-3.14/130-ARM-BCM5301X-register-bcma-bus.patch b/target/linux/bcm53xx/patches-3.14/130-ARM-BCM5301X-register-bcma-bus.patch
new file mode 100644
index 0000000000..9d01f3311a
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/130-ARM-BCM5301X-register-bcma-bus.patch
@@ -0,0 +1,74 @@
+From 23bcd5e7cb2aaee48ba8b2351f032a230d948b6f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 25 Jan 2014 17:03:07 +0100
+Subject: [PATCH 08/15] ARM: BCM5301X: register bcma bus
+
+---
+ arch/arm/boot/dts/bcm4708.dtsi | 58 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 58 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4708.dtsi
++++ b/arch/arm/boot/dts/bcm4708.dtsi
+@@ -31,4 +31,62 @@
+ 		};
+ 	};
+ 
++	nvram0: nvram@0 {
++		compatible = "brcm,bcm47xx-nvram";
++		reg = <0x1c000000 0x01000000>;
++	};
++
++	sprom0: sprom@0 {
++		compatible = "brcm,bcm53xx-sprom";
++		nvram = <&nvram0>;
++	};
++
++	aix@18000000 {
++		compatible = "brcm,bus-aix";
++		reg = <0x18000000 0x1000>;
++		ranges = <0x00000000 0x18000000 0x00100000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++		sprom = <&sprom0>;
++
++		usb2@0 {
++			reg = <0x18021000 0x1000>;
++			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
++		usb3@0 {
++			reg = <0x18023000 0x1000>;
++			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
++		gmac@0 {
++			reg = <0x18024000 0x1000>;
++			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
++		gmac@1 {
++			reg = <0x18025000 0x1000>;
++			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
++		gmac@2 {
++			reg = <0x18026000 0x1000>;
++			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
++		gmac@3 {
++			reg = <0x18027000 0x1000>;
++			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
++		pcie@0 {
++			reg = <0x18012000 0x1000>;
++			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
++		pcie@1 {
++			reg = <0x18013000 0x1000>;
++			interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
++		};
++	};
+ };
diff --git a/target/linux/bcm53xx/patches-3.14/140-bcma-only-map-wrap-if-it-is-not-null.patch b/target/linux/bcm53xx/patches-3.14/140-bcma-only-map-wrap-if-it-is-not-null.patch
new file mode 100644
index 0000000000..30e03e30e4
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/140-bcma-only-map-wrap-if-it-is-not-null.patch
@@ -0,0 +1,32 @@
+From f8ea60bbaf880d8d8d99fde3b5155f472e00141f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 12 May 2014 20:16:39 +0200
+Subject: [PATCH 09/15] bcma: only map wrap if it is not null
+
+The chipcommon B core does not have a wrap address and it would fail here.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/scan.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -421,10 +421,13 @@ static int bcma_get_next_core(struct bcm
+ 		core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
+ 		if (!core->io_addr)
+ 			return -ENOMEM;
+-		core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
+-		if (!core->io_wrap) {
+-			iounmap(core->io_addr);
+-			return -ENOMEM;
++		if (core->wrap) {
++			core->io_wrap = ioremap_nocache(core->wrap,
++							BCMA_CORE_SIZE);
++			if (!core->io_wrap) {
++				iounmap(core->io_addr);
++				return -ENOMEM;
++			}
+ 		}
+ 	}
+ 	return 0;
diff --git a/target/linux/bcm53xx/patches-3.14/141-bcma-store-more-alternative-addresses.patch b/target/linux/bcm53xx/patches-3.14/141-bcma-store-more-alternative-addresses.patch
new file mode 100644
index 0000000000..7a011cac4c
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/141-bcma-store-more-alternative-addresses.patch
@@ -0,0 +1,71 @@
+From 9317024aa1d8df94d3b021bc23b57f02a435e96c Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 12 May 2014 21:57:53 +0200
+Subject: [PATCH 10/15] bcma: store more alternative addresses
+
+Each core could have more than one alternative address. There are cores
+with 8 alternative addresses for different functions. The PHY control
+in the Chip common B core is done through the 2. alternative address
+and not the first one.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/scan.c         | 9 +++++----
+ drivers/usb/host/bcma-hcd.c | 2 +-
+ include/linux/bcma/bcma.h   | 2 +-
+ 3 files changed, 7 insertions(+), 6 deletions(-)
+
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -276,7 +276,7 @@ static int bcma_get_next_core(struct bcm
+ 			      struct bcma_device *core)
+ {
+ 	u32 tmp;
+-	u8 i, j;
++	u8 i, j, k;
+ 	s32 cia, cib;
+ 	u8 ports[2], wrappers[2];
+ 
+@@ -367,6 +367,7 @@ static int bcma_get_next_core(struct bcm
+ 	core->addr = tmp;
+ 
+ 	/* get & parse slave ports */
++	k = 0;
+ 	for (i = 0; i < ports[1]; i++) {
+ 		for (j = 0; ; j++) {
+ 			tmp = bcma_erom_get_addr_desc(bus, eromptr,
+@@ -376,9 +377,9 @@ static int bcma_get_next_core(struct bcm
+ 				/* pr_debug("erom: slave port %d "
+ 				 * "has %d descriptors\n", i, j); */
+ 				break;
+-			} else {
+-				if (i == 0 && j == 0)
+-					core->addr1 = tmp;
++			} else if (k < 8) {
++				core->addr_s[k] = tmp;
++				k++;
+ 			}
+ 		}
+ 	}
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -237,7 +237,7 @@ static int bcma_hcd_probe(struct bcma_de
+ 	bcma_hcd_init_chip(dev);
+ 
+ 	/* In AI chips EHCI is addrspace 0, OHCI is 1 */
+-	ohci_addr = dev->addr1;
++	ohci_addr = dev->addr_s[0];
+ 	if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749)
+ 	    && chipinfo->rev == 0)
+ 		ohci_addr = 0x18009000;
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -263,7 +263,7 @@ struct bcma_device {
+ 	u8 core_unit;
+ 
+ 	u32 addr;
+-	u32 addr1;
++	u32 addr_s[8];
+ 	u32 wrap;
+ 
+ 	void __iomem *io_addr;
diff --git a/target/linux/bcm53xx/patches-3.14/142-bcma-add-support-for-chipcommon-B-core.patch b/target/linux/bcm53xx/patches-3.14/142-bcma-add-support-for-chipcommon-B-core.patch
new file mode 100644
index 0000000000..9fdf66af08
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/142-bcma-add-support-for-chipcommon-B-core.patch
@@ -0,0 +1,180 @@
+From 6c0df4a483e41ef129caa8948b3bcde7f91de197 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 12 May 2014 20:33:15 +0200
+Subject: [PATCH 11/15] bcma: add support for chipcommon B core
+
+This core is used on BCM4708 to configure the PCIe and USB3 PHYs and it
+contains the addresses to the Device Management unit. This will be used
+by the PCIe driver first.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/Makefile                       |  1 +
+ drivers/bcma/bcma_private.h                 |  4 ++
+ drivers/bcma/driver_chipcommon_b.c          | 59 +++++++++++++++++++++++++++++
+ drivers/bcma/main.c                         | 10 +++++
+ drivers/bcma/scan.c                         |  1 +
+ include/linux/bcma/bcma.h                   |  1 +
+ include/linux/bcma/bcma_driver_chipcommon.h |  8 ++++
+ 7 files changed, 84 insertions(+)
+ create mode 100644 drivers/bcma/driver_chipcommon_b.c
+
+--- a/drivers/bcma/Makefile
++++ b/drivers/bcma/Makefile
+@@ -1,5 +1,6 @@
+ bcma-y					+= main.o scan.o core.o sprom.o
+ bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
++bcma-y					+= driver_chipcommon_b.o
+ bcma-$(CONFIG_BCMA_SFLASH)		+= driver_chipcommon_sflash.o
+ bcma-$(CONFIG_BCMA_NFLASH)		+= driver_chipcommon_nflash.o
+ bcma-y					+= driver_pci.o
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -50,6 +50,10 @@ void bcma_chipco_serial_init(struct bcma
+ extern struct platform_device bcma_pflash_dev;
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
+ 
++/* driver_chipcommon_b.c */
++int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
++void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb);
++
+ /* driver_chipcommon_pmu.c */
+ u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
+ u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
+--- /dev/null
++++ b/drivers/bcma/driver_chipcommon_b.c
+@@ -0,0 +1,59 @@
++/*
++ * Broadcom specific AMBA
++ * ChipCommon B Unit driver
++ *
++ * Copyright 2011, 2014, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include <linux/export.h>
++#include <linux/bcma/bcma.h>
++
++static bool bcma_wait_reg(void __iomem *addr, u32 mask, u32 value,
++		     int timeout)
++{
++	unsigned long deadline = jiffies + timeout;
++	u32 val;
++
++	do {
++		val = readl(addr);
++		if ((val & mask) == value)
++			return true;
++		cpu_relax();
++		udelay(10);
++	} while (!time_after_eq(jiffies, deadline));
++
++	pr_warn("Timeout waiting for register %p!\n", addr);
++
++	return false;
++}
++
++void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
++{
++	writel(offset, ccb->mii + 0x00);
++	bcma_wait_reg(ccb->mii + 0x00, 0x0100, 0x0000, 100);
++	writel(value, ccb->mii + 0x04);
++	bcma_wait_reg(ccb->mii + 0x00, 0x0100, 0x0000, 100);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write);
++
++int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb)
++{
++	if (ccb->setup_done)
++		return 0;
++
++	ccb->setup_done = 1;
++	ccb->mii = ioremap_nocache(ccb->core->addr_s[1], BCMA_CORE_SIZE);
++	if (!ccb->mii)
++		return -ENOMEM;
++
++	return 0;
++}
++
++void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb)
++{
++	if (ccb->mii)
++		iounmap(ccb->mii);
++}
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -164,6 +164,7 @@ static int bcma_register_cores(struct bc
+ 		switch (core->id.id) {
+ 		case BCMA_CORE_4706_CHIPCOMMON:
+ 		case BCMA_CORE_CHIPCOMMON:
++		case BCMA_CORE_CHIPCOMMON_B:
+ 		case BCMA_CORE_PCI:
+ 		case BCMA_CORE_PCIE:
+ 		case BCMA_CORE_MIPS_74K:
+@@ -300,6 +301,13 @@ int bcma_bus_register(struct bcma_bus *b
+ 		bcma_core_chipcommon_init(&bus->drv_cc);
+ 	}
+ 
++	/* Init CC core */
++	core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON_B);
++	if (core) {
++		bus->drv_cc_b.core = core;
++		bcma_core_chipcommon_b_init(&bus->drv_cc_b);
++	}
++
+ 	/* Init MIPS core */
+ 	core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+ 	if (core) {
+@@ -347,6 +355,8 @@ void bcma_bus_unregister(struct bcma_bus
+ 	else if (err)
+ 		bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
+ 
++	bcma_core_chipcommon_b_free(&bus->drv_cc_b);
++
+ 	cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+ 	cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
+ 	cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -314,6 +314,7 @@ static int bcma_get_next_core(struct bcm
+ 		/* Some specific cores don't need wrappers */
+ 		switch (core->id.id) {
+ 		case BCMA_CORE_4706_MAC_GBIT_COMMON:
++		case BCMA_CORE_CHIPCOMMON_B:
+ 		/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
+ 			break;
+ 		default:
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -334,6 +334,7 @@ struct bcma_bus {
+ 	u8 num;
+ 
+ 	struct bcma_drv_cc drv_cc;
++	struct bcma_drv_cc_b drv_cc_b;
+ 	struct bcma_drv_pci drv_pci[2];
+ 	struct bcma_drv_mips drv_mips;
+ 	struct bcma_drv_gmac_cmn drv_gmac_cmn;
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -644,6 +644,12 @@ struct bcma_drv_cc {
+ #endif
+ };
+ 
++struct bcma_drv_cc_b {
++	struct bcma_device *core;
++	u8 setup_done:1;
++	void __iomem *mii;
++};
++
+ /* Register access */
+ #define bcma_cc_read32(cc, offset) \
+ 	bcma_read32((cc)->core, offset)
+@@ -699,4 +705,6 @@ extern void bcma_pmu_spuravoid_pllupdate
+ 
+ extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc);
+ 
++void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value);
++
+ #endif /* LINUX_BCMA_DRIVER_CC_H_ */
diff --git a/target/linux/bcm53xx/patches-3.14/150-pci-do-not-probe-too-early.patch b/target/linux/bcm53xx/patches-3.14/150-pci-do-not-probe-too-early.patch
new file mode 100644
index 0000000000..23e8a02b19
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/150-pci-do-not-probe-too-early.patch
@@ -0,0 +1,29 @@
+From ea422113a5d2778347db6136d95f45a50e2f2d29 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 29 May 2014 20:54:15 +0200
+Subject: [PATCH 13/15] pci: do not probe too early
+
+Probing is done before the PCIe bridge is fully activated and the
+address spaces does not get assigned to the PCIe devices. Without the
+address space the driver can not register to this device. With this
+patch the driver reregistration is done later.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/pci/probe.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -1912,7 +1912,10 @@ struct pci_bus *pci_scan_root_bus(struct
+ 	if (!found)
+ 		pci_bus_update_busn_res_end(b, max);
+ 
+-	pci_bus_add_devices(b);
++	/* this should be done in arch/arm/kernel/bios32.c, because the
++	   resources for the PCI devices are initilized later and doing
++	   it here will fail. */
++	/* pci_bus_add_devices(b); */
+ 	return b;
+ }
+ EXPORT_SYMBOL(pci_scan_root_bus);
diff --git a/target/linux/bcm53xx/patches-3.14/160-bcma-add-PCI-IDs-for-more-devices.patch b/target/linux/bcm53xx/patches-3.14/160-bcma-add-PCI-IDs-for-more-devices.patch
new file mode 100644
index 0000000000..c87bdd7534
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/160-bcma-add-PCI-IDs-for-more-devices.patch
@@ -0,0 +1,24 @@
+From a0d83e0ad20f6dde0a71ed07da12ca3be8bbdc01 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 18 May 2014 17:15:24 +0200
+Subject: [PATCH 12/15] bcma: add PCI IDs for more devices
+
+This adds the PCI IDs for the BCM4360 and BCM43227.
+Both devices were found on a Netgear R6250 with a BCM4708 ARM SoC.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/host_pci.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -280,6 +280,8 @@ static const struct pci_device_id bcma_p
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
+ 	{ 0, },
+ };
+ MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
diff --git a/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch b/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch
new file mode 100644
index 0000000000..cfc231cf94
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch
@@ -0,0 +1,645 @@
+From 7475eee716d11f487076f78f26a6e403c06d0c76 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 12 May 2014 11:55:20 +0200
+Subject: [PATCH 14/15] pcie2-bcma: add new PCIe2 driver for bcma
+
+This driver supports the PCIe controller found on the BCM4708 and
+similar SoCs. The controller itself is automatically detected by bcma.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/arm/mach-bcm/Kconfig     |   1 +
+ drivers/pci/host/Kconfig      |   7 +
+ drivers/pci/host/Makefile     |   1 +
+ drivers/pci/host/pcie2-bcma.c | 594 ++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 603 insertions(+)
+ create mode 100644 drivers/pci/host/pcie2-bcma.c
+
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -45,6 +45,7 @@ config ARCH_BCM_5301X
+ 	select ARM_GLOBAL_TIMER
+ 	select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+ 	select MIGHT_HAVE_PCI
++	select PCI_DOMAINS if PCI
+ 	help
+ 	  Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores.
+ 
+--- a/drivers/pci/host/Kconfig
++++ b/drivers/pci/host/Kconfig
+@@ -33,4 +33,11 @@ config PCI_RCAR_GEN2
+ 	  There are 3 internal PCI controllers available with a single
+ 	  built-in EHCI/OHCI host controller present on each one.
+ 
++config PCI_BCMA
++	bool "BCMA PCIe2 host controller"
++	depends on BCMA && OF
++	help
++	  Say Y here if you want to support a simple generic PCI host
++	  controller, such as the one emulated by kvmtool.
++
+ endmenu
+--- a/drivers/pci/host/Makefile
++++ b/drivers/pci/host/Makefile
+@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
+ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
+ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
+ obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
++obj-$(CONFIG_PCI_BCMA) += pcie2-bcma.o
+--- /dev/null
++++ b/drivers/pci/host/pcie2-bcma.c
+@@ -0,0 +1,594 @@
++/*
++ * Northstar PCI-Express driver
++ * Only supports Root-Complex (RC) mode
++ *
++ * Notes:
++ * PCI Domains are being used to identify the PCIe port 1:1.
++ *
++ * Only MEM access is supported, PAX does not support IO.
++ *
++ * TODO:
++ *	MSI interrupts,
++ *	DRAM > 128 MBytes (e.g. DMA zones)
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/bug.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/bcma/bcma.h>
++
++#define SI_ENUM_BASE		0x18000000	/* Enumeration space base */
++
++/*
++ * Register offset definitions
++ */
++#define	SOC_PCIE_CONTROL	0x000	/* a.k.a. CLK_CONTROL reg */
++#define	SOC_PCIE_PM_STATUS	0x008
++#define	SOC_PCIE_PM_CONTROL	0x00c	/* in EP mode only ! */
++
++#define	SOC_PCIE_EXT_CFG_ADDR	0x120
++#define	SOC_PCIE_EXT_CFG_DATA	0x124
++#define	SOC_PCIE_CFG_ADDR	0x1f8
++#define	SOC_PCIE_CFG_DATA	0x1fc
++
++#define	SOC_PCIE_SYS_RC_INTX_EN		0x330
++#define	SOC_PCIE_SYS_RC_INTX_CSR	0x334
++#define	SOC_PCIE_SYS_HOST_INTR_EN	0x344
++#define	SOC_PCIE_SYS_HOST_INTR_CSR	0x348
++
++#define	SOC_PCIE_HDR_OFF	0x400	/* 256 bytes per function */
++
++/* 32-bit 4KB in-bound mapping windows for Function 0..3, n=0..7 */
++#define	SOC_PCIE_SYS_IMAP0(f, n)	(0xc00 + ((f) << 9)((n) << 2))
++/* 64-bit in-bound mapping windows for func 0..3 */
++#define	SOC_PCIE_SYS_IMAP1(f)		(0xc80 + ((f) << 3))
++#define	SOC_PCIE_SYS_IMAP2(f)		(0xcc0 + ((f) << 3))
++/* 64-bit in-bound address range n=0..2 */
++#define	SOC_PCIE_SYS_IARR(n)		(0xd00 + ((n) << 3))
++/* 64-bit out-bound address filter n=0..2 */
++#define	SOC_PCIE_SYS_OARR(n)		(0xd20 + ((n) << 3))
++/* 64-bit out-bound mapping windows n=0..2 */
++#define	SOC_PCIE_SYS_OMAP(n)		(0xd40 + ((n) << 3))
++
++#define BCM4360_D11AC_ID	0x43a0
++#define BCM4360_D11AC2G_ID	0x43a1
++#define BCM4360_D11AC5G_ID	0x43a2
++#define BCM4352_D11AC_ID	0x43b1	/* 4352 802.11ac dualband device */
++#define BCM4352_D11AC2G_ID	0x43b2	/* 4352 802.11ac 2.4G device */
++#define BCM4352_D11AC5G_ID	0x43b3	/* 4352 802.11ac 5G device */
++
++static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
++{
++	struct pci_sys_data *sys = pdev->sysdata;
++	struct bcma_device *bdev = sys->private_data;
++
++	return bdev->irq;
++}
++
++static u32 bcma_pcie2_cfg_base(struct bcma_device *bdev, int busno,
++			       unsigned int devfn, int where)
++{
++	int slot = PCI_SLOT(devfn);
++	int fn = PCI_FUNC(devfn);
++	u32 addr_reg;
++
++	if (busno == 0) {
++		if (slot >= 1)
++			return 0;
++		bcma_write32(bdev, SOC_PCIE_EXT_CFG_ADDR, where & 0xffc);
++		return SOC_PCIE_EXT_CFG_DATA;
++	} else {
++		if (fn > 1)
++			return 0;
++		addr_reg = (busno & 0xff) << 20 | (slot << 15) | (fn << 12) |
++			   (where & 0xffc) | (1 & 0x3);
++
++		bcma_write32(bdev, SOC_PCIE_CFG_ADDR, addr_reg);
++		return SOC_PCIE_CFG_DATA;
++	}
++}
++
++static u32 bcma_pcie2_read_config(struct bcma_device *bdev, int busno,
++				  unsigned int devfn, int where, int size)
++{
++	u32 base;
++	u32 data_reg;
++
++	base = bcma_pcie2_cfg_base(bdev, busno, devfn, where);
++
++	if (!base)
++		return ~0UL;
++
++	data_reg = bcma_read32(bdev, base);
++
++	/* NS: CLASS field is R/O, and set to wrong 0x200 value */
++	if (busno == 0 && devfn == 0) {
++		/*
++		 * RC's class is 0x0280, but Linux PCI driver needs 0x604
++		 * for a PCIe bridge. So we must fixup the class code
++		 * to 0x604 here.
++		 */
++		if ((where & 0xffc) == PCI_CLASS_REVISION) {
++			data_reg &= 0xff;
++			data_reg |= 0x604 << 16;
++		}
++	}
++	/* HEADER_TYPE=00 indicates the port in EP mode */
++
++	if (size == 4) {
++		return data_reg;
++	} else {
++		u32 mask = (1 << (size * 8)) - 1;
++		int shift = (where % 4) * 8;
++		return (data_reg >> shift) & mask;
++	}
++}
++
++static void bcma_pcie2_write_config(struct bcma_device *bdev, int busno,
++				    unsigned int devfn, int where, int size,
++				    u32 val)
++{
++	u32 base;
++	u32 data_reg;
++
++	base = bcma_pcie2_cfg_base(bdev, busno, devfn, where);
++
++	if (!base)
++		return;
++
++	if (size < 4) {
++		u32 mask = (1 << (size * 8)) - 1;
++		int shift = (where % 4) * 8;
++		data_reg = bcma_read32(bdev, base);
++		data_reg &= ~(mask << shift);
++		data_reg |= (val & mask) << shift;
++	} else {
++		data_reg = val;
++	}
++
++	bcma_write32(bdev, base, data_reg);
++}
++
++static u8 bcma_pcie2_read_config8(struct bcma_device *bdev, int busno,
++				  unsigned int devfn, int where)
++{
++	return bcma_pcie2_read_config(bdev, busno, devfn, where, 1);
++}
++
++static u16 bcma_pcie2_read_config16(struct bcma_device *bdev, int busno,
++				    unsigned int devfn, int where)
++{
++	return bcma_pcie2_read_config(bdev, busno, devfn, where, 2);
++}
++
++static u32 bcma_pcie2_read_config32(struct bcma_device *bdev, int busno,
++				    unsigned int devfn, int where)
++{
++	return bcma_pcie2_read_config(bdev, busno, devfn, where, 4);
++}
++
++static void bcma_pcie2_write_config8(struct bcma_device *bdev, int busno,
++				     unsigned int devfn, int where, u8 val)
++{
++	return bcma_pcie2_write_config(bdev, busno, devfn, where, 1, val);
++}
++
++static void bcma_pcie2_write_config16(struct bcma_device *bdev, int busno,
++				      unsigned int devfn, int where, u16 val)
++{
++	return bcma_pcie2_write_config(bdev, busno, devfn, where, 2, val);
++}
++
++static void bcma_pcie2_write_config32(struct bcma_device *bdev, int busno,
++				      unsigned int devfn, int where, u32 val)
++{
++	return bcma_pcie2_write_config(bdev, busno, devfn, where, 4, val);
++}
++
++static int bcma_pcie2_read_config_pci(struct pci_bus *bus, unsigned int devfn,
++				   int where, int size, u32 *val)
++{
++	struct pci_sys_data *sys = bus->sysdata;
++	struct bcma_device *bdev = sys->private_data;
++
++	*val = bcma_pcie2_read_config(bdev, bus->number, devfn, where, size);
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int bcma_pcie2_write_config_pci(struct pci_bus *bus, unsigned int devfn,
++				    int where, int size, u32 val)
++{
++	struct pci_sys_data *sys = bus->sysdata;
++	struct bcma_device *bdev = sys->private_data;
++
++	bcma_pcie2_write_config(bdev, bus->number, devfn, where, size, val);
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++/*
++ * Check link status, return 0 if link is up in RC mode,
++ * otherwise return non-zero
++ */
++static int bcma_pcie2_check_link(struct bcma_device *bdev, u32 allow_gen2)
++{
++	u32 devfn = 0;
++	u8 tmp8;
++	u32 tmp32;
++
++	tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xdc);
++	tmp32 &= ~0xf;
++	if (allow_gen2)
++		tmp32 |= 2;
++	else {
++		/* force PCIE GEN1 */
++		tmp32 |= 1;
++	}
++	bcma_pcie2_write_config32(bdev, 0, devfn, 0xdc, tmp32);
++
++	/* See if the port is in EP mode, indicated by header type 00 */
++	tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_HEADER_TYPE);
++	if (tmp8 != PCI_HEADER_TYPE_BRIDGE) {
++		dev_info(&bdev->dev, "Port %d in End-Point mode - ignored\n",
++			 bdev->core_unit);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++/*
++ * Initializte the PCIe controller
++ */
++static void bcma_pcie2_hw_init(struct bcma_device *bdev)
++{
++	u32 devfn = 0;
++	u32 tmp32;
++	u16 tmp16;
++
++	/* Change MPS and MRRS to 512 */
++	tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, 0x4d4);
++	tmp16 &= ~7;
++	tmp16 |= 2;
++	bcma_pcie2_write_config16(bdev, 0, devfn, 0x4d4, tmp16);
++
++	tmp32 = bcma_pcie2_read_config32(bdev, 0, devfn, 0xb4);
++	tmp32 &= ~((7 << 12) | (7 << 5));
++	tmp32 |= (2 << 12) | (2 << 5);
++	bcma_pcie2_write_config32(bdev, 0, devfn, 0xb4, tmp32);
++
++	/* Turn-on Root-Complex (RC) mode, from reset defailt of EP */
++
++	/* The mode is set by straps, can be overwritten via DMU
++	   register <cru_straps_control> bit 5, "1" means RC
++	 */
++
++	/* Send a downstream reset */
++	bcma_write32(bdev, SOC_PCIE_CONTROL, 0x3);
++	udelay(250);
++	bcma_write32(bdev, SOC_PCIE_CONTROL, 0x1);
++	mdelay(250);
++
++	/* TBD: take care of PM, check we're on */
++}
++
++/*
++ * Setup the address translation
++ */
++static void bcma_pcie2_map_init(struct bcma_device *bdev)
++{
++	unsigned size, i;
++	u32 addr;
++
++	/*
++	 * NOTE:
++	 * All PCI-to-CPU address mapping are 1:1 for simplicity
++	 */
++
++	/* Outbound address translation setup */
++	size = SZ_128M;
++	addr = bdev->addr_s[0];
++	BUG_ON(!addr);
++	BUG_ON(addr & ((1 << 25) - 1));	/* 64MB alignment */
++
++	for (i = 0; i < 3; i++) {
++		const unsigned win_size = SZ_64M;
++		/* 64-bit LE regs, write low word, high is 0 at reset */
++		bcma_write32(bdev, SOC_PCIE_SYS_OMAP(i), addr);
++		bcma_write32(bdev, SOC_PCIE_SYS_OARR(i), addr|0x1);
++		addr += win_size;
++		if (size >= win_size)
++			size -= win_size;
++		if (size == 0)
++			break;
++	}
++	WARN_ON(size > 0);
++
++	/*
++	 * Inbound address translation setup
++	 * Northstar only maps up to 128 MiB inbound, DRAM could be up to 1 GiB.
++	 *
++	 * For now allow access to entire DRAM, assuming it is less than 128MiB,
++	 * otherwise DMA bouncing mechanism may be required.
++	 * Also consider DMA mask to limit DMA physical address
++	 */
++	size = SZ_128M;
++	addr = PHYS_OFFSET;
++
++	size >>= 20;	/* In MB */
++	size &= 0xff;	/* Size is an 8-bit field */
++
++	WARN_ON(size == 0);
++	/* 64-bit LE regs, write low word, high is 0 at reset */
++	bcma_write32(bdev, SOC_PCIE_SYS_IMAP1(0), addr | 0x1);
++	bcma_write32(bdev, SOC_PCIE_SYS_IARR(1), addr | size);
++
++#ifdef CONFIG_SPARSEMEM
++	addr = PHYS_OFFSET2;
++	bcma_write32(bdev, SOC_PCIE_SYS_IMAP2(0), addr | 0x1);
++	bcma_write32(bdev, SOC_PCIE_SYS_IARR(2), addr | size);
++#endif
++}
++
++/*
++ * Setup PCIE Host bridge
++ */
++static void bcma_pcie2_bridge_init(struct bcma_device *bdev)
++{
++	u32 devfn = 0;
++	u8 tmp8;
++	u16 tmp16;
++
++	bcma_pcie2_write_config8(bdev, 0, devfn, PCI_PRIMARY_BUS, 0);
++	bcma_pcie2_write_config8(bdev, 0, devfn, PCI_SECONDARY_BUS, 1);
++	bcma_pcie2_write_config8(bdev, 0, devfn, PCI_SUBORDINATE_BUS, 4);
++
++	tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_PRIMARY_BUS);
++	tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_SECONDARY_BUS);
++	tmp8 = bcma_pcie2_read_config8(bdev, 0, devfn, PCI_SUBORDINATE_BUS);
++
++	/* MEM_BASE, MEM_LIM require 1MB alignment */
++	BUG_ON((bdev->addr_s[0] >> 16) & 0xf);
++	bcma_pcie2_write_config16(bdev, 0, devfn, PCI_MEMORY_BASE,
++		bdev->addr_s[0] >> 16);
++	BUG_ON(((bdev->addr_s[0] + SZ_128M) >> 16) & 0xf);
++	bcma_pcie2_write_config16(bdev, 0, devfn, PCI_MEMORY_LIMIT,
++		(bdev->addr_s[0] + SZ_128M) >> 16);
++
++	/* These registers are not supported on the NS */
++	bcma_pcie2_write_config16(bdev, 0, devfn, PCI_IO_BASE_UPPER16, 0);
++	bcma_pcie2_write_config16(bdev, 0, devfn, PCI_IO_LIMIT_UPPER16, 0);
++
++	/* Force class to that of a Bridge */
++	bcma_pcie2_write_config16(bdev, 0, devfn, PCI_CLASS_DEVICE,
++				  PCI_CLASS_BRIDGE_PCI);
++
++	tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, PCI_CLASS_DEVICE);
++	tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, PCI_MEMORY_BASE);
++	tmp16 = bcma_pcie2_read_config16(bdev, 0, devfn, PCI_MEMORY_LIMIT);
++}
++
++static int bcma_pcie2_allow_gen2_rc(struct bcma_device *bdev)
++{
++	u32 vendorid, devid, chipid, chiprev;
++	u32 val, bar;
++	void __iomem *base;
++	int allow = 1;
++
++	/* Read PCI vendor/device ID's */
++	bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x0);
++	val = bcma_read32(bdev, SOC_PCIE_CFG_DATA);
++	vendorid = val & 0xffff;
++	devid = val >> 16;
++	if (vendorid == PCI_VENDOR_ID_BROADCOM &&
++	    (devid == BCMA_CHIP_ID_BCM4360 || devid == BCM4360_D11AC_ID ||
++	     devid == BCM4360_D11AC2G_ID || devid == BCM4360_D11AC5G_ID ||
++	     devid == BCM4352_D11AC_ID || devid == BCM4352_D11AC2G_ID ||
++	     devid == BCM4352_D11AC5G_ID)) {
++		/* Config BAR0 */
++		bar = bdev->addr_s[0];
++		bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x10);
++		bcma_write32(bdev, SOC_PCIE_CFG_DATA, bar);
++		/* Config BAR0 window to access chipc */
++		bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x80);
++		bcma_write32(bdev, SOC_PCIE_CFG_DATA, SI_ENUM_BASE);
++
++		/* Enable memory resource */
++		bcma_write32(bdev, SOC_PCIE_CFG_ADDR, 0x4);
++		val = bcma_read32(bdev, SOC_PCIE_CFG_DATA);
++		val |= PCI_COMMAND_MEMORY;
++		bcma_write32(bdev, SOC_PCIE_CFG_DATA, val);
++		/* Enable memory and bus master */
++		bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6);
++
++		/* Read CHIP ID */
++		base = ioremap(bar, 0x1000);
++		val = __raw_readl(base);
++		iounmap(base);
++		chipid = val & 0xffff;
++		chiprev = (val >> 16) & 0xf;
++		if ((chipid == BCMA_CHIP_ID_BCM4360 ||
++		     chipid == BCMA_CHIP_ID_BCM43460 ||
++		     chipid == BCMA_CHIP_ID_BCM4352) && (chiprev < 3))
++			allow = 0;
++	}
++	return allow;
++}
++
++static void bcma_pcie2_3rd_init(struct bcma_bus *bus)
++{
++	/* PCIE PLL block register (base 0x8000) */
++	bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x00000088, 0x57fe8000);
++	/* Check PCIE PLL lock status */
++	bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x00000088, 0x67c60000);
++}
++
++/* To improve PCIE phy jitter */
++static void bcma_pcie2_improve_phy_jitter(struct bcma_bus *bus, int phyaddr)
++{
++	u32 val;
++
++	/* Change blkaddr */
++	val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x1f << 18) |
++		(2 << 16) | (0x863 << 4);
++	bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val);
++
++	/* Write 0x0190 to 0x13 regaddr */
++	val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x13 << 18) |
++		(2 << 16) | 0x0190;
++	bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val);
++
++	/* Write 0x0191 to 0x19 regaddr */
++	val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x19 << 18) |
++		(2 << 16) | 0x0191;
++	bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val);
++}
++
++static int bcma_pcie2_setup(int nr, struct pci_sys_data *sys)
++{
++	struct bcma_device *bdev = sys->private_data;
++	struct bcma_bus *bus = bdev->bus;
++	struct resource *res;
++	struct bcma_device *arm_core;
++	u32 cru_straps_ctrl;
++	int allow_gen2, linkfail;
++	int phyaddr;
++
++	if (bdev->core_unit == 2) {
++		arm_core = bcma_find_core(bus, BCMA_CORE_ARMCA9);
++		cru_straps_ctrl = bcma_read32(arm_core, 0x2a0);
++
++		/* 3rd PCIE is not selected */
++		if (cru_straps_ctrl & 0x10)
++			return -ENODEV;
++
++		bcma_pcie2_3rd_init(bus);
++		phyaddr = 0xf;
++	} else {
++		phyaddr = bdev->core_unit;
++	}
++	bcma_pcie2_improve_phy_jitter(bus, phyaddr);
++
++	/* create mem resource */
++	res = devm_kzalloc(&bdev->dev, sizeof(*res), GFP_KERNEL);
++	if (!res) {
++		dev_info(&bdev->dev, "requesting resource at 0x%x failed\n",
++			 bdev->addr_s[0]);
++		return -EINVAL;
++	}
++	res->start = bdev->addr_s[0];
++	res->end = res->start + SZ_128M - 1;
++	res->name = "PCIe Configuration Space";
++	res->flags = IORESOURCE_MEM;
++
++	pci_add_resource(&sys->resources, res);
++
++	/* This PCIe controller does not support IO Mem, so use a dummy one. */
++	res = devm_kzalloc(&bdev->dev, sizeof(*res), GFP_KERNEL);
++	if (!res) {
++		dev_info(&bdev->dev, "requesting resource at 0x%x failed\n",
++			 bdev->addr_s[0]);
++		return -EINVAL;
++	}
++	res->start = bdev->addr_s[0];
++	res->end = res->start + SZ_128M - 1;
++	res->name = "PCIe Configuration Space";
++	res->flags = IORESOURCE_IO;
++
++	pci_add_resource(&sys->resources, res);
++
++	for (allow_gen2 = 0; allow_gen2 <= 1; allow_gen2++) {
++		bcma_pcie2_hw_init(bdev);
++		bcma_pcie2_map_init(bdev);
++
++		/*
++		 * Skip inactive ports -
++		 * will need to change this for hot-plugging
++		 */
++		linkfail = bcma_pcie2_check_link(bdev, allow_gen2);
++		if (linkfail)
++			break;
++
++		bcma_pcie2_bridge_init(bdev);
++
++		if (allow_gen2 == 0) {
++			if (bcma_pcie2_allow_gen2_rc(bdev) == 0)
++				break;
++			dev_info(&bdev->dev, "switching to GEN2\n");
++		}
++	}
++
++	if (linkfail)
++		return -1;
++
++	return 1;
++}
++
++/*
++ * Methods for accessing configuration registers
++ */
++static struct pci_ops bcma_pcie2_ops = {
++	.read = bcma_pcie2_read_config_pci,
++	.write = bcma_pcie2_write_config_pci,
++};
++
++static int bcma_pcie2_probe(struct bcma_device *bdev)
++{
++	struct hw_pci hw;
++
++	dev_info(&bdev->dev, "scanning bus\n");
++
++	hw = (struct hw_pci) {
++		.nr_controllers = 1,
++		.domain		= bdev->core_unit,
++		.private_data	= (void **)&bdev,
++		.setup		= bcma_pcie2_setup,
++		.map_irq	= bcma_pcie2_map_irq,
++		.ops		= &bcma_pcie2_ops,
++	};
++
++	/* Announce this port to ARM/PCI common code */
++	pci_common_init_dev(&bdev->dev, &hw);
++
++	/* Setup virtual-wire interrupts */
++	bcma_write32(bdev, SOC_PCIE_SYS_RC_INTX_EN, 0xf);
++
++	/* Enable memory and bus master */
++	bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6);
++
++	return 0;
++}
++
++static const struct bcma_device_id bcma_pcie2_table[] = {
++	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_PCIEG2, BCMA_ANY_REV, BCMA_ANY_CLASS),
++	BCMA_CORETABLE_END
++};
++MODULE_DEVICE_TABLE(bcma, bcma_pcie2_table);
++
++static struct bcma_driver bcma_pcie2_driver = {
++	.name		= KBUILD_MODNAME,
++	.id_table	= bcma_pcie2_table,
++	.probe		= bcma_pcie2_probe,
++};
++
++static int __init bcma_pcie2_init(void)
++{
++	return bcma_driver_register(&bcma_pcie2_driver);
++}
++module_init(bcma_pcie2_init);
++
++static void __exit bcma_pcie2_exit(void)
++{
++	bcma_driver_unregister(&bcma_pcie2_driver);
++}
++module_exit(bcma_pcie2_exit);
++
++MODULE_AUTHOR("Hauke Mehrtens");
++MODULE_DESCRIPTION("PCIe Gen2 driver for BCMA");
++MODULE_LICENSE("GPLv2");
diff --git a/target/linux/bcm53xx/patches-3.14/202-bgmac-make-bgmac-work-on-systems-without-nvram.patch b/target/linux/bcm53xx/patches-3.14/202-bgmac-make-bgmac-work-on-systems-without-nvram.patch
deleted file mode 100644
index 1cf4641fa6..0000000000
--- a/target/linux/bcm53xx/patches-3.14/202-bgmac-make-bgmac-work-on-systems-without-nvram.patch
+++ /dev/null
@@ -1,73 +0,0 @@
-These are some hackish patches to make the Ethernet driver work somehow
-on this arm core.
-The flash driver is not working, so we removed the nvram reading, this 
-should be changed after we have a flash driver.
-The mdelay(1) is a ugly workaround for this arm chip, this seams to be a dma problem.
-
-The PHY says it is not connected by default, just ignore it.
-
---- a/drivers/net/ethernet/broadcom/Kconfig
-+++ b/drivers/net/ethernet/broadcom/Kconfig
-@@ -131,7 +131,7 @@ config BNX2X_SRIOV
- 
- config BGMAC
- 	tristate "BCMA bus GBit core support"
--	depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
-+	depends on BCMA_HOST_SOC && HAS_DMA
- 	select PHYLIB
- 	---help---
- 	  This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
---- a/drivers/net/ethernet/broadcom/bgmac.c
-+++ b/drivers/net/ethernet/broadcom/bgmac.c
-@@ -17,7 +17,11 @@
- #include <linux/interrupt.h>
- #include <linux/dma-mapping.h>
- #include <linux/platform_data/b53.h>
-+#ifdef CONFIG_BCM47XX
- #include <bcm47xx_nvram.h>
-+#else
-+#define bcm47xx_nvram_getenv(a, b, c) -1
-+#endif
- 
- static const struct bcma_device_id bgmac_bcma_tbl[] = {
- 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
-@@ -1452,7 +1456,7 @@ static int bgmac_probe(struct bcma_devic
- 	int err;
- 
- 	/* We don't support 2nd, 3rd, ... units, SPROM has to be adjusted */
--	if (core->core_unit > 1) {
-+	if (core->core_unit > 0) {
- 		pr_err("Unsupported core_unit %d\n", core->core_unit);
- 		return -ENOTSUPP;
- 	}
-@@ -1487,8 +1491,7 @@ static int bgmac_probe(struct bcma_devic
- 	}
- 	bgmac->cmn = core->bus->drv_gmac_cmn.core;
- 
--	bgmac->phyaddr = core->core_unit ? sprom->et1phyaddr :
--			 sprom->et0phyaddr;
-+	bgmac->phyaddr = BGMAC_PHY_NOREGS; // core->core_unit ? sprom->et1phyaddr : sprom->et0phyaddr;
- 	bgmac->phyaddr &= BGMAC_PHY_MASK;
- 	if (bgmac->phyaddr == BGMAC_PHY_MASK) {
- 		bgmac_err(bgmac, "No PHY found\n");
-@@ -1540,8 +1543,7 @@ static int bgmac_probe(struct bcma_devic
- 	/* TODO: reset the external phy. Specs are needed */
- 	bgmac_phy_reset(bgmac);
- 
--	bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
--			       BGMAC_BFL_ENETROBO);
-+	bgmac->has_robosw = 1;
- 	if (bgmac->has_robosw)
- 		bgmac_warn(bgmac, "Support for Roboswitch not implemented\n");
- 
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -898,7 +898,7 @@ int genphy_update_link(struct phy_device
- 		return status;
- 
- 	if ((status & BMSR_LSTATUS) == 0)
--		phydev->link = 0;
-+		phydev->link = 1;
- 	else
- 		phydev->link = 1;
- 
diff --git a/target/linux/bcm53xx/patches-3.14/900-bgmac-some-fixes-to-get-bgmac-work.patch b/target/linux/bcm53xx/patches-3.14/900-bgmac-some-fixes-to-get-bgmac-work.patch
new file mode 100644
index 0000000000..caf2f3338a
--- /dev/null
+++ b/target/linux/bcm53xx/patches-3.14/900-bgmac-some-fixes-to-get-bgmac-work.patch
@@ -0,0 +1,33 @@
+From 0bd576e93a188fd3aab769b622fb3d35fa9bc7a7 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 3 May 2014 19:55:38 +0200
+Subject: [PATCH 15/15] bgmac: some fixes to get bgmac work
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/net/ethernet/broadcom/Kconfig | 2 +-
+ drivers/net/phy/phy_device.c          | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/Kconfig
++++ b/drivers/net/ethernet/broadcom/Kconfig
+@@ -131,7 +131,7 @@ config BNX2X_SRIOV
+ 
+ config BGMAC
+ 	tristate "BCMA bus GBit core support"
+-	depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
++	depends on BCMA_HOST_SOC && HAS_DMA
+ 	select PHYLIB
+ 	---help---
+ 	  This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -898,7 +898,7 @@ int genphy_update_link(struct phy_device
+ 		return status;
+ 
+ 	if ((status & BMSR_LSTATUS) == 0)
+-		phydev->link = 0;
++		phydev->link = 1;
+ 	else
+ 		phydev->link = 1;
+