MIPS: BCM47xx: Move NVRAM driver to the drivers/firmware/
authorRafał Miłecki <zajec5@gmail.com>
Wed, 10 Jun 2015 21:05:08 +0000 (23:05 +0200)
committerRalf Baechle <ralf@linux-mips.org>
Sun, 21 Jun 2015 19:55:33 +0000 (21:55 +0200)
After Broadcom switched from MIPS to ARM for their home routers we need
to have NVRAM driver in some common place (not arch/mips/). As explained
in Kconfig, this driver is responsible for parsing SoC configuration
data that is passed to the kernel in flash from the bootloader firmware
called "CFE".

We were thinking about putting it in bus directory, however there are
two possible buses for MIPS: drivers/ssb/ and drivers/bcma/. So this
won't fit there and this is why I would like to move this driver to the
drivers/firmware/.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Reviewed-by: Paul Walmsley <paul@pwsan.com>
Cc: linux-mips@linux-mips.org
Cc: Hauke Mehrtens <hauke@hauke-m.de>
Cc: Seiji Aguchi <seiji.aguchi@hds.com>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Mike Waychison <mikew@google.com>
Cc: Roy Franz <roy.franz@linaro.org>
Cc: Matt Fleming <matt.fleming@intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Patchwork: https://patchwork.linux-mips.org/patch/10544/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
MAINTAINERS
arch/mips/Kconfig
arch/mips/bcm47xx/Makefile
arch/mips/bcm47xx/nvram.c [deleted file]
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/broadcom/Kconfig [new file with mode: 0644]
drivers/firmware/broadcom/Makefile [new file with mode: 0644]
drivers/firmware/broadcom/bcm47xx_nvram.c [new file with mode: 0644]
include/linux/bcm47xx_nvram.h

index 43043f0b354edad01ee4d54d38cdc92581672cc5..25a17aa20741b9e367b6f3175127199516bd949b 100644 (file)
@@ -2265,6 +2265,12 @@ S:       Supported
 F:     drivers/gpio/gpio-bcm-kona.c
 F:     Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt
 
