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