mirror of
https://github.com/ipxe/ipxe
synced 2026-01-30 04:58:12 +03:00
Initial revision
This commit is contained in:
20
contrib/smc9462tx-flash/Makefile
Normal file
20
contrib/smc9462tx-flash/Makefile
Normal 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
|
||||
24
contrib/smc9462tx-flash/README
Normal file
24
contrib/smc9462tx-flash/README
Normal 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
|
||||
310
contrib/smc9462tx-flash/dp83820_write.c
Normal file
310
contrib/smc9462tx-flash/dp83820_write.c
Normal 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;
|
||||
}
|
||||
152
contrib/smc9462tx-flash/dp83820flash.c
Normal file
152
contrib/smc9462tx-flash/dp83820flash.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user