Trying to make this general purpose user-land flash burner

Corresponding to coreboot v1 svn r489.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0d9712b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+OBJS = jedec.o sst28sf040.o am29f040b.o mx29f002.c
+CC = gcc -O2
+
+all: ${OBJS}
+	${CC} -o flash_rom flash_rom.c ${OBJS}
+	${CC} -o flash_on flash_on.c
+	${CC} -o acpi_reset acpi_reset.c
+	${CC} -o acpi_shutdown acpi_shutdown.c
+
+clean:
+	rm -f flash_rom flash_on acpi_reset acpi_shutdown *.o *~
\ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..86a1ffd
--- /dev/null
+++ b/README
@@ -0,0 +1,15 @@
+I am making this a general-purpose userland flash burner -- RGM
+
+Earlier notes from Ollie:
+
+Here is some utilities for using/programming flash ROM on SiS 630/950 M/Bs
+
+	1. flash_on, turnning on the flash writer enable for 630/950 M/Bs,
+ 	   you have to run this before load DoC drivers.
+
+	2. flash_rom, use your 630/950 M/Bs as a flash programmer for some
+	   flash parts. This utility is made as modular as possible. If
+	   you find your flash part is not supported, you can add a driver
+	   your own. Or sending me the data sheet.
+
+Ollie
diff --git a/am29f040b.c b/am29f040b.c
new file mode 100644
index 0000000..121297f
--- /dev/null
+++ b/am29f040b.c
@@ -0,0 +1,120 @@
+/*
+ * am29f040.c: driver for programming AMD am29f040b models
+ *
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ *	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 Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Reference:
+ *	AMD Am29F040B data sheet
+ * $Id$
+ */
+
+#include "flash.h"
+#include "jedec.h"
+
+static __inline__ erase_sector_29f040b (char * bios, unsigned long address)
+{
+	*(bios +   0x555) = 0xAA;
+	*(bios +   0x2AA) = 0x55;
+	*(bios +   0x555) = 0x80;
+	*(bios +   0x555) = 0xAA;
+	*(bios +   0x2AA) = 0x55;
+	*(bios + address) = 0x30;
+
+	sleep(2);
+
+	/* wait for Toggle bit ready         */
+	toggle_ready_jedec(bios + address);
+}
+
+static __inline__ write_sector_29f040b(char * bios, unsigned char * src,
+				       unsigned char * dst, unsigned int page_size)
+{
+	int i;
+
+	for (i = 0; i < page_size; i++) {
+		printf("0x%08x", (unsigned long) dst - (unsigned long) bios);
+	
+		*(bios + 0x555) = 0xAA;
+		*(bios + 0x2AA) = 0x55;
+		*(bios + 0x555) = 0xA0;
+		*dst++ = *src++;
+
+		/* wait for Toggle bit ready */
+		toggle_ready_jedec(bios);
+
+		printf("\b\b\b\b\b\b\b\b\b\b");
+	}
+}
+
+int probe_29f040b (struct flashchip * flash)
+{
+	char * bios = flash->virt_addr;
+	unsigned char id1, id2;
+
+	*(bios + 0x555) = 0xAA;
+	*(bios + 0x2AA) = 0x55;
+	*(bios + 0x555) = 0x90;
+    
+	id1 = *(unsigned char *) bios;
+	id2 = *(unsigned char *) (bios + 0x01);
+
+	*bios = 0xF0;
+
+	usleep(10);
+    
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
+
+int erase_29f040b (struct flashchip * flash)
+{
+	char * bios = flash->virt_addr;
+
+	*(bios + 0x555) = 0xAA;
+	*(bios + 0x2AA) = 0x55;
+	*(bios + 0x555) = 0x80;
+	*(bios + 0x555) = 0xAA;
+	*(bios + 0x2AA) = 0x55;
+	*(bios + 0x555) = 0x10;
+
+	usleep(10);
+	toggle_ready_jedec(bios);
+}
+
+int write_29f040b (struct flashchip * flash, char * buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024, page_size = flash->page_size;
+	char * bios = flash->virt_addr;
+
+	printf ("Programming Page: ");
+	for (i = 0; i < total_size/page_size; i++) {
+		/* erase the page before programming */
+		erase_sector_29f040b(bios, i * page_size);
+
+		/* write to the sector */
+		printf ("%04d at address: ", i);
+		write_sector_29f040b(bios, buf + i * page_size, bios + i * page_size,
+				     page_size);
+		printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+}
diff --git a/flash.h b/flash.h
new file mode 100644
index 0000000..3b763a7
--- /dev/null
+++ b/flash.h
@@ -0,0 +1,44 @@
+#include <sys/io.h>
+#include <unistd.h>
+
+struct flashchip {
+	char * name;
+	int manufacture_id;
+	int model_id;
+
+	char * virt_addr;
+	int total_size;
+	int page_size;
+
+	int (*probe) (struct flashchip * flash);
+	int (*erase) (struct flashchip * flash);
+	int (*write) (struct flashchip * flash, char * buf);
+};
+
+#define AMD_ID            0x01
+#define AM_29F040B        0xA4
+
+#define ATMEL_ID          0x1F    /* Winbond Manufacture ID code	*/
+#define AT_29C040A        0xA4    /* Winbond w29c020c device code*/
+
+#define MX_ID             0xC2
+#define MX_29F002         0xB0
+
+#define SST_ID            0xBF	/* SST Manufacturer ID[B code	*/
+#define SST_29EE020A      0x10	/* SST 29EE020 device code	*/
+#define SST_28SF040       0x04    /* SST 29EE040 device code	*/
+
+#define WINBOND_ID        0xDA	/* Winbond Manufacture ID code	*/
+#define W_29C020C         0x45	/* Winbond w29c020c device code*/
+
+extern int probe_28sf040 (struct flashchip * flash);
+extern int erase_28sf040 (struct flashchip * flash);
+extern int write_28sf040 (struct flashchip * flash, char * buf);
+
+extern int probe_29f040b (struct flashchip * flash);
+extern int erase_29f040b (struct flashchip * flash);
+extern int write_29f040b (struct flashchip * flash, char * buf);
+
+extern int probe_29f002 (struct flashchip * flash);
+extern int erase_29f002 (struct flashchip * flash);
+extern int write_29f002 (struct flashchip * flash, char * buf);
diff --git a/flash_on.c b/flash_on.c
new file mode 100644
index 0000000..c8952e2
--- /dev/null
+++ b/flash_on.c
@@ -0,0 +1,74 @@
+/*
+ * flash_rom.c: Turnning on Flash Write Enable for SiS 630/950 M/Bs,
+ *              use this program before loading DoC drivers.
+ *
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ *	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 Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Reference:
+ *	1. SiS 630 Specification
+ *	2. SiS 950 Specification
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/io.h>
+#include <unistd.h>
+#include <stdio.h>
+
+main()
+{
+	char b;
+
+	/* get io privilege access PCI configuration space */
+	if (iopl(3) != 0) {
+		perror("Can not set io priviliage");
+		exit(1);
+	}
+
+	/* Enable 0xFFF8000~0xFFFF0000 decoding on SiS 540/630 */
+	outl(0x80000840, 0x0cf8);
+	b = inb(0x0cfc) | 0x0b;
+	outb(b, 0xcfc);
+	/* Flash write enable on SiS 540/630 */
+	outl(0x80000845, 0x0cf8);
+	b = inb(0x0cfd) | 0x40;
+	outb(b, 0xcfd);
+
+	/* The same thing on SiS 950 SuperIO side */
+	outb(0x87, 0x2e);
+	outb(0x01, 0x2e);
+	outb(0x55, 0x2e);
+	outb(0x55, 0x2e);
+
+	if (inb(0x2f) != 0x87) {
+		printf("Can not access SiS 950\n");
+		return -1;
+	}
+
+	outb(0x24, 0x2e);
+	b = inb(0x2f) | 0xfc;
+	outb(0x24, 0x2e);
+	outb(b, 0x2f);
+
+	outb(0x02, 0x2e);
+	outb(0x02, 0x2f);
+}
diff --git a/flash_rom.c b/flash_rom.c
new file mode 100644
index 0000000..12aa273
--- /dev/null
+++ b/flash_rom.c
@@ -0,0 +1,196 @@
+/*
+ * flash_rom.c: Flash programming utility for SiS 630/950 M/Bs
+ *
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ *	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 Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Reference:
+ *	1. SiS 630 Specification
+ *	2. SiS 950 Specification
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/io.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "flash.h"
+#include "jedec.h"
+
+struct flashchip flashchips[] = {
+    {"Am29F040B",   AMD_ID,     AM_29F040B,   NULL, 512, 64*1024,
+     probe_29f040b, erase_29f040b, write_29f040b},
+    {"At29C040A",   ATMEL_ID,   AT_29C040A,   NULL, 512, 256,
+     probe_jedec,   erase_jedec,   write_jedec},
+    {"Mx29f002",    MX_ID,      MX_29F002,    NULL, 256, 64*1024,
+     probe_29f002,  erase_29f002,  write_29f002},
+    {"SST29EE020A", SST_ID,     SST_29EE020A, NULL, 256, 128,
+     probe_jedec,   erase_jedec,   write_jedec},
+    {"SST28SF040A", SST_ID,     SST_28SF040,  NULL, 512, 256,
+     probe_28sf040, erase_28sf040, write_28sf040},
+    {"W29C020C",    WINBOND_ID, W_29C020C,    NULL, 256, 128,
+     probe_jedec,   erase_jedec,   write_jedec},
+    {NULL,}
+};
+
+int enable_flash_sis630 (void)
+{
+    char b;
+
+    /* get io privilege access PCI configuration space */
+    if (iopl(3) != 0) {
+    	perror("Can not set io priviliage");
+        exit(1);
+    }
+
+    /* Enable 0xFFF8000~0xFFFF0000 decoding on SiS 540/630 */
+    outl(0x80000840, 0x0cf8);
+    b = inb(0x0cfc) | 0x0b;
+    outb(b, 0xcfc);
+    /* Flash write enable on SiS 540/630 */
+    outl(0x80000845, 0x0cf8);
+    b = inb(0x0cfd) | 0x40;
+    outb(b, 0xcfd);
+
+    /* The same thing on SiS 950 SuperIO side */
+    outb(0x87, 0x2e);
+    outb(0x01, 0x2e);
+    outb(0x55, 0x2e);
+    outb(0x55, 0x2e);
+
+    if (inb(0x2f) != 0x87) {
+	outb(0x87, 0x4e);
+    	outb(0x01, 0x4e);
+    	outb(0x55, 0x4e);
+    	outb(0xaa, 0x4e);
+	if (inb(0x4f) != 0x87) {
+	    printf("Can not access SiS 950\n");
+	    return -1;
+	}
+	outb(0x24, 0x4e);
+	b = inb(0x4f) | 0xfc;
+	outb(0x24, 0x4e);
+	outb(b, 0x4f);
+	outb(0x02, 0x4e);
+	outb(0x02, 0x4f);	
+    }
+
+    outb(0x24, 0x2e);
+    printf("2f is %#x\n", inb(0x2f));
+    b = inb(0x2f) | 0xfc;
+    outb(0x24, 0x2e);
+    outb(b, 0x2f);
+
+    outb(0x02, 0x2e);
+    outb(0x02, 0x2f);
+
+    return 0;
+}
+
+struct flashchip * probe_flash(struct flashchip * flash)
+{
+    int fd_mem;
+    char * bios;
+    unsigned long size;
+
+    if ((fd_mem = open("/dev/mem", O_RDWR)) < 0) {
+	perror("Can not open /dev/mem");
+	exit(1);
+    }
+
+    while (flash->name != NULL) {
+	size = flash->total_size * 1024;
+	bios = mmap (0, size, PROT_WRITE | PROT_READ, MAP_SHARED,
+		     fd_mem, (off_t) (0 - size));
+	if (bios == MAP_FAILED) {
+	    perror("Error MMAP /dev/mem");
+	    exit(1);
+	}
+	flash->virt_addr = bios;
+
+	if (flash->probe(flash) == 1) {
+	    printf ("%s found at physical address: 0x%lx\n",
+		    flash->name, (0 - size), bios);
+	    return flash;
+	}
+	munmap (bios, size);
+	flash++;
+    }
+    return NULL;
+}
+
+int verify_flash (struct flashchip * flash, char * buf)
+{
+    int i = 0;
+    int total_size = flash->total_size *1024;
+    char * bios = flash->virt_addr;
+
+    printf("Verifying address: ");
+    while (i++ < total_size) {
+	printf("0x%08x", i);
+	if (*(bios+i) != *(buf+i)) {
+	    return 0;
+	}
+	printf("\b\b\b\b\b\b\b\b\b\b");
+    }
+    printf("\n");
+    return 1;
+}
+
+main (int argc, char * argv[])
+{
+    char * buf;
+    unsigned long size;
+    FILE * image;
+    struct flashchip * flash;
+
+    if (argc > 2){
+	printf("usage: %s [romimage]\n", argv[0]);
+	printf(" If no romimage is specified, then all that happens\n");
+	printf(" is that flash writes are enabled (useful for DoC)\n");
+	exit(1);
+    }
+
+    enable_flash_sis630 ();
+
+    if ((flash = probe_flash (flashchips)) == NULL) {
+	printf("EEPROM not found\n");
+	exit(1);
+    }
+
+    if (argc < 2){
+	printf("OK, only ENABLING flash write, but NOT FLASHING\n");
+        exit(0);
+    }
+    size = flash->total_size * 1024;
+
+    if ((image = fopen (argv[1], "r")) == NULL) {
+	perror("Error opening image file");
+	exit(1);
+    }
+
+    buf = (char *) calloc (size, sizeof(char));
+    fread (buf, sizeof(char), size, image);
+
+    flash->write (flash, buf);
+    verify_flash (flash, buf);
+}
diff --git a/jedec.c b/jedec.c
new file mode 100644
index 0000000..73a399c
--- /dev/null
+++ b/jedec.c
@@ -0,0 +1,88 @@
+/*
+ * jedec.c: driver for programming JEDEC standard flash parts
+ *
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ *	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 Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Reference:
+ *
+ * $Id$
+ */
+
+#include "flash.h"
+#include "jedec.h"
+
+int probe_jedec (struct flashchip * flash)
+{
+	char * bios = flash->virt_addr;
+	unsigned char  id1, id2;
+
+	*(char *) (bios + 0x5555) = 0xAA;
+	*(char *) (bios + 0x2AAA) = 0x55;
+	*(char *) (bios + 0x5555) = 0x90;
+
+	usleep(10);
+
+	id1 = *(unsigned char *) bios;
+	id2 = *(unsigned char *) (bios + 0x01);
+
+	*(char *) (bios + 0x5555) = 0xAA;
+	*(char *) (bios + 0x2AAA) = 0x55;
+	*(char *) (bios + 0x5555) = 0xF0;
+
+	usleep(10);
+
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
+
+int erase_jedec (struct flashchip * flash)
+{
+	char * bios = flash->virt_addr;
+
+	*(char *) (bios + 0x5555) = 0xAA;
+	*(char *) (bios + 0x2AAA) = 0x55;
+	*(char *) (bios + 0x5555) = 0x80;
+
+	*(char *) (bios + 0x5555) = 0xAA;
+	*(char *) (bios + 0x2AAA) = 0x55;
+	*(char *) (bios + 0x5555) = 0x10;
+
+	usleep(10);
+	toggle_ready_jedec(bios);
+}
+
+int write_jedec (struct flashchip * flash, char * buf)
+{
+	int i;
+	int total_size = flash->total_size *1024, page_size = flash->page_size;
+	char * bios = flash->virt_addr;
+
+	erase_jedec (flash);
+	printf ("Programming Page: ");
+	for (i = 0; i < total_size/page_size; i++) {
+		printf ("%04d at address: 0x%08x", i, i * page_size);
+		write_page_jedec(bios, buf + i * page_size, bios + i * page_size,
+				 page_size);
+		printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+	protect_jedec (bios);
+}
diff --git a/jedec.h b/jedec.h
new file mode 100644
index 0000000..de9c3d6
--- /dev/null
+++ b/jedec.h
@@ -0,0 +1,61 @@
+extern int probe_jedec (struct flashchip * flash);
+extern int erase_jedec (struct flashchip * flash);
+extern int write_jedec (struct flashchip * flash, char * buf);
+
+extern __inline__ void toggle_ready_jedec (char * dst)
+{
+	unsigned int i = 0;
+	char tmp1, tmp2;
+
+	tmp1 = *dst & 0x40;
+
+	while (i++ < 0xFFFFFF) {
+		tmp2 = *dst & 0x40;
+		if (tmp1 == tmp2) {
+			break;
+		}
+		tmp1 = tmp2;
+	}
+}
+
+extern __inline__ void data_polling_jedec (char * dst, char data)
+{
+	unsigned int i = 0;
+	char tmp;
+
+	data &= 0x80;
+
+	while (i++ < 0xFFFFFF) {
+		tmp = *dst & 0x80;
+		if (tmp == data) {
+			break;
+		}
+	}
+}
+
+extern __inline__ void protect_jedec (char * bios)
+{
+	*(char *) (bios + 0x5555) = 0xAA;
+	*(char *) (bios + 0x2AAA) = 0x55;
+	*(char *) (bios + 0x5555) = 0xA0;
+
+	usleep(200);
+}
+
+extern __inline__ void write_page_jedec (char * bios, char * src, char * dst,
+					 int page_size)
+{
+	int i;
+
+	*(char *) (bios + 0x5555) = 0xAA;
+	*(char *) (bios + 0x2AAA) = 0x55;
+	*(char *) (bios + 0x5555) = 0xA0;
+
+	for (i = 0; i < page_size; i++) {
+		/* transfer data from source to destination */
+		*dst++ = *src++;
+	}
+
+	usleep(100);
+	toggle_ready_jedec(dst-1);
+}
diff --git a/mx29f002.c b/mx29f002.c
new file mode 100644
index 0000000..e5c2c08
--- /dev/null
+++ b/mx29f002.c
@@ -0,0 +1,112 @@
+/*
+ * mx29f002.c: driver for MXIC MX29F002 flash models
+ *
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ *	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 Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Reference:
+ *	MX29F002/002N data sheet
+ *
+ * $Id$
+ */
+
+#include "flash.h"
+#include "jedec.h"
+
+int probe_29f002 (struct flashchip * flash)
+{
+	char * bios = flash->virt_addr;
+	unsigned char id1, id2, id3;
+
+	*(bios + 0x5555) = 0xAA;
+	*(bios + 0x2AAA) = 0x55;
+	*(bios + 0x5555) = 0x90;
+    
+	id1 = *(unsigned char *) bios;
+	id2 = *(unsigned char *) (bios + 0x01);
+ 
+	*bios = 0xF0;
+
+	usleep(10);
+
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	return 0;
+}
+
+int erase_29f002 (struct flashchip * flash)
+{
+	char * bios = flash->virt_addr;
+
+ again:
+	*(bios + 0x555) = 0xF0;
+	*(bios + 0x555) = 0xAA;
+	*(bios + 0x2AA) = 0x55;
+	*(bios + 0x555) = 0x80;
+	*(bios + 0x555) = 0xAA;
+	*(bios + 0x2AA) = 0x55;
+	*(bios + 0x555) = 0x10;
+
+	usleep(100);
+	toggle_ready_jedec(bios);
+
+	//   while ((*bios & 0x40) != 0x40)
+	//;
+
+#if 0
+	toggle_ready_jedec(bios);
+	*(bios + 0x0ffff) = 0x30;
+	*(bios + 0x1ffff) = 0x30;
+	*(bios + 0x2ffff) = 0x30;
+	*(bios + 0x37fff) = 0x30;
+	*(bios + 0x39fff) = 0x30;
+	*(bios + 0x3bfff) = 0x30;
+#endif
+
+}
+
+int write_29f002 (struct flashchip * flash, char * buf)
+{
+    int i;
+    int total_size = flash->total_size * 1024, page_size = flash->page_size;
+    char * bios = flash->virt_addr;
+    char * dst = bios, * src = buf;
+
+    *bios = 0xF0;
+    usleep(10);
+    erase_29f002(flash);
+    //*bios = 0xF0;
+#if 1
+   printf ("Programming Page: ");
+    for (i = 0; i < total_size; i++) {
+	/* write to the sector */
+	printf ("address: 0x%08lx", i);
+	*(bios + 0x5555) = 0xAA;
+	*(bios + 0x2AAA) = 0x55;
+	*(bios + 0x5555) = 0xA0;
+	*dst++ = 0x33;
+
+	/* wait for Toggle bit ready */
+	toggle_ready_jedec(dst);
+
+	printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+    }
+#endif
+    printf("\n");
+}
diff --git a/spd_dump.c b/spd_dump.c
new file mode 100644
index 0000000..f45ef31
--- /dev/null
+++ b/spd_dump.c
@@ -0,0 +1,136 @@
+/*
+ * acpi_reset.c: Reboot your LinuxBIOS system with ACPI software watchdo
+ *
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ *	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 Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Reference:
+ *	1. SiS 630 Specification
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/io.h>
+#include <unistd.h>
+#include <stdio.h>
+
+unsigned short acpi_base;
+
+void
+waitsmbus()
+{
+	unsigned short port = acpi_base;
+	unsigned char val;
+
+	//printf("waitsmb ..\n");
+
+	for (val = inb(port); (val & 8) == 0; val = inb(port))
+		;
+	//printf("past first test\n");
+}
+
+void
+setsmbus(unsigned char index, unsigned char value)
+{
+	unsigned short port = acpi_base + index;
+
+	//printf("setsmbus: index 0x%02x, value 0x%02x\n", 
+	//	index, value);
+
+	outb(value, port);
+}
+
+unsigned char
+getsmbus(unsigned char index)
+{
+	unsigned short port = acpi_base + index;
+	unsigned char value;
+
+	value = inb(port);
+
+	//printf("getsmbus: index 0x%02x, value 0x%02x\n", 
+	//	index, value);
+
+	return value;
+}
+
+unsigned char
+read_spd(unsigned char slot, unsigned char index)
+{
+	unsigned char value;
+
+	setsmbus(0x03, 0x20);
+
+	setsmbus(0x04, 0xA1 + (slot << 1));
+
+	setsmbus(0x05, index);
+
+	setsmbus(0x03, 0x12);
+
+	waitsmbus();
+
+	value = getsmbus(0x08);
+
+	setsmbus(0x00, 0xFF);
+
+	return value;
+}
+
+main()
+{
+	unsigned char b;
+	unsigned short w;
+
+
+	/* get io privilege access PCI configuration space */
+	if (iopl(3) != 0) {
+		perror("Can not set io priviliage");
+		exit(1);
+	}
+
+	/* Enable ACPI by set B7 on Reg 0x40, LPC */
+	outl(0x80000840, 0x0cf8);
+	b = inb(0x0cfc) | 0x80;
+	outb(b, 0xcfc);
+
+	/* get the ACPI base address for register 0x74,0x75 of LPC */
+	outl(0x80000874, 0x0cf8);
+	w = inw(0x0cfc);
+	acpi_base = w + 0x80;
+
+	printf("Number of bytes used by module manufacturer 0x%02x\n",
+	       read_spd(0x00, 0x00));
+
+	printf("Memory Type 0x%02x\n",
+	       read_spd(0x00, 0x02));
+
+	printf("Number of Row Address bits 0x%02x\n",
+	       read_spd(0x00, 0x03));
+
+	printf("Number of Column Address bits 0x%02x\n",
+	       read_spd(0x00, 0x04));
+
+	printf("Number of Sides 0x%02x\n",
+	       read_spd(0x00, 0x05));
+
+	printf("Number of Banks 0x%02x\n",
+	       read_spd(0x00, 0x11));
+}
diff --git a/sst28sf040.c b/sst28sf040.c
new file mode 100644
index 0000000..e0e5ea3
--- /dev/null
+++ b/sst28sf040.c
@@ -0,0 +1,159 @@
+/*
+ * sst28sf040.c: driver for SST28SF040C flash models.
+ *
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ *	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 Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Reference:
+ *	4 MEgabit (512K x 8) SuperFlash EEPROM, SST28SF040 data sheet
+ *
+ * $Id$
+ */
+
+#include "flash.h"
+#include "jedec.h"
+
+#define AUTO_PG_ERASE1		0x20
+#define AUTO_PG_ERASE2		0xD0
+#define AUTO_PGRM			0x10
+#define CHIP_ERASE		0x30
+#define RESET			0xFF
+#define READ_ID			0x90
+
+static __inline__ void protect_28sf040 (char * bios)
+{
+	/* ask compiler not to optimize this */
+	volatile unsigned char tmp;
+
+	tmp = *(unsigned char *) (bios + 0x1823);
+	tmp = *(unsigned char *) (bios + 0x1820);
+	tmp = *(unsigned char *) (bios + 0x1822);
+	tmp = *(unsigned char *) (bios + 0x0418);
+	tmp = *(unsigned char *) (bios + 0x041B);
+	tmp = *(unsigned char *) (bios + 0x0419);
+	tmp = *(unsigned char *) (bios + 0x040A);
+}
+
+static __inline__ void unprotect_28sf040 (char * bios)
+{
+	/* ask compiler not to optimize this */
+	volatile unsigned char tmp;
+
+	tmp = *(unsigned char *) (bios + 0x1823);
+	tmp = *(unsigned char *) (bios + 0x1820);
+	tmp = *(unsigned char *) (bios + 0x1822);
+	tmp = *(unsigned char *) (bios + 0x0418);
+	tmp = *(unsigned char *) (bios + 0x041B);
+	tmp = *(unsigned char *) (bios + 0x0419);
+	tmp = *(unsigned char *) (bios + 0x041A);
+}
+
+static __inline__ erase_sector_28sf040 (char * bios, unsigned long address)
+{
+	*bios = AUTO_PG_ERASE1;
+	*(bios + address) = AUTO_PG_ERASE2;
+
+	/* wait for Toggle bit ready         */
+	toggle_ready_jedec(bios);
+}
+
+static __inline__ write_sector_28sf040(char * bios, unsigned char * src,
+				       unsigned char * dst, unsigned int page_size)
+{
+	int i;
+
+	for (i = 0; i < page_size; i++) {
+		/* transfer data from source to destination */
+		if (*src == 0xFF) {
+			dst++, src++;
+			/* If the data is 0xFF, don't program it */
+			continue;
+		}
+		/*issue AUTO PROGRAM command */
+		*dst =  AUTO_PGRM;
+		*dst++ = *src++;
+
+		/* wait for Toggle bit ready */
+		toggle_ready_jedec(bios);
+	}
+}
+
+int probe_28sf040 (struct flashchip * flash)
+{
+	char * bios = flash->virt_addr;
+	unsigned char  id1, id2, tmp;
+
+	/* save the value at the beginning of the Flash */
+	tmp = *bios;
+
+	*bios = RESET;
+	usleep(10);
+
+	*bios = READ_ID;
+	usleep(10);
+	id1 = *(unsigned char *) bios;
+	usleep(10);
+	id2 = *(unsigned char *) (bios + 0x01);
+
+	*bios = RESET;
+	usleep(10);
+
+	if (id1 == flash->manufacture_id && id2 == flash->model_id)
+		return 1;
+
+	/* if there is no SST28SF040, restore the original value */
+	*bios = tmp;
+	return 0;
+}
+
+int erase_28sf040 (struct flashchip * flash)
+{
+	char * bios = flash->virt_addr;
+
+	unprotect_28sf040 (bios);
+	*bios = CHIP_ERASE;
+	*bios = CHIP_ERASE;
+	protect_28sf040 (bios);
+
+	usleep(10);
+	toggle_ready_jedec(bios);
+}
+
+int write_28sf040 (struct flashchip * flash, char * buf)
+{
+	int i;
+	int total_size = flash->total_size * 1024, page_size = flash->page_size;
+	char * bios = flash->virt_addr;
+
+	unprotect_28sf040 (bios);
+
+	printf ("Programming Page: ");
+	for (i = 0; i < total_size/page_size; i++) {
+		/* erase the page before programming */
+		erase_sector_28sf040(bios, i * page_size);
+
+		/* write to the sector */
+		printf ("%04d at address: 0x%08x", i, i * page_size);
+		write_sector_28sf040(bios, buf + i * page_size, bios + i * page_size,
+				     page_size);
+		printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+	}
+	printf("\n");
+
+	protect_28sf040 (bios);
+}