aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/bcm47xx/nvram.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/bcm47xx/nvram.c')
-rw-r--r--arch/mips/bcm47xx/nvram.c155
1 files changed, 86 insertions, 69 deletions
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 2bed73a684ae..c5c381c43f17 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -13,24 +13,35 @@
13 13
14#include <linux/types.h> 14#include <linux/types.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/ssb/ssb.h>
17#include <linux/kernel.h> 16#include <linux/kernel.h>
18#include <linux/string.h> 17#include <linux/string.h>
19#include <asm/addrspace.h> 18#include <linux/mtd/mtd.h>
20#include <bcm47xx_nvram.h> 19#include <bcm47xx_nvram.h>
21#include <asm/mach-bcm47xx/bcm47xx.h> 20
21#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */
22#define NVRAM_SPACE 0x8000
23
24#define FLASH_MIN 0x00020000 /* Minimum flash size */
25
26struct nvram_header {
27 u32 magic;
28 u32 len;
29 u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
30 u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
31 u32 config_ncdl; /* ncdl values for memc */
32};
22 33
23static char nvram_buf[NVRAM_SPACE]; 34static char nvram_buf[NVRAM_SPACE];
24static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000}; 35static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
25 36
26static u32 find_nvram_size(u32 end) 37static u32 find_nvram_size(void __iomem *end)
27{ 38{
28 struct nvram_header *header; 39 struct nvram_header __iomem *header;
29 int i; 40 int i;
30 41
31 for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { 42 for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
32 header = (struct nvram_header *)KSEG1ADDR(end - nvram_sizes[i]); 43 header = (struct nvram_header *)(end - nvram_sizes[i]);
33 if (header->magic == NVRAM_HEADER) 44 if (header->magic == NVRAM_MAGIC)
34 return nvram_sizes[i]; 45 return nvram_sizes[i];
35 } 46 }
36 47
@@ -38,36 +49,40 @@ static u32 find_nvram_size(u32 end)
38} 49}
39 50
40/* Probe for NVRAM header */ 51/* Probe for NVRAM header */
41static int nvram_find_and_copy(u32 base, u32 lim) 52static int nvram_find_and_copy(void __iomem *iobase, u32 lim)
42{ 53{
43 struct nvram_header *header; 54 struct nvram_header __iomem *header;
44 int i; 55 int i;
45 u32 off; 56 u32 off;
46 u32 *src, *dst; 57 u32 *src, *dst;
47 u32 size; 58 u32 size;
48 59
60 if (nvram_buf[0]) {
61 pr_warn("nvram already initialized\n");
62 return -EEXIST;
63 }
64
49 /* TODO: when nvram is on nand flash check for bad blocks first. */ 65 /* TODO: when nvram is on nand flash check for bad blocks first. */
50 off = FLASH_MIN; 66 off = FLASH_MIN;
51 while (off <= lim) { 67 while (off <= lim) {
52 /* Windowed flash access */ 68 /* Windowed flash access */
53 size = find_nvram_size(base + off); 69 size = find_nvram_size(iobase + off);
54 if (size) { 70 if (size) {
55 header = (struct nvram_header *)KSEG1ADDR(base + off - 71 header = (struct nvram_header *)(iobase + off - size);
56 size);
57 goto found; 72 goto found;
58 } 73 }
59 off <<= 1; 74 off <<= 1;
60 } 75 }
61 76
62 /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ 77 /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
63 header = (struct nvram_header *) KSEG1ADDR(base + 4096); 78 header = (struct nvram_header *)(iobase + 4096);
64 if (header->magic == NVRAM_HEADER) { 79 if (header->magic == NVRAM_MAGIC) {
65 size = NVRAM_SPACE; 80 size = NVRAM_SPACE;
66 goto found; 81 goto found;
67 } 82 }
68 83
69 header = (struct nvram_header *) KSEG1ADDR(base + 1024); 84 header = (struct nvram_header *)(iobase + 1024);
70 if (header->magic == NVRAM_HEADER) { 85 if (header->magic == NVRAM_MAGIC) {
71 size = NVRAM_SPACE; 86 size = NVRAM_SPACE;
72 goto found; 87 goto found;
73 } 88 }
@@ -94,71 +109,73 @@ found:
94 return 0; 109 return 0;
95} 110}
96 111
97#ifdef CONFIG_BCM47XX_SSB 112/*
98static int nvram_init_ssb(void) 113 * On bcm47xx we need access to the NVRAM very early, so we can't use mtd
114 * subsystem to access flash. We can't even use platform device / driver to
115 * store memory offset.
116 * To handle this we provide following symbol. It's supposed to be called as
117 * soon as we get info about flash device, before any NVRAM entry is needed.
118 */
119int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
99{ 120{
100 struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore; 121 void __iomem *iobase;
101 u32 base; 122 int err;
102 u32 lim;
103
104 if (mcore->pflash.present) {
105 base = mcore->pflash.window;
106 lim = mcore->pflash.window_size;
107 } else {
108 pr_err("Couldn't find supported flash memory\n");
109 return -ENXIO;
110 }
111 123
112 return nvram_find_and_copy(base, lim); 124 iobase = ioremap_nocache(base, lim);
113} 125 if (!iobase)
114#endif 126 return -ENOMEM;
115 127
116#ifdef CONFIG_BCM47XX_BCMA 128 err = nvram_find_and_copy(iobase, lim);
117static int nvram_init_bcma(void) 129
118{ 130 iounmap(iobase);
119 struct bcma_drv_cc *cc = &bcm47xx_bus.bcma.bus.drv_cc;
120 u32 base;
121 u32 lim;
122
123#ifdef CONFIG_BCMA_NFLASH
124 if (cc->nflash.boot) {
125 base = BCMA_SOC_FLASH1;
126 lim = BCMA_SOC_FLASH1_SZ;
127 } else
128#endif
129 if (cc->pflash.present) {
130 base = cc->pflash.window;
131 lim = cc->pflash.window_size;
132#ifdef CONFIG_BCMA_SFLASH
133 } else if (cc->sflash.present) {
134 base = cc->sflash.window;
135 lim = cc->sflash.size;
136#endif
137 } else {
138 pr_err("Couldn't find supported flash memory\n");
139 return -ENXIO;
140 }
141 131
142 return nvram_find_and_copy(base, lim); 132 return err;
143} 133}
144#endif
145 134
146static int nvram_init(void) 135static int nvram_init(void)
147{ 136{
148 switch (bcm47xx_bus_type) { 137#ifdef CONFIG_MTD
149#ifdef CONFIG_BCM47XX_SSB 138 struct mtd_info *mtd;
150 case BCM47XX_BUS_TYPE_SSB: 139 struct nvram_header header;
151 return nvram_init_ssb(); 140 size_t bytes_read;
152#endif 141 int err, i;
153#ifdef CONFIG_BCM47XX_BCMA 142
154 case BCM47XX_BUS_TYPE_BCMA: 143 mtd = get_mtd_device_nm("nvram");
155 return nvram_init_bcma(); 144 if (IS_ERR(mtd))
156#endif 145 return -ENODEV;
146
147 for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
148 loff_t from = mtd->size - nvram_sizes[i];
149
150 if (from < 0)
151 continue;
152
153 err = mtd_read(mtd, from, sizeof(header), &bytes_read,
154 (uint8_t *)&header);
155 if (!err && header.magic == NVRAM_MAGIC) {
156 u8 *dst = (uint8_t *)nvram_buf;
157 size_t len = header.len;
158
159 if (header.len > NVRAM_SPACE) {
160 pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
161 header.len, NVRAM_SPACE);
162 len = NVRAM_SPACE;
163 }
164
165 err = mtd_read(mtd, from, len, &bytes_read, dst);
166 if (err)
167 return err;
168 memset(dst + bytes_read, 0x0, NVRAM_SPACE - bytes_read);
169
170 return 0;
171 }
157 } 172 }
173#endif
174
158 return -ENXIO; 175 return -ENXIO;
159} 176}
160 177
161int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len) 178int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
162{ 179{
163 char *var, *value, *end, *eq; 180 char *var, *value, *end, *eq;
164 int err; 181 int err;