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);
+}