0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/io.h>
0011 #include <linux/types.h>
0012 #include <linux/module.h>
0013 #include <linux/kernel.h>
0014 #include <linux/string.h>
0015 #include <linux/mtd/mtd.h>
0016 #include <linux/bcm47xx_nvram.h>
0017
0018 #define NVRAM_MAGIC 0x48534C46
0019 #define NVRAM_SPACE 0x10000
0020 #define NVRAM_MAX_GPIO_ENTRIES 32
0021 #define NVRAM_MAX_GPIO_VALUE_LEN 30
0022
0023 #define FLASH_MIN 0x00020000
0024
0025 struct nvram_header {
0026 u32 magic;
0027 u32 len;
0028 u32 crc_ver_init;
0029 u32 config_refresh;
0030 u32 config_ncdl;
0031 };
0032
0033 static char nvram_buf[NVRAM_SPACE];
0034 static size_t nvram_len;
0035 static const u32 nvram_sizes[] = {0x6000, 0x8000, 0xF000, 0x10000};
0036
0037
0038
0039
0040 static bool bcm47xx_nvram_is_valid(void __iomem *nvram)
0041 {
0042 return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC;
0043 }
0044
0045
0046
0047
0048 static void bcm47xx_nvram_copy(void __iomem *nvram_start, size_t res_size)
0049 {
0050 struct nvram_header __iomem *header = nvram_start;
0051 size_t copy_size;
0052
0053 copy_size = header->len;
0054 if (copy_size > res_size) {
0055 pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n");
0056 copy_size = res_size;
0057 }
0058 if (copy_size >= NVRAM_SPACE) {
0059 pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
0060 copy_size, NVRAM_SPACE - 1);
0061 copy_size = NVRAM_SPACE - 1;
0062 }
0063
0064 __ioread32_copy(nvram_buf, nvram_start, DIV_ROUND_UP(copy_size, 4));
0065 nvram_buf[NVRAM_SPACE - 1] = '\0';
0066 nvram_len = copy_size;
0067 }
0068
0069
0070
0071
0072 static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size)
0073 {
0074 size_t flash_size;
0075 size_t offset;
0076 int i;
0077
0078 if (nvram_len) {
0079 pr_warn("nvram already initialized\n");
0080 return -EEXIST;
0081 }
0082
0083
0084
0085
0086 for (flash_size = FLASH_MIN; flash_size <= res_size; flash_size <<= 1) {
0087 for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
0088 offset = flash_size - nvram_sizes[i];
0089 if (bcm47xx_nvram_is_valid(flash_start + offset))
0090 goto found;
0091 }
0092 }
0093
0094
0095
0096 offset = 4096;
0097 if (bcm47xx_nvram_is_valid(flash_start + offset))
0098 goto found;
0099
0100 offset = 1024;
0101 if (bcm47xx_nvram_is_valid(flash_start + offset))
0102 goto found;
0103
0104 pr_err("no nvram found\n");
0105 return -ENXIO;
0106
0107 found:
0108 bcm47xx_nvram_copy(flash_start + offset, res_size - offset);
0109
0110 return 0;
0111 }
0112
0113
0114
0115
0116
0117
0118
0119
0120 int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
0121 {
0122 void __iomem *iobase;
0123 int err;
0124
0125 iobase = ioremap(base, lim);
0126 if (!iobase)
0127 return -ENOMEM;
0128
0129 err = bcm47xx_nvram_find_and_copy(iobase, lim);
0130
0131 iounmap(iobase);
0132
0133 return err;
0134 }
0135
0136 static int nvram_init(void)
0137 {
0138 #ifdef CONFIG_MTD
0139 struct mtd_info *mtd;
0140 struct nvram_header header;
0141 size_t bytes_read;
0142 int err;
0143
0144 mtd = get_mtd_device_nm("nvram");
0145 if (IS_ERR(mtd))
0146 return -ENODEV;
0147
0148 err = mtd_read(mtd, 0, sizeof(header), &bytes_read, (uint8_t *)&header);
0149 if (!err && header.magic == NVRAM_MAGIC &&
0150 header.len > sizeof(header)) {
0151 nvram_len = header.len;
0152 if (nvram_len >= NVRAM_SPACE) {
0153 pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
0154 nvram_len, NVRAM_SPACE);
0155 nvram_len = NVRAM_SPACE - 1;
0156 }
0157
0158 err = mtd_read(mtd, 0, nvram_len, &nvram_len,
0159 (u8 *)nvram_buf);
0160 return err;
0161 }
0162 #endif
0163
0164 return -ENXIO;
0165 }
0166
0167 int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
0168 {
0169 char *var, *value, *end, *eq;
0170 int err;
0171
0172 if (!name)
0173 return -EINVAL;
0174
0175 if (!nvram_len) {
0176 err = nvram_init();
0177 if (err)
0178 return err;
0179 }
0180
0181
0182 var = &nvram_buf[sizeof(struct nvram_header)];
0183 end = nvram_buf + sizeof(nvram_buf);
0184 while (var < end && *var) {
0185 eq = strchr(var, '=');
0186 if (!eq)
0187 break;
0188 value = eq + 1;
0189 if (eq - var == strlen(name) &&
0190 strncmp(var, name, eq - var) == 0)
0191 return snprintf(val, val_len, "%s", value);
0192 var = value + strlen(value) + 1;
0193 }
0194 return -ENOENT;
0195 }
0196 EXPORT_SYMBOL(bcm47xx_nvram_getenv);
0197
0198 int bcm47xx_nvram_gpio_pin(const char *name)
0199 {
0200 int i, err;
0201 char nvram_var[] = "gpioXX";
0202 char buf[NVRAM_MAX_GPIO_VALUE_LEN];
0203
0204
0205 for (i = 0; i < NVRAM_MAX_GPIO_ENTRIES; i++) {
0206 err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
0207 if (err <= 0)
0208 continue;
0209 err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
0210 if (err <= 0)
0211 continue;
0212 if (!strcmp(name, buf))
0213 return i;
0214 }
0215 return -ENOENT;
0216 }
0217 EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
0218
0219 char *bcm47xx_nvram_get_contents(size_t *nvram_size)
0220 {
0221 int err;
0222 char *nvram;
0223
0224 if (!nvram_len) {
0225 err = nvram_init();
0226 if (err)
0227 return NULL;
0228 }
0229
0230 *nvram_size = nvram_len - sizeof(struct nvram_header);
0231 nvram = vmalloc(*nvram_size);
0232 if (!nvram)
0233 return NULL;
0234 memcpy(nvram, &nvram_buf[sizeof(struct nvram_header)], *nvram_size);
0235
0236 return nvram;
0237 }
0238 EXPORT_SYMBOL(bcm47xx_nvram_get_contents);
0239
0240 MODULE_LICENSE("GPL v2");