From: Hauke Mehrtens Date: Thu, 29 May 2014 19:25:40 +0000 (+0000) Subject: bcm53xx: add support for the PCIe controller X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=cdc7ea333719e9896da1440f6bf0f0178023797e;p=openwrt%2Fstaging%2Fjow.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 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 -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 = ; -+ }; -+ -+ usb3@0 { -+ compatible = "brcm,northstar-usb3"; -+ reg = <0x18023000 0x1000>; -+ interrupts = ; -+ }; -+ -+ gmac@0 { -+ compatible = "brcm,northstar-gmac"; -+ reg = <0x18024000 0x1000>; -+ interrupts = ; -+ }; -+ -+ gmac@1 { -+ compatible = "brcm,northstar-gmac"; -+ reg = <0x18025000 0x1000>; -+ interrupts = ; -+ }; -+ -+ gmac@2 { -+ compatible = "brcm,northstar-gmac"; -+ reg = <0x18026000 0x1000>; -+ interrupts = ; -+ }; -+ -+ gmac@3 { -+ compatible = "brcm,northstar-gmac"; -+ reg = <0x18027000 0x1000>; -+ interrupts = ; -+ }; -+ }; - }; 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 +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 + #include + #include +-#include ++#include + + 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 + #include + #include +-#include ++#include + #include + + static char nvram_buf[NVRAM_SPACE]; +--- a/arch/mips/bcm47xx/setup.c ++++ b/arch/mips/bcm47xx/setup.c +@@ -42,7 +42,7 @@ + #include + #include + #include +-#include ++#include + #include + + union bcm47xx_bus bcm47xx_bus; +--- a/arch/mips/bcm47xx/sprom.c ++++ b/arch/mips/bcm47xx/sprom.c +@@ -27,7 +27,7 @@ + */ + + #include +-#include ++#include + + 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 + #include + #include +-#include ++#include + #include + + 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 +- * +- * 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 +-#include +- +-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 + #include + #include ++#include + + #include + #include +@@ -399,8 +400,6 @@ static void b44_set_flow_ctrl(struct b44 + __b44_set_flow_ctrl(bp, pause_enab); + } + +-#ifdef CONFIG_BCM47XX +-#include + 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 + #include + #include +-#include ++#include + + 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 + #include + #include +-#ifdef CONFIG_BCM47XX +-#include +-#endif ++#include + + #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 ++ * Copyright (C) 2014 Hauke Mehrtens ++ * ++ * 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 ++#include ++ ++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 +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 ++ * Copyright (C) 2010-2014 Hauke Mehrtens ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 "); ++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 + #include + ++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 -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 ---- - 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 -+#include -+#include - #include - #include - -@@ -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 +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 +--- + 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 ++ * Copyright (C) 2006 Michael Buesch ++ * Copyright (C) 2010 Waldemar Brodkorb ++ * Copyright (C) 2006 Felix Fietkau ++ * Copyright (C) 2010-2014 Hauke Mehrtens ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 "); ++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 -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 - #include - #include -+#include -+#include - - 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 +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 +--- + 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 ++#include ++#include + #include + #include + +@@ -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 +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 + #include + #include ++#include ++#include + + 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 +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 +--- + 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 + #include + #include ++#include ++#include + + 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 +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 = ; ++ }; ++ ++ usb3@0 { ++ reg = <0x18023000 0x1000>; ++ interrupts = ; ++ }; ++ ++ gmac@0 { ++ reg = <0x18024000 0x1000>; ++ interrupts = ; ++ }; ++ ++ gmac@1 { ++ reg = <0x18025000 0x1000>; ++ interrupts = ; ++ }; ++ ++ gmac@2 { ++ reg = <0x18026000 0x1000>; ++ interrupts = ; ++ }; ++ ++ gmac@3 { ++ reg = <0x18027000 0x1000>; ++ interrupts = ; ++ }; ++ ++ pcie@0 { ++ reg = <0x18012000 0x1000>; ++ interrupts = ; ++ }; ++ ++ pcie@1 { ++ reg = <0x18013000 0x1000>; ++ interrupts = ; ++ }; ++ }; + }; 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include "bcma_private.h" ++#include ++#include ++ ++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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 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 - #include - #include -+#ifdef CONFIG_BCM47XX - #include -+#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 +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 +--- + 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; +