Initial revision

This commit is contained in:
Michael Brown
2005-05-17 16:44:57 +00:00
parent 75a5374d79
commit 1097cf8685
164 changed files with 24592 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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