diff options
Diffstat (limited to 'arch/mips/bcm47xx/nvram.c')
-rw-r--r-- | arch/mips/bcm47xx/nvram.c | 155 |
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 | |||
26 | struct 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 | ||
23 | static char nvram_buf[NVRAM_SPACE]; | 34 | static char nvram_buf[NVRAM_SPACE]; |
24 | static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000}; | 35 | static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000}; |
25 | 36 | ||
26 | static u32 find_nvram_size(u32 end) | 37 | static 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 */ |
41 | static int nvram_find_and_copy(u32 base, u32 lim) | 52 | static 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 | /* |
98 | static 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 | */ | ||
119 | int 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); |
117 | static 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 | ||
146 | static int nvram_init(void) | 135 | static 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 | ||
161 | int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len) | 178 | int 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; |