nvram merge patch...

Ani Joshi ajoshi at shell.unixbox.com
Thu Mar 9 02:53:05 EST 2000



with all the recent talk about nvram, i decide to try and merge the pmac
nvram stuff (and eventually prep also) into drivers/char/nvram.c.  nvram.c
uses an "api" for PC and amiga, and i've added some pmacnvram support in
there.  along with the basic nvram support of /dev/nvram, i've added
support for /proc/nvram which will dump the current variables and values.

note: this patch was hacked up late last nite and is no way belived to be
working, i want to get some feedback before continuing this.  would this
be The Right solution?

when this is refined and finished, it will remove the need for
drivers/macintosh/nvram.c and arch/ppc/kernel/{pmac,prep}_nvram.c (though
i have not put in the necessary prep stuff in yet, just pmac)


any ideas/suggestions?


ani
-------------- next part --------------
--- nvram.c.orig	Wed Mar  8 01:00:06 2000
+++ nvram.c	Wed Mar  8 02:43:44 2000
@@ -34,12 +34,15 @@
 
 #define PC		1
 #define ATARI	2
+#define PMAC	3
 
 /* select machine configuration */
 #if defined(CONFIG_ATARI)
 #define MACH ATARI
 #elif defined(__i386__) || defined(__arm__) /* and others?? */
 #define MACH PC
+#elif defined(CONFIG_PMAC)
+#define MACH PMAC
 #else
 #error Cannot build nvram driver for this machine configuration.
 #endif
@@ -56,6 +59,7 @@
 
 #define	mach_check_checksum	pc_check_checksum
 #define	mach_set_checksum	pc_set_checksum
+#define mach_init		/* nothing to do */
 #define	mach_proc_infos		pc_proc_infos
 
 #endif
@@ -76,10 +80,97 @@
 
 #define	mach_check_checksum	atari_check_checksum
 #define	mach_set_checksum	atari_set_checksum
+#define mach_init		/* nothing to do */
 #define	mach_proc_infos		atari_proc_infos
 
 #endif
 
+#if MACH == PMAC
+
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/init.h>
+
+struct nvram {
+	unsigned short magic;
+	unsigned char char2;
+	unsigned char char3;
+	unsigned short cksum;
+	unsigned short end_vals;
+	unsigned short start_strsl
+	unsigned short word5;
+	unsigned long bits;
+	unsigned long vals[1];
+};
+
+struct nvbuf {
+	struct nvram nv;
+	car c[NVRAM_SIZE2];
+	unsigned short s[NVRAM_SIZE2/2];
+} nv_buffer;
+
+enum nv_type {
+	boolean,
+	word,
+	string
+};
+
+struct nv_var {
+	const char *name;
+	enum nv_type type;
+} nv_vars[] = {
+	{"little-endian?", boolean},
+	{"real-mode?", boolean},
+	{"auto-boot?", boolean},
+	{"diag-switch?", boolean},
+	{"fcode-debug?", boolean},
+	{"oem-banner?", boolean},
+	{"oem-logo?", boolean},
+	{"use-nvramrc?", boolean},
+	{"real-base", word},
+	{"real-size", word},
+	{"virt-base", word},
+	{"virt-size", word},
+	{"load-base", word},
+	{"pci-probe-list", word},
+	{"screen-#columns", word},
+	{"screen-#rows", word},
+	{"selftest-#megs", word},
+	{"boot-device", string},
+	{"boot-file", string},
+	{"diag-device", string},
+	{"diag-file", string},
+	{"input-device", string},
+	{"output-device", string},
+	{"oem-banner", string},
+	{"oem-logo", string},
+	{"nvramrc", string},
+	{"boot-command", string},
+};
+
+union nv_val {
+	unsigned long word_val;
+	char *str_val;
+} nv_vals[32];
+
+
+#define	mach_check_checksum	/* nothing to do ? */
+#define	mach_set_checksum	/* nothing to do ? */
+#define mach_init		pmac_init
+#define	mach_proc_infos		pmac_proc_infos
+
+static int nvram_addrs, nvram_mult, is_core_99;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+static char *nvram_image;
+static char nvstrbuf[NVRAM_SIZE2];
+static int nvstr_used = 0;
+
+#define NVRAM_SIZE	0x2000	/* 8kb of non-volatile RAM */
+#define NVRAM_SIZE2	0x800
+
+#endif
+
 /* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
  * interrupts disabled. Due to the index-port/data-port design of the RTC, we
  * don't want two different things trying to get to it at once. (e.g. the
@@ -113,6 +204,7 @@
 
 static int mach_check_checksum( void );
 static void mach_set_checksum( void );
+static void mach_init( void );
 #ifdef CONFIG_PROC_FS
 static int mach_proc_infos( unsigned char *contents, char *buffer, int *len,
 							off_t *begin, off_t offset, int size );
@@ -205,6 +297,115 @@
 #endif /* MACH == ATARI */
 
 