+BROADCOM NVRAM DRIVER
+M:     Rafał Miłecki <zajec5@gmail.com>
+L:     linux-mips@linux-mips.org
+S:     Maintained
+F:     drivers/firmware/broadcom/*
+
 BROADCOM SPECIFIC AMBA DRIVER (BCMA)
 M:     Rafał Miłecki <zajec5@gmail.com>
 L:     linux-wireless@vger.kernel.org
index d53b43237f7ff7541b24e90892bb7c0feee67177..dbb1a1d0f9b30de42d320f7488738ed53381e4d0 100644 (file)
@@ -190,6 +190,7 @@ config BCM47XX
        select USE_GENERIC_EARLY_PRINTK_8250
        select GPIOLIB
        select LEDS_GPIO_REGISTER
+       select BCM47XX_NVRAM
        help
         Support for BCM47XX based boards
 
index d58c51b5e501b81e6a528a107e2082b2a6694795..66bea4ecf449eb497b9bb11c591df18cfe4babb0 100644 (file)
@@ -3,5 +3,5 @@
 # under Linux.
 #
 
-obj-y                          += irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
+obj-y                          += irq.o prom.o serial.o setup.o time.o sprom.o
 obj-y                          += board.o buttons.o leds.o workarounds.o
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
deleted file mode 100644 (file)
index 9ccdce8..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * BCM947xx nvram variable access
- *
- * Copyright (C) 2005 Broadcom Corporation
- * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under  the terms of the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <linux/io.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/mtd/mtd.h>
-#include <linux/bcm47xx_nvram.h>
-
-#define NVRAM_MAGIC                    0x48534C46      /* 'FLSH' */
-#define NVRAM_SPACE                    0x10000
-#define NVRAM_MAX_GPIO_ENTRIES         32
-#define NVRAM_MAX_GPIO_VALUE_LEN       30
-
-#define FLASH_MIN              0x00020000      /* Minimum flash size */
-
-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 */
-};
-
-static char nvram_buf[NVRAM_SPACE];
-static size_t nvram_len;
-static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
-
-static u32 find_nvram_size(void __iomem *end)
-{
-       struct nvram_header __iomem *header;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
-               header = (struct nvram_header *)(end - nvram_sizes[i]);
-               if (header->magic == NVRAM_MAGIC)
-                       return nvram_sizes[i];
-       }
-
-       return 0;
-}
-
-/* Probe for NVRAM header */
-static int nvram_find_and_copy(void __iomem *iobase, u32 lim)
-{
-       struct nvram_header __iomem *header;
-       int i;
-       u32 off;
-       u32 *src, *dst;
-       u32 size;
-
-       if (nvram_len) {
-               pr_warn("nvram already initialized\n");
-               return -EEXIST;
-       }
-
-       /* TODO: when nvram is on nand flash check for bad blocks first. */
-       off = FLASH_MIN;
-       while (off <= lim) {
-               /* Windowed flash access */
-               size = find_nvram_size(iobase + off);
-               if (size) {
-                       header = (struct nvram_header *)(iobase + off - size);
-                       goto found;
-               }
-               off <<= 1;
-       }
-
-       /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
-       header = (struct nvram_header *)(iobase + 4096);
-       if (header->magic == NVRAM_MAGIC) {
-               size = NVRAM_SPACE;
-               goto found;
-       }
-
-       header = (struct nvram_header *)(iobase + 1024);
-       if (header->magic == NVRAM_MAGIC) {
-               size = NVRAM_SPACE;
-               goto found;
-       }
-
-       pr_err("no nvram found\n");
-       return -ENXIO;
-
-found:
-       src = (u32 *)header;
-       dst = (u32 *)nvram_buf;
-       for (i = 0; i < sizeof(struct nvram_header); i += 4)
-               *dst++ = __raw_readl(src++);
-       header = (struct nvram_header *)nvram_buf;
-       nvram_len = header->len;
-       if (nvram_len > size) {
-               pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n");
-               nvram_len = size;
-       }
-       if (nvram_len >= NVRAM_SPACE) {
-               pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
-                      header->len, NVRAM_SPACE - 1);
-               nvram_len = NVRAM_SPACE - 1;
-       }
-       /* proceed reading data after header */
-       for (; i < nvram_len; i += 4)
-               *dst++ = readl(src++);
-       nvram_buf[NVRAM_SPACE - 1] = '\0';
-
-       return 0;
-}
-
-/*
- * On bcm47xx we need access to the NVRAM very early, so we can't use mtd
- * subsystem to access flash. We can't even use platform device / driver to
- * store memory offset.
- * To handle this we provide following symbol. It's supposed to be called as
- * soon as we get info about flash device, before any NVRAM entry is needed.
- */
-int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
-{
-       void __iomem *iobase;
-       int err;
-
-       iobase = ioremap_nocache(base, lim);
-       if (!iobase)
-               return -ENOMEM;
-
-       err = nvram_find_and_copy(iobase, lim);
-
-       iounmap(iobase);
-
-       return err;
-}
-
-static int nvram_init(void)
-{
-#ifdef CONFIG_MTD
-       struct mtd_info *mtd;
-       struct nvram_header header;
-       size_t bytes_read;
-       int err;
-
-       mtd = get_mtd_device_nm("nvram");
-       if (IS_ERR(mtd))
-               return -ENODEV;
-
-       err = mtd_read(mtd, 0, sizeof(header), &bytes_read, (uint8_t *)&header);
-       if (!err && header.magic == NVRAM_MAGIC &&
-           header.len > sizeof(header)) {
-               nvram_len = header.len;
-               if (nvram_len >= NVRAM_SPACE) {
-                       pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
-                               header.len, NVRAM_SPACE);
-                       nvram_len = NVRAM_SPACE - 1;
-               }
-
-               err = mtd_read(mtd, 0, nvram_len, &nvram_len,
-                              (u8 *)nvram_buf);
-               return err;
-       }
-#endif
-
-       return -ENXIO;
-}
-
-int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
-{
-       char *var, *value, *end, *eq;
-       int err;
-
-       if (!name)
-               return -EINVAL;
-
-       if (!nvram_len) {
-               err = nvram_init();
-               if (err)
-                       return err;
-       }
-
-       /* Look for name=value and return value */
-       var = &nvram_buf[sizeof(struct nvram_header)];
-       end = nvram_buf + sizeof(nvram_buf);
-       while (var < end && *var) {
-               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);
-               var = value + strlen(value) + 1;
-       }
-       return -ENOENT;
-}
-EXPORT_SYMBOL(bcm47xx_nvram_getenv);
-
-int bcm47xx_nvram_gpio_pin(const char *name)
-{
-       int i, err;
-       char nvram_var[] = "gpioXX";
-       char buf[NVRAM_MAX_GPIO_VALUE_LEN];
-
-       /* TODO: Optimize it to don't call getenv so many times */
-       for (i = 0; i < NVRAM_MAX_GPIO_ENTRIES; i++) {
-               err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
-               if (err <= 0)
-                       continue;
-               err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
-               if (err <= 0)
-                       continue;
-               if (!strcmp(name, buf))
-                       return i;
-       }
-       return -ENOENT;
-}
-EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
-
-char *bcm47xx_nvram_get_contents(size_t *nvram_size)
-{
-       int err;
-       char *nvram;
-
-       if (!nvram_len) {
-               err = nvram_init();
-               if (err)
-                       return NULL;
-       }
-
-       *nvram_size = nvram_len - sizeof(struct nvram_header);
-       nvram = vmalloc(*nvram_size);
-       if (!nvram)
-               return NULL;
-       memcpy(nvram, &nvram_buf[sizeof(struct nvram_header)], *nvram_size);
-
-       return nvram;
-}
-EXPORT_SYMBOL(bcm47xx_nvram_get_contents);
index 6517132e5d8b5900baebcbc4620e10dbb4a876e0..99c69a3205c469de22232ee70fa790793c5b42df 100644 (file)
@@ -136,6 +136,7 @@ config QCOM_SCM
        bool
        depends on ARM || ARM64
 
