1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-26 14:42:36 +02:00

Trying to make this general purpose user-land flash burner

Corresponding to coreboot v1 svn r489.
This commit is contained in:
Ronald G. Minnich 2002-01-29 18:21:41 +00:00
commit 5e5f75e559
11 changed files with 1016 additions and 0 deletions

11
Makefile Normal file
View File

@ -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 *~

15
README Normal file
View File

@ -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

120
am29f040b.c Normal file
View File

@ -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");
}

44
flash.h Normal file
View File

@ -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);

74
flash_on.c Normal file
View File

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

196
flash_rom.c Normal file
View File

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

88
jedec.c Normal file
View File

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

61
jedec.h Normal file
View File

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

112
mx29f002.c Normal file
View File

@ -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");
}

136
spd_dump.c Normal file
View File

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

159
sst28sf040.c Normal file
View File

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