From ae61421afa39e5f0eff857207070aee11c057832 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 29 May 2014 19:25:40 +0000 Subject: 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 git-svn-id: svn://svn.openwrt.org/openwrt/trunk@40880 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- ...vram-add-new-nvram-driver-with-dt-support.patch | 520 +++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 target/linux/bcm53xx/patches-3.14/111-bcm47xx-nvram-add-new-nvram-driver-with-dt-support.patch (limited to 'target/linux/bcm53xx/patches-3.14/111-bcm47xx-nvram-add-new-nvram-driver-with-dt-support.patch') 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; + } -- cgit v1.2.3