File: /usr/src/linux/arch/ppc/kernel/pmac_nvram.c
1 /*
2 * BK Id: SCCS/s.pmac_nvram.c 1.15 09/08/01 15:47:42 paulus
3 */
4 /*
5 * Miscellaneous procedures for dealing with the PowerMac hardware.
6 */
7 #include <linux/config.h>
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/stddef.h>
11 #include <linux/nvram.h>
12 #include <linux/init.h>
13 #include <linux/slab.h>
14 #include <linux/delay.h>
15 #include <asm/sections.h>
16 #include <asm/io.h>
17 #include <asm/system.h>
18 #include <asm/prom.h>
19 #include <asm/machdep.h>
20 #include <asm/nvram.h>
21 #include <linux/adb.h>
22 #include <linux/pmu.h>
23
24 #undef DEBUG
25
26 #define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
27
28 #define CORE99_SIGNATURE 0x5a
29 #define CORE99_ADLER_START 0x14
30
31 /* Core99 nvram is a flash */
32 #define CORE99_FLASH_STATUS_DONE 0x80
33 #define CORE99_FLASH_STATUS_ERR 0x38
34 #define CORE99_FLASH_CMD_ERASE_CONFIRM 0xd0
35 #define CORE99_FLASH_CMD_ERASE_SETUP 0x20
36 #define CORE99_FLASH_CMD_RESET 0xff
37 #define CORE99_FLASH_CMD_WRITE_SETUP 0x40
38
39 /* CHRP NVRAM header */
40 struct chrp_header {
41 u8 signature;
42 u8 cksum;
43 u16 len;
44 char name[12];
45 u8 data[0];
46 };
47
48 struct core99_header {
49 struct chrp_header hdr;
50 u32 adler;
51 u32 generation;
52 u32 reserved[2];
53 };
54
55 /*
56 * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
57 */
58 static int nvram_naddrs;
59 static volatile unsigned char *nvram_addr;
60 static volatile unsigned char *nvram_data;
61 static int nvram_mult, is_core_99;
62 static int core99_bank = 0;
63 static int nvram_partitions[3];
64
65 /* FIXME: kmalloc fails to allocate the image now that I had to move it
66 * before time_init(). For now, I allocate a static buffer here
67 * but it's a waste of space on all but core99 machines
68 */
69 #if 0
70 static char* nvram_image;
71 #else
72 static char nvram_image[NVRAM_SIZE] __pmacdata;
73 #endif
74
75 extern int pmac_newworld;
76
77 static u8 __openfirmware
78 chrp_checksum(struct chrp_header* hdr)
79 {
80 u8 *ptr;
81 u16 sum = hdr->signature;
82 for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
83 sum += *ptr;
84 while (sum > 0xFF)
85 sum = (sum & 0xFF) + (sum>>8);
86 return sum;
87 }
88
89 static u32 __pmac
90 core99_calc_adler(u8 *buffer)
91 {
92 int cnt;
93 u32 low, high;
94
95 buffer += CORE99_ADLER_START;
96 low = 1;
97 high = 0;
98 for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
99 if ((cnt % 5000) == 0) {
100 high %= 65521UL;
101 high %= 65521UL;
102 }
103 low += buffer[cnt];
104 high += low;
105 }
106 low %= 65521UL;
107 high %= 65521UL;
108
109 return (high << 16) | low;
110 }
111
112 static u32 __pmac
113 core99_check(u8* datas)
114 {
115 struct core99_header* hdr99 = (struct core99_header*)datas;
116
117 if (hdr99->hdr.signature != CORE99_SIGNATURE) {
118 #ifdef DEBUG
119 printk("Invalid signature\n");
120 #endif
121 return 0;
122 }
123 if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
124 #ifdef DEBUG
125 printk("Invalid checksum\n");
126 #endif
127 return 0;
128 }
129 if (hdr99->adler != core99_calc_adler(datas)) {
130 #ifdef DEBUG
131 printk("Invalid adler\n");
132 #endif
133 return 0;
134 }
135 return hdr99->generation;
136 }
137
138 static int __pmac
139 core99_erase_bank(int bank)
140 {
141 int stat, i;
142
143 u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
144
145 out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
146 out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
147 do { stat = in_8(base); }
148 while(!(stat & CORE99_FLASH_STATUS_DONE));
149 out_8(base, CORE99_FLASH_CMD_RESET);
150 if (stat & CORE99_FLASH_STATUS_ERR) {
151 printk("nvram: flash error 0x%02x on erase !\n", stat);
152 return -ENXIO;
153 }
154 for (i=0; i<NVRAM_SIZE; i++)
155 if (base[i] != 0xff) {
156 printk("nvram: flash erase failed !\n");
157 return -ENXIO;
158 }
159 return 0;
160 }
161
162 static int __pmac
163 core99_write_bank(int bank, u8* datas)
164 {
165 int i, stat = 0;
166
167 u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
168
169 for (i=0; i<NVRAM_SIZE; i++) {
170 out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
171 out_8(base+i, datas[i]);
172 do { stat = in_8(base); }
173 while(!(stat & CORE99_FLASH_STATUS_DONE));
174 if (stat & CORE99_FLASH_STATUS_ERR)
175 break;
176 }
177 out_8(base, CORE99_FLASH_CMD_RESET);
178 if (stat & CORE99_FLASH_STATUS_ERR) {
179 printk("nvram: flash error 0x%02x on write !\n", stat);
180 return -ENXIO;
181 }
182 for (i=0; i<NVRAM_SIZE; i++)
183 if (base[i] != datas[i]) {
184 printk("nvram: flash write failed !\n");
185 return -ENXIO;
186 }
187 return 0;
188 }
189
190 static void __init
191 lookup_partitions(void)
192 {
193 u8 buffer[17];
194 int i, offset;
195 struct chrp_header* hdr;
196
197 if (pmac_newworld) {
198 nvram_partitions[pmac_nvram_OF] = -1;
199 nvram_partitions[pmac_nvram_XPRAM] = -1;
200 nvram_partitions[pmac_nvram_NR] = -1;
201 hdr = (struct chrp_header *)buffer;
202
203 offset = 0;
204 buffer[16] = 0;
205 do {
206 for (i=0;i<16;i++)
207 buffer[i] = nvram_read_byte(offset+i);
208 if (!strcmp(hdr->name, "common"))
209 nvram_partitions[pmac_nvram_OF] = offset + 0x10;
210 if (!strcmp(hdr->name, "APL,MacOS75")) {
211 nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
212 nvram_partitions[pmac_nvram_NR] = offset + 0x110;
213 }
214 offset += (hdr->len * 0x10);
215 } while(offset < NVRAM_SIZE);
216 } else {
217 nvram_partitions[pmac_nvram_OF] = 0x1800;
218 nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
219 nvram_partitions[pmac_nvram_NR] = 0x1400;
220 }
221 #ifdef DEBUG
222 printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
223 printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
224 printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
225 #endif
226 }
227
228 void __init
229 pmac_nvram_init(void)
230 {
231 struct device_node *dp;
232
233 nvram_naddrs = 0;
234
235 dp = find_devices("nvram");
236 if (dp == NULL) {
237 printk(KERN_ERR "Can't find NVRAM device\n");
238 return;
239 }
240 nvram_naddrs = dp->n_addrs;
241 is_core_99 = device_is_compatible(dp, "nvram,flash");
242 if (is_core_99) {
243 int i;
244 u32 gen_bank0, gen_bank1;
245
246 if (nvram_naddrs < 1) {
247 printk(KERN_ERR "nvram: no address\n");
248 return;
249 }
250 #if 0
251 nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
252 if (!nvram_image) {
253 printk(KERN_ERR "nvram: can't allocate image\n");
254 return;
255 }
256 #endif
257 nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
258 #ifdef DEBUG
259 printk("nvram: Checking bank 0...\n");
260 #endif
261 gen_bank0 = core99_check((u8 *)nvram_data);
262 gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
263 core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
264 #ifdef DEBUG
265 printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
266 printk("nvram: Active bank is: %d\n", core99_bank);
267 #endif
268 for (i=0; i<NVRAM_SIZE; i++)
269 nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
270 } else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
271 nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
272 dp->addrs[0].size);
273 nvram_mult = 1;
274 } else if (nvram_naddrs == 1) {
275 nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
276 nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
277 } else if (nvram_naddrs == 2) {
278 nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
279 nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
280 } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
281 nvram_naddrs = -1;
282 } else {
283 printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
284 nvram_naddrs);
285 }
286 lookup_partitions();
287 }
288
289 void __pmac
290 pmac_nvram_update(void)
291 {
292 struct core99_header* hdr99;
293
294 if (!is_core_99 || !nvram_data || !nvram_image)
295 return;
296 if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
297 NVRAM_SIZE))
298 return;
299 #ifdef DEBUG
300 printk("Updating nvram...\n");
301 #endif
302 hdr99 = (struct core99_header*)nvram_image;
303 hdr99->generation++;
304 hdr99->hdr.signature = CORE99_SIGNATURE;
305 hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
306 hdr99->adler = core99_calc_adler(nvram_image);
307 core99_bank = core99_bank ? 0 : 1;
308 if (core99_erase_bank(core99_bank)) {
309 printk("nvram: Error erasing bank %d\n", core99_bank);
310 return;
311 }
312 if (core99_write_bank(core99_bank, nvram_image))
313 printk("nvram: Error writing bank %d\n", core99_bank);
314 }
315
316 unsigned char __openfirmware
317 nvram_read_byte(int addr)
318 {
319 switch (nvram_naddrs) {
320 #ifdef CONFIG_ADB_PMU
321 case -1: {
322 struct adb_request req;
323
324 if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
325 (addr >> 8) & 0xff, addr & 0xff))
326 break;
327 while (!req.complete)
328 pmu_poll();
329 return req.reply[1];
330 }
331 #endif
332 case 1:
333 if (is_core_99)
334 return nvram_image[addr];
335 return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
336 case 2:
337 *nvram_addr = addr >> 5;
338 eieio();
339 return nvram_data[(addr & 0x1f) << 4];
340 }
341 return 0;
342 }
343
344 void __openfirmware
345 nvram_write_byte(unsigned char val, int addr)
346 {
347 switch (nvram_naddrs) {
348 #ifdef CONFIG_ADB_PMU
349 case -1: {
350 struct adb_request req;
351
352 if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
353 (addr >> 8) & 0xff, addr & 0xff, val))
354 break;
355 while (!req.complete)
356 pmu_poll();
357 break;
358 }
359 #endif
360 case 1:
361 if (is_core_99) {
362 nvram_image[addr] = val;
363 break;
364 }
365 nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
366 break;
367 case 2:
368 *nvram_addr = addr >> 5;
369 eieio();
370 nvram_data[(addr & 0x1f) << 4] = val;
371 break;
372 }
373 eieio();
374 }
375
376 int __pmac
377 pmac_get_partition(int partition)
378 {
379 return nvram_partitions[partition];
380 }
381
382 u8 __pmac
383 pmac_xpram_read(int xpaddr)
384 {
385 int offset = nvram_partitions[pmac_nvram_XPRAM];
386
387 if (offset < 0)
388 return 0;
389
390 return nvram_read_byte(xpaddr + offset);
391 }
392
393 void __pmac
394 pmac_xpram_write(int xpaddr, u8 data)
395 {
396 int offset = nvram_partitions[pmac_nvram_XPRAM];
397
398 if (offset < 0)
399 return;
400
401 nvram_write_byte(xpaddr + offset, data);
402 }
403