+source "drivers/firmware/broadcom/Kconfig"
 source "drivers/firmware/google/Kconfig"
 source "drivers/firmware/efi/Kconfig"
 
index 3fdd3912709af54950f84f7f2dacb1e9a5aee366..210c6e0550d349a402d69053a34dba97aef1be17 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
 obj-$(CONFIG_QCOM_SCM)         += qcom_scm.o
 CFLAGS_qcom_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
 
+obj-y                          += broadcom/
 obj-$(CONFIG_GOOGLE_FIRMWARE)  += google/
 obj-$(CONFIG_EFI)              += efi/
 obj-$(CONFIG_UEFI_CPER)                += efi/
diff --git a/drivers/firmware/broadcom/Kconfig b/drivers/firmware/broadcom/Kconfig
new file mode 100644 (file)
index 0000000..6bed119
--- /dev/null
@@ -0,0 +1,11 @@
+config BCM47XX_NVRAM
+       bool "Broadcom NVRAM driver"
+       depends on BCM47XX || ARCH_BCM_5301X
+       help
+         Broadcom home routers contain flash partition called "nvram" with all
+         important hardware configuration as well as some minor user setup.
+         NVRAM partition contains a text-like data representing name=value
+         pairs.
+         This driver provides an easy way to get value of requested parameter.
+         It simply reads content of NVRAM and parses it. It doesn't control any
+         hardware part itself.
diff --git a/drivers/firmware/broadcom/Makefile b/drivers/firmware/broadcom/Makefile
new file mode 100644 (file)
index 0000000..d0e6835
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_BCM47XX_NVRAM)            += bcm47xx_nvram.o
diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c
new file mode 100644 (file)
index 0000000..87add3f
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * BCM947xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under  the terms of the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+#include <linux/bcm47xx_nvram.h>
+
+#define NVRAM_MAGIC                    0x48534C46      /* 'FLSH' */
+#define NVRAM_SPACE                    0x10000
+#define NVRAM_MAX_GPIO_ENTRIES         32
+#define NVRAM_MAX_GPIO_VALUE_LEN       30
+
+#define FLASH_MIN              0x00020000      /* Minimum flash size */
+
+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 */
+};
+
+static char nvram_buf[NVRAM_SPACE];
+static size_t nvram_len;
+static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
+
+static u32 find_nvram_size(void __iomem *end)
+{
+       struct nvram_header __iomem *header;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+               header = (struct nvram_header *)(end - nvram_sizes[i]);
+               if (header->magic == NVRAM_MAGIC)
+                       return nvram_sizes[i];
+       }
+
+       return 0;
+}
+
+/* Probe for NVRAM header */
+static int nvram_find_and_copy(void __iomem *iobase, u32 lim)
+{
+       struct nvram_header __iomem *header;
+       int i;
+       u32 off;
+       u32 *src, *dst;
+       u32 size;
+
+       if (nvram_len) {
+               pr_warn("nvram already initialized\n");
+               return -EEXIST;
+       }
+
+       /* TODO: when nvram is on nand flash check for bad blocks first. */
+       off = FLASH_MIN;
+       while (off <= lim) {
+               /* Windowed flash access */
+               size = find_nvram_size(iobase + off);
+               if (size) {
+                       header = (struct nvram_header *)(iobase + off - size);
+                       goto found;
+               }
+               off <<= 1;
+       }
+
+       /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+       header = (struct nvram_header *)(iobase + 4096);
+       if (header->magic == NVRAM_MAGIC) {
+               size = NVRAM_SPACE;
+               goto found;
+       }
+
+       header = (struct nvram_header *)(iobase + 1024);
+       if (header->magic == NVRAM_MAGIC) {
+               size = NVRAM_SPACE;
+               goto found;
+       }
+
+       pr_err("no nvram found\n");
+       return -ENXIO;
+
+found:
+       src = (u32 *)header;
+       dst = (u32 *)nvram_buf;
+       for (i = 0; i < sizeof(struct nvram_header); i += 4)
+               *dst++ = __raw_readl(src++);
+       header = (struct nvram_header *)nvram_buf;
+       nvram_len = header->len;
+       if (nvram_len > size) {
+               pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n");
+               nvram_len = size;
+       }
+       if (nvram_len >= NVRAM_SPACE) {
+               pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
+                      header->len, NVRAM_SPACE - 1);
+               nvram_len = NVRAM_SPACE - 1;
+       }
+       /* proceed reading data after header */
+       for (; i < nvram_len; i += 4)
+               *dst++ = readl(src++);
+       nvram_buf[NVRAM_SPACE - 1] = '\0';
+
+       return 0;
+}
+
+/*
+ * On bcm47xx we need access to the NVRAM very early, so we can't use mtd
+ * subsystem to access flash. We can't even use platform device / driver to
+ * store memory offset.
+ * To handle this we provide following symbol. It's supposed to be called as
+ * soon as we get info about flash device, before any NVRAM entry is needed.
+ */
+int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
+{
+       void __iomem *iobase;
+       int err;
+
+       iobase = ioremap_nocache(base, lim);
+       if (!iobase)
+               return -ENOMEM;
+
+       err = nvram_find_and_copy(iobase, lim);
+
+       iounmap(iobase);
+
+       return err;
+}
+
+static int nvram_init(void)
+{
+#ifdef CONFIG_MTD
+       struct mtd_info *mtd;
+       struct nvram_header header;
+       size_t bytes_read;
+       int err;
+
+       mtd = get_mtd_device_nm("nvram");
+       if (IS_ERR(mtd))
+               return -ENODEV;
+
+       err = mtd_read(mtd, 0, sizeof(header), &bytes_read, (uint8_t *)&header);
+       if (!err && header.magic == NVRAM_MAGIC &&
+           header.len > sizeof(header)) {
+               nvram_len = header.len;
+               if (nvram_len >= NVRAM_SPACE) {
+                       pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
+                               header.len, NVRAM_SPACE);
+                       nvram_len = NVRAM_SPACE - 1;
+               }
+
+               err = mtd_read(mtd, 0, nvram_len, &nvram_len,
+                              (u8 *)nvram_buf);
+               return err;
+       }
+#endif
+
+       return -ENXIO;
+}
+
+int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
+{
+       char *var, *value, *end, *eq;
+       int err;
+
+       if (!name)
+               return -EINVAL;
+
+       if (!nvram_len) {
+               err = nvram_init();
+               if (err)
+                       return err;
+       }
+
+       /* Look for name=value and return value */
+       var = &nvram_buf[sizeof(struct nvram_header)];
+       end = nvram_buf + sizeof(nvram_buf);
+       while (var < end && *var) {
+               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);
+               var = value + strlen(value) + 1;
+       }
+       return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_getenv);
+
+int bcm47xx_nvram_gpio_pin(const char *name)
+{
+       int i, err;
+       char nvram_var[] = "gpioXX";
+       char buf[NVRAM_MAX_GPIO_VALUE_LEN];
+
+       /* TODO: Optimize it to don't call getenv so many times */
+       for (i = 0; i < NVRAM_MAX_GPIO_ENTRIES; i++) {
+               err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
+               if (err <= 0)
+                       continue;
+               err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
+               if (err <= 0)
+                       continue;
+               if (!strcmp(name, buf))
+                       return i;
+       }
+       return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
+
+char *bcm47xx_nvram_get_contents(size_t *nvram_size)
+{
+       int err;
+       char *nvram;
+
+       if (!nvram_len) {
+               err = nvram_init();
+               if (err)
+                       return NULL;
+       }
+
+       *nvram_size = nvram_len - sizeof(struct nvram_header);
+       nvram = vmalloc(*nvram_size);
+       if (!nvram)
+               return NULL;
+       memcpy(nvram, &nvram_buf[sizeof(struct nvram_header)], *nvram_size);
+
+       return nvram;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_get_contents);
+
+MODULE_LICENSE("GPLv2");
index c73927c66c2cf33882d886b0c9bb029d875837cc..2793652fbf66ebc2429e6146ce52fcdadbe39490 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/vmalloc.h>
 
-#ifdef CONFIG_BCM47XX
+#ifdef CONFIG_BCM47XX_NVRAM
 int bcm47xx_nvram_init_from_mem(u32 base, u32 lim);
 int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
 int bcm47xx_nvram_gpio_pin(const char *name);