+
+
+#if MACH == PMAC
+
+void pmac_init(void)
+{
+	struct device_node *node;
+
+	nvram_addrs = 0;
+	node = find_devices("nvram");
+	if (node == NULL) {
+		printk(KERN_ERR "Can't find NVRAM device.\n");
+		return;
+	}
+	nvram_addrs = node->n_addrs;
+	is_core_99 = device_is_compatible(node, "nvram,flash");
+	if (is_core_99) {
+		int i;
+
+		if (nvram_addrs < 1) {
+			printk(KERN_ERR "Bad number of addrs %d\n",
+			       nvram_addrs);
+			return;
+		}
+		nvram_image = kmalloc(node->addrs[0].size, GFP_KERNEL);
+		if (!nvram_image) {
+			printk("KERN_ERR "nvram image kmalloc failed!\n");
+			return;
+		}
+		nvram_data = ioremap(node->addrs[0].address,
+				     node->addrs[0].size);
+		for(i=0; i<node->addrs[0].size; i++) {
+			nvram_image[i] = in_8(nvram_data + i);
+	} else if (nvram_addrs == 1) {
+		nvram_data = ioremap(node->addrs[0].address,
+				     node->addrs[0].size);
+		nvram_mult = (node->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
+	} else if (nvram_addrs == 2) {
+		nvram_addr = ioremap(node->addrs[0].address,
+				     node->addrs[0].size);
+		nvram_data = ioremap(node->addrs[1].address,
+				     node->addrs[1].size);
+	} else if (nvram_addrs == 0 && sys_ctrler == SYS_CTRLER_PMU)
+		nvram_naddrs = -1;
+	else
+		printk(KERN_ERR "Don't know how to access NVRAM with %d
+		       addresses\n", nvram_naddrs);
+}
+
+
+unsigned char nvram_read_byte(int addr)
+{
+	struct adb_request req;
+
+	switch (nvram_naddrs) {
+#ifdef CONFIG_ADB_PMU
+	case -1:
+		if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
+				(addr >> 8) & 0xff, addr & 0xff))
+			break;
+		while(!req.complete)
+			pmu_poll();
+		return req.reply[1];;
+#endif
+	case 1:
+		if (is_core_99)
+			return nvram_image[addr];
+		return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
+	case 2:
+		*nvram_addr = addr >> 5;
+		eieio();
+		return nvram_data[(addr & 0x1f) << 4];
+	}
+	return 0;
+}
+
+void nvram_write_byte(unsigned char val, int addr)
+{
+	struct adb_request req;
+
+	switch(nvram_naddrs) {
+#ifdef CONFIG_ADB_PMU
+	case -1:
+		if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
+				(addr >> 8) & 0xff, addr & 0xff, val))
+			break;
+		while(!req.complete)
+			pmu_poll();
+		break;
+#endif
+	case 1:
+		if (is_core_99) {
+			nvram_image[addr] = val;
+			break;
+		}
+		nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
+		break;
+	case 2:
+		*nvram_addr = addr >> 5;
+		eieio();
+		nvram_data[(addr & 0x1f) << 4] = val;
+		break;
+	}
+	eieio();
+}
+	
+#endif /* MACH == PMAC */
+
+
 /*
  * The are the file operation function for user access to /dev/nvram
  */
@@ -414,6 +615,7 @@
 	if (!CHECK_DRIVER_INIT())
 	    return( -ENXIO );
 
+	mach_init();
 	printk(KERN_INFO "Non-volatile memory driver v%s\n", NVRAM_VERSION );
 	misc_register( &nvram_dev );
 	create_proc_read_entry("driver/nvram",0,0,nvram_read_proc,NULL);
@@ -677,6 +879,64 @@
 #endif
 
 #endif /* MACH == ATARI */
+
+
+#if MACH == PMAC
+
+static int pmac_proc_infos( unsigned char *nvram, char *buffer, int *len,
+			    off_t *begin, off_t offset, int size )
+{
+	int i, vi=0, off, len;
+	unsigned long bmask = 0x80000000;
+	char *p;
+
+	nv_buffer = (sruct nvbuf) &(nvram_image);
+
+	for (i=0; i<27; i++) {
+		switch(nv_vars[i].type) {
+		case boolean:
+			nv_vals[i].word_val = (nv_buffer.nv.bits & bmask) ? 1 : 0;
+			bmask >>= 1;
+			break;
+		case word;
+			nv_vals[i].word_val = nv_buffer.nv.vals[vi++];
+			break;
+		case string:
+			off = nv_buffer.nv.vals[vi] >> 16;
+			len = nv_buffer.nv.vals[vi++] & 0xffff;
+			nv_vals[i].str_val = nvstrbuf + nvstr_used;
+			memcpy(nv_vals[i].str_val, nv_buffer.c +
+			       off - 0x1800, (size_t) len);
+			nv_vals[i].str_val[len] = (char) 0;
+			nvstr_used += len + 1;
+			break;
+		}
+	}
+
+	for (i=0; i<27; i++) {
+		switch(nv_vars[i].type) {
+		case boolean:
+			PRINT_PROC ( "%s - ", nv_vars[i].name);
+			PRINT_PROC ( "%s\n", nv_vals[i].word_val != 0 ?
+				     "true" : "false");
+		break;
+		case word:
+			PRINT_PROC ( "%s - ", nv_vars[i].name);
+			PRINT_PROC ( "0x%lx\n", nv_vals[i].word_val);
+			break;
+		case string:
+			PRINT_PROC ( "%s - ", nv_vars[i].name);
+			PRINT_PROC ( "don't know about this yet\n" );
+			break;
+		}
+	}
+	return( 1 );
+}
+
+
+
+#endif /* MACH == PMAC */
+
 
 /*
  * Local variables:


More information about the Linuxppc-dev mailing list