--- a/arch/mips/bcm47xx/Makefile +++ b/arch/mips/bcm47xx/Makefile @@ -3,4 +3,4 @@ # under Linux. # -obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o +obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o --- /dev/null +++ b/arch/mips/bcm47xx/nvram.c @@ -0,0 +1,98 @@ +/* + * BCM947xx nvram variable access + * + * Copyright 2005, Broadcom Corporation + * Copyright 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char nvram_buf[NVRAM_SPACE]; + +/* Probe for NVRAM header */ +static void __init early_nvram_init(void) +{ + struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; + struct nvram_header *header; + int i; + u32 base, lim, off; + u32 *src, *dst; + + base = mcore->flash_window; + lim = mcore->flash_window_size; + + off = 0x20000; + while (off <= lim) { + /* Windowed flash access */ + header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE); + if (header->magic == NVRAM_HEADER) + goto found; + off <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ + header = (struct nvram_header *) KSEG1ADDR(base + 4096); + if (header->magic == NVRAM_HEADER) + goto found; + + header = (struct nvram_header *) KSEG1ADDR(base + 1024); + if (header->magic == NVRAM_HEADER) + goto found; + + return; + +found: + src = (u32 *) header; + dst = (u32 *) nvram_buf; + for (i = 0; i < sizeof(struct nvram_header); i += 4) + *dst++ = *src++; + for (; i < header->len && i < NVRAM_SPACE; i += 4) + *dst++ = le32_to_cpu(*src++); +} + +char *nvram_get(const char *name) +{ + char *var, *value, *end, *eq; + + if (!name) + return NULL; + + if (!nvram_buf[0]) + early_nvram_init(); + + /* Look for name=value and return value */ + var = &nvram_buf[sizeof(struct nvram_header)]; + end = nvram_buf + sizeof(nvram_buf) - 2; + end[0] = end[1] = '\0'; + for (; *var; var = value + strlen(value) + 1) { + if (!(eq = strchr(var, '='))) + break; + value = eq + 1; + if ((eq - var) == strlen(name) && + strncmp(var, name, (eq - var)) == 0) + return value; + } + + return NULL; +} + +EXPORT_SYMBOL(nvram_get); --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -33,6 +33,7 @@ #include #include #include +#include struct ssb_bus ssb_bcm47xx; EXPORT_SYMBOL(ssb_bcm47xx); @@ -77,6 +78,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) { char buf[100]; + char *s; /* Fill boardinfo structure */ memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); @@ -92,18 +94,47 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus, memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); iv->sprom.revision = 3; - if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0) + if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0) { str2eaddr(buf, iv->sprom.et0mac); - if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0) + } else { + if ((s = nvram_get("et0macaddr"))) + str2eaddr(s, iv->sprom.et0mac); + } + + if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0) { str2eaddr(buf, iv->sprom.et1mac); - if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) - iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 10); - if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) - iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10); - if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0) + } else { + if ((s = nvram_get("et1macaddr"))) + str2eaddr(s, iv->sprom.et1mac); + } + + if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) { + iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0); + } else { + if ((s = nvram_get("et0phyaddr"))) + iv->sprom.et0phyaddr = simple_strtoul(s, NULL, 0); + } + + if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) { + iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0); + } else { + if ((s = nvram_get("et1phyaddr"))) + iv->sprom.et1phyaddr = simple_strtoul(s, NULL, 0); + } + + if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0) { iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10); - if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0) + } else { + if ((s = nvram_get("et0mdcport"))) + iv->sprom.et0mdcport = simple_strtoul(s, NULL, 10); + } + + if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0) { iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10); + } else { + if ((s = nvram_get("et1mdcport"))) + iv->sprom.et1mdcport = simple_strtoul(s, NULL, 10); + } return 0; } --- /dev/null +++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h @@ -0,0 +1,37 @@ +/* + * 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 __NVRAM_H +#define __NVRAM_H + +struct nvram_header { + u32 magic; + u32 len; + u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ + u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ + u32 config_ncdl; /* ncdl values for memc */ +}; + +struct nvram_tuple { + char *name; + char *value; + struct nvram_tuple *next; +}; + +#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */ +#define NVRAM_VERSION 1 +#define NVRAM_HEADER_SIZE 20 +#define NVRAM_SPACE 0x8000 + +#define NVRAM_MAX_VALUE_LEN 255 +#define NVRAM_MAX_PARAM_LEN 64 + +char *nvram_get(const char *name); + +#endif