summaryrefslogtreecommitdiffstats
path: root/target/linux/brcm47xx/patches-3.6/080-MIPS-BCM47XX-rewrite-nvram-probing.patch
blob: a271876fa93bdb91928a3032b795aafc60267338 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2005 Broadcom Corporation
  * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de>
+ * 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
@@ -23,69 +23,139 @@
 
 static char nvram_buf[NVRAM_SPACE];
 
+static u32 find_nvram_size(u32 end)
+{
+	struct nvram_header *header;
+	u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+		header = (struct nvram_header *)KSEG1ADDR(end - nvram_sizes[i]);
+		if (header->magic == NVRAM_HEADER)
+			return nvram_sizes[i];
+	}
+
+	return 0;
+}
+
 /* Probe for NVRAM header */
-static void early_nvram_init(void)
+static void early_nvram_init_fill(u32 base, u32 lim)
 {
-#ifdef CONFIG_BCM47XX_SSB
-	struct ssb_mipscore *mcore_ssb;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
-	struct bcma_drv_cc *bcma_cc;
-#endif
 	struct nvram_header *header;
 	int i;
-	u32 base = 0;
-	u32 lim = 0;
 	u32 off;
 	u32 *src, *dst;
+	u32 size;
 
-	switch (bcm47xx_bus_type) {
-#ifdef CONFIG_BCM47XX_SSB
-	case BCM47XX_BUS_TYPE_SSB:
-		mcore_ssb = &bcm47xx_bus.ssb.mipscore;
-		base = mcore_ssb->pflash.window;
-		lim = mcore_ssb->pflash.window_size;
-		break;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
-	case BCM47XX_BUS_TYPE_BCMA:
-		bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
-		base = bcma_cc->pflash.window;
-		lim = bcma_cc->pflash.window_size;
-		break;
-#endif
-	}
-
+	/* TODO: when nvram is on nand flash check for bad blocks first. */
 	off = FLASH_MIN;
 	while (off <= lim) {
 		/* Windowed flash access */
-		header = (struct nvram_header *)
-			KSEG1ADDR(base + off - NVRAM_SPACE);
-		if (header->magic == NVRAM_HEADER)
+		size = find_nvram_size(base + off);
+		if (size) {
+			header = (struct nvram_header *)KSEG1ADDR(base + off -
+								  size);
 			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)
+	if (header->magic == NVRAM_HEADER) {
+		size = NVRAM_SPACE;
 		goto found;
+	}
 
 	header = (struct nvram_header *) KSEG1ADDR(base + 1024);
-	if (header->magic == NVRAM_HEADER)
+	if (header->magic == NVRAM_HEADER) {
+		size = NVRAM_SPACE;
 		goto found;
+	}
 
+	pr_err("no nvram found\n");
 	return;
 
 found:
+
+	if (header->len > size)
+		pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n");
+	if (header->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);
+
 	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)
+	for (; i < header->len && i < NVRAM_SPACE && i < size; i += 4)
 		*dst++ = le32_to_cpu(*src++);
 }
 
+#ifdef CONFIG_BCM47XX_BCMA
+static void early_nvram_init_bcma(void)
+{
+	struct bcma_drv_cc *cc = &bcm47xx_bus.bcma.bus.drv_cc;
+	u32 base = 0;
+	u32 lim = 0;
+
+	if (cc->nflash.boot) {
+		base = BCMA_SOC_FLASH1;
+		lim = BCMA_SOC_FLASH1_SZ;
+	} else if (cc->pflash.present) {
+		base = cc->pflash.window;
+		lim = cc->pflash.window_size;
+	} else if (cc->sflash.present) {
+		base = cc->sflash.window;
+		lim = cc->sflash.size;
+	} else {
+		pr_err("No supported flash found\n");
+		return;
+	}
+
+	early_nvram_init_fill(base, lim);
+}
+#endif
+
+#ifdef CONFIG_BCM47XX_SSB
+static void early_nvram_init_ssb(void)
+{
+	struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
+	struct ssb_chipcommon *chipco = &bcm47xx_bus.ssb.chipco;
+	u32 base = 0;
+	u32 lim = 0;
+
+	if (mcore->pflash.present) {
+		base = mcore->pflash.window;
+		lim = mcore->pflash.window_size;
+	} else if (chipco->sflash.present) {
+		base = chipco->sflash.window;
+		lim = chipco->sflash.size;
+	} else {
+		pr_err("No supported flash found\n");
+		return;
+	}
+
+	early_nvram_init_fill(base, lim);
+}
+#endif
+
+static void early_nvram_init(void)
+{
+	switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+	case BCM47XX_BUS_TYPE_SSB:
+		early_nvram_init_ssb();
+		break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		early_nvram_init_bcma();
+		break;
+#endif
+	}
+}
+
 int nvram_getenv(char *name, char *val, size_t val_len)
 {
 	char *var, *value, *end, *eq;