summaryrefslogtreecommitdiffstats
path: root/contrib/smc9462tx-flash
diff options
context:
space:
mode:
authorMichael Brown2005-05-17 18:44:57 +0200
committerMichael Brown2005-05-17 18:44:57 +0200
commit1097cf8685cd81f0003bd6f17d050e5174a85b90 (patch)
tree47a39f2a1e980cca43c28c4d1a6dfdf431b910b2 /contrib/smc9462tx-flash
parentQuickly hacked to use a buffer rather than a processor. (diff)
downloadipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.tar.gz
ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.tar.xz
ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.zip
Initial revision
Diffstat (limited to 'contrib/smc9462tx-flash')
-rw-r--r--contrib/smc9462tx-flash/Makefile20
-rw-r--r--contrib/smc9462tx-flash/README24
-rw-r--r--contrib/smc9462tx-flash/dp83820_write.c310
-rw-r--r--contrib/smc9462tx-flash/dp83820flash.c152
4 files changed, 506 insertions, 0 deletions
diff --git a/contrib/smc9462tx-flash/Makefile b/contrib/smc9462tx-flash/Makefile
new file mode 100644
index 00000000..dc5b3ff8
--- /dev/null
+++ b/contrib/smc9462tx-flash/Makefile
@@ -0,0 +1,20 @@
+GCC = gcc
+KERNELDIR = ../linux-2.4.20
+KERNELSTYLE=-D__KERNEL__ -DCPU=__i386__ -DMODULE
+INCLUDE_DIR=-I$(KERNELDIR)/include -I../include -I$(ROOTDIR)/include
+
+all: dp83820flash.o dp83820_write
+
+CFLAGS+=-O2 -Wall -fomit-frame-pointer -fno-strength-reduce
+CFLAGS+=$(KERNELSTYLE) $(CDEBUG) $(INCLUDE_DIR)
+
+install:
+
+dp83820flash.o: dp83820flash.c
+ $(GCC) dp83820flash.c -o dp83820flash.o -c $(CFLAGS)
+
+dp83820_write: dp83820_write.c
+ $(GCC) $< -o $@ -Wall -O2
+
+clean:
+ $(RM) *.o dp83820_write
diff --git a/contrib/smc9462tx-flash/README b/contrib/smc9462tx-flash/README
new file mode 100644
index 00000000..53501cb3
--- /dev/null
+++ b/contrib/smc9462tx-flash/README
@@ -0,0 +1,24 @@
+This code was written by Dave Ashley for NXTV, Inc. It is released under
+the terms of the GPL. The purpose is to let you write to the bootrom of
+the SMC9462TX card. The assumption is that you've stuck an AT29C512 in the
+socket. Note that the board has pins D5 + D6 reversed on the socket. Also
+the socket only supplies 3.3V to the rom. Good luck trying to locate a
+DIP programmable flash device that operates at 3.3V. What I do is to bend
+pin 32 back and solder a wire directly from the 5V side of the 3.3V regulator
+over to it. The dp83820's bootrom interface pins are all 5V logic tolerant.
+However mod your board at your own risk, no warranty or guarantees are implied
+or given!!! If you don't wire the 5V to the AT29C512, you can still read
+the rom contents (it operates ok at 3.3V evidently) but you can't write to it
+because the AT29C512 has a safety protection, it disables writes if the
+power supply voltage drops below 3.8V.
+
+See the comments at the top of the 2 C files for more information.
+
+The Makefile needs to be hacked to build for your system. If you can't
+figure it out you shouldn't be messing with this stuff anyway.
+
+-Dave Ashley
+Email address intentionally left out to avoid spam.
+http://www.xdr.com/dash
+
+Mon Mar 8 13:55:34 PST 2004
diff --git a/contrib/smc9462tx-flash/dp83820_write.c b/contrib/smc9462tx-flash/dp83820_write.c
new file mode 100644
index 00000000..ab6e5662
--- /dev/null
+++ b/contrib/smc9462tx-flash/dp83820_write.c
@@ -0,0 +1,310 @@
+/*
+ DP83820 flash utility written by Dave Ashley for NXTV, Inc.
+ Copyright (C) 2004 by NXTV, Inc.
+ Written 20040219 by Dave Ashley.
+
+ Currently only supports the AT29C512
+
+ This code is released under the terms of the GPL. No warranty.
+
+
+ THEORY:
+ This code uses the /proc/dp83820 file which is created by the
+ dp83820flash.o module. That file allows single byte reads + writes
+ to the bootrom.
+
+*/
+
+#include <unistd.h>
+#include <sys/io.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+
+
+// SMC9462TX card has D5 + D6 on the bootrom socket reversed
+int fixb(int val)
+{
+ return (val&~0x60) | ((val&0x20)<<1) | ((val&0x40)>>1);
+}
+int openit(void)
+{
+int fd;
+ fd=open("/proc/dp83820",O_RDWR);
+ if(fd<0)
+ {
+ printf("Failed to open the /proc/dp83820 file to access the flashrom.\n");
+ printf("Make sure you've done:\n");
+ printf(" modprobe dp83820flash\n");
+ exit(-1);
+ }
+ return fd;
+}
+void set(int addr, unsigned char val)
+{
+unsigned char msg[3];
+int fd;
+ fd=openit();
+ msg[0]=addr;
+ msg[1]=addr>>8;
+ msg[2]=val;
+ write(fd,msg,3);
+ close(fd);
+}
+int get(int addr)
+{
+unsigned char msg[2];
+int fd;
+ fd=openit();
+ msg[0]=addr;
+ msg[1]=addr>>8;
+ write(fd,msg,2);
+ read(fd,msg,1);
+ close(fd);
+ return msg[0];
+}
+
+
+int getromsize(unsigned char *id)
+{
+ if(id[0]==0xbf && id[1]==0xb6) return 0x40000;
+ if(id[0]==0xc2 && id[1]==0xb0) return 0x40000;
+ if(id[0]==0x1f && id[1]==0x3d) return 0x10000;
+ return -1;
+}
+
+#define MAXROMSIZE 0x200000
+unsigned char *buffer;
+
+int loadfile(char *name)
+{
+int filefd;
+int filesize;
+ filefd=open(name,O_RDONLY);
+ if(filefd<0)
+ {
+ printf("Couldn't open file %s\n",name);
+ return -1;
+ }
+ filesize=read(filefd,buffer,MAXROMSIZE);
+ close(filefd);
+ if(filesize<0)
+ {
+ printf("Error trying to read from file %s\n",name);
+ }
+ return filesize;
+}
+
+void readbios(char *name,int len)
+{
+int filefd;
+int filesize=0;
+unsigned char block[256];
+int i,j;
+
+ filefd=open(name,O_WRONLY|O_TRUNC|O_CREAT,0644);
+ if(filefd<0)
+ {
+ printf("Couldn't create file %s for writing\n",name);
+ return;
+ }
+ for(i=j=0;i<len;++i)
+ {
+ block[j++]=get(i);
+ if(j<sizeof(block)) continue;
+ filesize+=write(filefd,block,j);
+ j=0;
+ }
+ close(filefd);
+ if(filesize!=len)
+ {
+ printf("Error during write of %s file\n",name);
+ return;
+ }
+ printf("BIOS contents saved to %s, $%x bytes\n",name,len);
+}
+
+int verifybios(char *name,int len, int print)
+{
+int filelen;
+int i;
+int same=0;
+
+ filelen=loadfile(name);
+ for(i=0;i<filelen;++i)
+ if(get(i)!=buffer[i]) break;
+ if(i<filelen)
+ {
+ if(print)
+ printf("BIOS contents does not match file %s, from byte $%x\n",
+ name,i);
+ } else
+ {
+ if(print)
+ printf("BIOS contents match file %s for all of its $%x bytes\n",
+ name,i);
+ same=1;
+ }
+ return same;
+}
+
+void writebios(char *name,int len,unsigned char *id)
+{
+int i;
+int p1,p2;
+int sectorsize=128;
+
+ if(len!=loadfile(name))
+ {
+ printf("File size does not match expected ROM size\n");
+ return;
+ }
+ if(0 && (id[0]!=0xbf || id[1]!=0xb6))
+ {
+ printf("Don't know how to write this kind of flash device\n");
+ return;
+ }
+
+ printf("Erasing device\n");
+ set(0x5555,fixb(0xaa));
+ set(0x2aaa,fixb(0x55));
+ set(0x5555,fixb(0x80));
+ set(0x5555,fixb(0xaa));
+ set(0x2aaa,fixb(0x55));
+ set(0x5555,fixb(0x10));
+
+ for(;;)
+ {
+ printf(".");fflush(stdout);
+ usleep(250000);
+ if(get(0)==get(0) && get(0)==get(0))
+ break;
+ }
+ printf("BIOS erased\n");
+
+ printf("Writing to BIOS\n");
+ p1=-1;
+ for(i=0;i<len;++i)
+ {
+ p2=100*i/(len-1);
+ if(p2!=p1)
+ {
+ printf("\r%d%%",p1=p2);
+ fflush(stdout);
+ }
+ if(i%sectorsize==0)
+ {
+ set(0x5555,fixb(0xaa));
+ set(0x2aaa,fixb(0x55));
+ set(0x5555,fixb(0xa0));
+ }
+ set(i,buffer[i]);
+ if(i%sectorsize==sectorsize-1)
+ while(get(0)!=get(0) || get(0)!=get(0));
+ }
+ printf("\n");
+}
+
+void helptext(char *name)
+{
+ printf("USE: %s <options>\n",name);
+ printf(" -v <filename> = verify bios rom contents with file\n");
+ printf(" -w <filename> = write to bios rom contents from file\n");
+ printf(" -r <filename> = read from bios rom contents to file\n");
+ printf(" -f = force erase/write even if contents already match\n");
+ exit(0);
+}
+
+int main(int argc,char **argv)
+{
+int i;
+int vals;
+unsigned char id[4];
+char *filename=0;
+char action=0;
+int romsize;
+int force=0;
+int same;
+
+ vals=0;
+
+ if(argc<2) helptext(argv[0]);
+ for(i=1;i<argc;++i)
+ {
+ if(argv[i][0]!='-')
+ helptext(argv[0]);
+ switch(argv[i][1])
+ {
+ case 'f':
+ force=1;
+ break;
+ case 'v':
+ case 'w':
+ case 'r':
+ action=argv[i][1];
+ if(i+1<argc)
+ filename=argv[++i];
+ else helptext(argv[0]);
+ break;
+ default:
+ helptext(argv[0]);
+ }
+
+ }
+
+ buffer=malloc(MAXROMSIZE);
+ if(!buffer)
+ {
+ printf("No memory available!\n");
+ exit(-1);
+ }
+
+ set(0x5555,fixb(0xaa)); // get into flash ID mode
+ set(0x2aaa,fixb(0x55));
+ set(0x5555,fixb(0x90));
+
+ for(i=0;i<4;++i) id[i]=get(i);
+
+ set(0x5555,fixb(0xaa)); // get out of flash ID mode
+ set(0x2aaa,fixb(0x55));
+ set(0x5555,fixb(0xf0));
+ usleep(10000);
+
+ for(i=0;i<4;++i)
+ if(id[i]!=get(i)) break;
+ if(i==4)
+ {
+ printf("Could not read BIOS flashrom ID.\n");
+ goto biosdone;
+ }
+ printf("ID %02x %02x\n",id[0],id[1]);
+ romsize=getromsize(id);
+ if(romsize<0)
+ {
+ printf("Unknown rom type\n");
+ goto biosdone;
+ }
+ printf("romsize=$%x bytes\n",romsize);
+ if(action=='r')
+ readbios(filename,romsize);
+ if(action=='w')
+ {
+ if(!force)
+ same=verifybios(filename,romsize,0);
+ else
+ same=0;
+ if(!same)
+ writebios(filename,romsize,id);
+ }
+ if(action=='v' || action=='w')
+ verifybios(filename,romsize,1);
+
+biosdone:
+
+ return 0;
+}
diff --git a/contrib/smc9462tx-flash/dp83820flash.c b/contrib/smc9462tx-flash/dp83820flash.c
new file mode 100644
index 00000000..661c4291
--- /dev/null
+++ b/contrib/smc9462tx-flash/dp83820flash.c
@@ -0,0 +1,152 @@
+/*
+ Kernel module for the dp83820 flash write utility. This code was written
+ by Dave Ashley for NXTV, Inc.
+ Copyright 2004 by NXTV, Inc.
+ Written 20040219 by Dave Ashley.
+
+ This code is released under the terms of the GPL. No warranty.
+
+ THEORY: The dp83820 bootrom interface is flawed in that you can't
+ read or write a single byte at a time, and this is required in order
+ to write to flash devices like the AT29C512. So the workaround is
+ to use the chips ability to map into memory the bootrom, then the cpu
+ can directly do byte accesses.
+
+ The problem is that a "feature" of the dp83820 is that when you map
+ in the bootrom, you conveniently lose access to the PCI registers.
+ So we need to do this in kernel space and wrap every access to the
+ bootrom within interrupt_disable/restore, in case a network interrupt
+ were to come in.
+
+ This kernel module is very simple, it just creates a proc file
+ /proc/dp83820
+ If you write 3 bytes to this file you are doing a write to the flashrom:
+
+Byte 1 2 3
+ ALOW AHIGH DATA
+
+ If you write 2 bytes to this file you are doing a read from the flashrom:
+Byte 1 2
+ ALOW AHIGH
+ Then the next read from the file will return a single byte of what
+ was at that location.
+
+ You only get one shot at accessing the proc file, you need to then
+ close/open if you want to do another access. This could probably be
+ cleaned up pretty easily so more accesses can be done without having
+ to close/open the file.
+
+*/
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+
+
+#define PROCNAME "dp83820"
+
+struct pci_dev *mydev=0;
+unsigned long loc;
+unsigned char *addr=0;
+
+unsigned char lastread;
+
+
+int my_read_proc(char *buf, char **start,off_t offset,int count, int *eof,void *data)
+{
+int retval=0;
+
+ if(count>0)
+ {
+ buf[0]=lastread;
+ retval=1;
+ }
+
+ *eof=1;
+
+ return retval;
+}
+
+int my_write_proc(struct file *file, const char *buffer, unsigned long count,
+ void *data)
+{
+unsigned char *msg;
+
+unsigned long flags;
+
+ msg=(void *)buffer;
+ save_flags(flags);
+ cli();
+ pci_write_config_dword(mydev, 0x30, loc | 1);
+
+ switch(count)
+ {
+ case 2:
+ lastread=addr[msg[0] | (msg[1]<<8)];
+ break;
+ case 3:
+ addr[msg[0] | (msg[1]<<8)] = msg[2];
+ break;
+ }
+ pci_write_config_dword(mydev, 0x30, loc);
+ restore_flags(flags);
+ return count;
+}
+
+
+struct proc_dir_entry *de=0;
+
+int __init init_module(void)
+{
+int found=0;
+ mydev=0;
+ pci_for_each_dev(mydev)
+ {
+ if(mydev->vendor==0x100b && mydev->device==0x0022)
+ {
+ found=1;
+ break;
+ }
+ }
+ if(!found)
+ {
+ printk("Could not find DP83820 network device\n");
+ return ENODEV;
+ }
+
+ de=create_proc_entry(PROCNAME,0,0);
+ if(!de)
+ return -1;
+ de->data=0;
+ de->read_proc=my_read_proc;
+ de->write_proc=my_write_proc;
+
+ loc=mydev->resource[PCI_ROM_RESOURCE].start;
+ addr=ioremap_nocache(loc,0x10000);
+
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if(de)
+ {
+ remove_proc_entry(PROCNAME,0);
+ de=0;
+ }
+ if(addr)
+ {
+ iounmap(addr);
+ addr=0;
+ }
+}
+