diff options
author | Michael Brown | 2005-05-17 18:44:57 +0200 |
---|---|---|
committer | Michael Brown | 2005-05-17 18:44:57 +0200 |
commit | 1097cf8685cd81f0003bd6f17d050e5174a85b90 (patch) | |
tree | 47a39f2a1e980cca43c28c4d1a6dfdf431b910b2 /contrib/smc9462tx-flash | |
parent | Quickly hacked to use a buffer rather than a processor. (diff) | |
download | ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.tar.gz ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.tar.xz ipxe-1097cf8685cd81f0003bd6f17d050e5174a85b90.zip |
Initial revision
Diffstat (limited to 'contrib/smc9462tx-flash')
-rw-r--r-- | contrib/smc9462tx-flash/Makefile | 20 | ||||
-rw-r--r-- | contrib/smc9462tx-flash/README | 24 | ||||
-rw-r--r-- | contrib/smc9462tx-flash/dp83820_write.c | 310 | ||||
-rw-r--r-- | contrib/smc9462tx-flash/dp83820flash.c | 152 |
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; + } +} + |