📄 drv.c
字号:
void ffsdrv_ram_intel_erase(uint8 block);
#else // (TARGET == 0)
// On PC these functions are empty
void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value) {}
void ffsdrv_ram_intel_sb_erase(uint8 block) {}
void ffsdrv_ram_intel_erase(uint8 block) {}
#endif // (TARGET == 1)
/******************************************************************************
* Intel Dual/Multi Bank Driver Functions
******************************************************************************/
void ffsdrv_intel_write_end(void);
void ffsdrv_intel_erase_end(void);
// ffsdrv_intel_write_halfword and ffsdrv_intel_write_end is not used
// because of the bug in the intel flash device. Instead is the functions
// ffsdrv_ram_intel_sb_write_halfword and ffsdrv_ram_intel_erase used.
void ffsdrv_intel_write_halfword(volatile uint16 *addr, uint16 value)
{
uint32 cpsr;
tlw(led_on(LED_WRITE));
ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value));
dev.addr = addr;
if (~*addr & value) {
ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value));
return;
}
cpsr = int_disable();
dev.state = DEV_WRITE;
#if 1
*addr = 0x60; // Intel Config setup
*addr = 0xD0; // Intel Unlock block
*addr = 0x50; // Intel Clear Status Register
#endif
*addr = 0x40; // Intel program byte/word
*addr = value;
int_enable(cpsr);
ffsdrv_intel_write_end();
}
void ffsdrv_intel_write(void *dst, const void *src, uint16 size)
{
uint8 *mydst = dst;
const uint8 *mysrc = src;
if (size > 0)
{
if ((unsigned int) mydst & 1) {
ffsdrv_write_byte(mydst++, *mysrc++);
size--;
}
while (size >= 2) {
ffsdrv_intel_write_halfword((uint16 *) mydst,
mysrc[0] | (mysrc[1] << 8));
size -= 2;
mysrc += 2;
mydst += 2;
}
if (size == 1)
ffsdrv_write_byte(mydst++, *mysrc++);
}
}
void ffsdrv_intel_write_end(void)
{
// We can be interrupted and reentered thus the state can have been changed.
while ((*dev.addr & 0x80) == 0 && dev.state == DEV_WRITE)
;
*dev.addr = 0xFF; // Intel read array
dev.state = DEV_READ;
tlw(led_off(LED_WRITE));
}
void ffsdrv_intel_erase(uint8 block)
{
uint32 cpsr;
ttw(ttr(TTrDrvErase, "e(%d)" NL, block));
tlw(led_on(LED_ERASE));
dev.addr = (uint16 *) block2addr(block);
cpsr = int_disable();
dev.state = DEV_ERASE;
#if 1
*dev.addr = 0x60; // Intel Config setup
*dev.addr = 0xD0; // Intel Unlock block
#endif
*dev.addr = 0x50; // Intel clear status register (not really necessary)
*dev.addr = 0x20; // Intel erase setup
*dev.addr = 0xD0; // Intel erase confirm
int_enable(cpsr);
ffsdrv_intel_erase_end();
}
void ffsdrv_intel_erase_end(void)
{
while ((*dev.addr & 0x80) == 0)
;
*dev.addr = 0xFF; // Intel read array
dev.state = DEV_READ;
tlw(led_off(LED_ERASE));
}
void ffsdrv_intel_erase_suspend(void)
{
uint32 cpsr;
uint16 poll;
ttw(str(TTrDrvErase, "es" NL));
tlw(led_on(LED_ERASE_SUSPEND));
cpsr = int_disable();
dev.state = DEV_ERASE_SUSPEND;
*dev.addr = 0xB0; // Intel Erase Suspend
*dev.addr = 0x70; // Intel Read Status Register
while (((poll = *dev.addr) & 0x80) == 0)
;
if ((poll & 0x40) == 0) {
// Block erase has completed
tlw(led_off(LED_ERASE_SUSPEND));
dev.state = DEV_READ;
tlw(led_off(LED_ERASE));
}
*dev.addr = 0xFF; // Intel read array
int_enable(cpsr);
}
void ffsdrv_intel_erase_resume(void)
{
uint32 cpsr;
ttw(str(TTrDrvErase, "er" NL));
cpsr = int_disable();
dev.state = DEV_ERASE;
*dev.addr = 0xD0; // Intel erase resume
// The following "extra" Read Status command is required because Intel has
// changed the specification of the W30 flash! (See "1.8 Volt Intel?// Wireless Flash Memory with 3 Volt I/O 28F6408W30, 28F640W30, 28F320W30
// Specification Update")
*dev.addr = 0x70; // Intel Read Status Register
int_enable(cpsr);
tlw(led_off(LED_ERASE_SUSPEND));
}
/******************************************************************************
* Void Functions
******************************************************************************/
int ffsdrv_null_init(void)
{
ttw(ttr(TTrDrvOther, "ffsdrv_null_init()" NL));
return 0;
}
void ffsdrv_null_erase(uint8 block)
{
ttw(ttr(TTrDrvErase, "ffsdrv_null_erase(%d)" NL, block));
}
void ffsdrv_null_write_halfword(volatile uint16 *addr, uint16 value)
{
ttw(ttr(TTrDrvWrite, "ffsdrv_null_write_halfword(0x%x, 0x%x)" NL, addr, value));
}
void ffsdrv_null_write(void *dst, const void *src, uint16 size)
{
ttw(ttr(TTrDrvWrite, "ffsdrv_null_write(0x%x, 0x%x, %d)" NL, dst, src, size));
}
void ffsdrv_null_erase_suspend(void)
{
ttw(str(TTrDrvErase, "ffsdrv_null_erase_suspend()" NL));
}
void ffsdrv_null_erase_resume(void)
{
ttw(str(TTrDrvErase, "ffsdrv_null_erase_resume()" NL));
}
void ffsdrv_null_write_end(void)
{
ttw(str(TTrDrvWrite, "ffsdrv_null_write_end()" NL));
}
void ffsdrv_null_erase_end(void)
{
ttw(str(TTrDrvErase, "ffsdrv_null_erase_end()" NL));
}
/******************************************************************************
* Test Driver Functions
******************************************************************************/
#if (TARGET == 0)
static char *image_addr = 0;
static int image_size = 0;
static int image_fd = 0;
extern int arg_removeimage;
extern char *arg_imagename;
extern void test_fatal_printf(char *format, ...);
void ffsdrv_write_check(char *addr, int size)
{
offset_t offset, last;
offset = addr2offset(addr);
last = dev.binfo[dev.numblocks-1].offset
+ (1 << dev.binfo[dev.numblocks-1].size_ld);
if (offset < 0 || (offset + size) > last) {
fprintf(stderr, "ffsdrv_write_check() failed (addr = 0x%x, size = %d)\n",
(int) addr, size);
fprintf(stdout, "ffsdrv_write_check() failed (addr = 0x%x, size = %d)\n",
(int) addr, size);
exit (1);
}
}
void ffsdrv_write_error(uint16 old, uint16 new)
{
test_fatal_printf("FATAL: Attempt to rewrite 0 to 1 bit "
"(old:0x%x/%c new:0x%x/%c)\n",
old, (old < ' ' ? '?' : old),
new, (new < ' ' ? '?' : new));
}
void ffsdrv_test_write_halfword(volatile uint16 *addr, uint16 value)
{
tw(tr(TR_FUNC, TrDrvWrite, "test_write_halfword(0x%05x, 0x%x)\n",
addr2offset(addr), value));
ffsdrv_write_check((uint8 *) addr, 2);
if (~*addr & value)
ffsdrv_write_error(*addr, value);
*addr = value;
}
void ffsdrv_test_write(void *dst, const void *src, uint16 size)
{
uint8 *mydst = dst;
const uint8 *mysrc = src;
tw(tr(TR_FUNC, TrDrvWrite, "test_write(0x%05x, 0x%x, %d)\n",
addr2offset(mydst), mysrc, size));
if (size > 0)
{
if ((int) mydst & 1) {
ffsdrv_write_byte(mydst++, *mysrc++);
size--;
}
while (size >= 2) {
ffsdrv_test_write_halfword((uint16 *) mydst, mysrc[0]|(mysrc[1] << 8));
size -= 2;
mysrc += 2;
mydst += 2;
}
if (size == 1)
ffsdrv_write_byte(mydst++, *mysrc++);
}
}
void ffsdrv_test_erase(uint8 block)
{
int i;
uint8 *addr;
addr = block2addr(block);
tw(tr(TR_FUNC, TrDrvErase, "ffsdrv_test_erase(%d)\n", block));
for (i = 0; i < 1 << dev.binfo[block].size_ld; i++) {
*addr++ = 0xFF;
}
}
char *ffsdrv_test_create(void)
{
// If flash image file already exists, open the file, and mmap it.
// Otherwise, create file, fill file with 1's, then mmap it.
int i;
struct stat statbuf;
image_size = (int) dev.binfo[dev.numblocks - 1].offset +
(1 << dev.binfo[dev.numblocks - 1].size_ld);
tw(tr(TR_BEGIN, TrDrvInit, "ffsdrv_test_create() {\n"));
tw(tr(TR_FUNC, TrDrvInit, "%s image: '%s', size = %d\n",
arg_removeimage ? "new" : "current", arg_imagename, image_size));
// create file if it does not exist
if (arg_removeimage || lstat(arg_imagename, &statbuf) == -1)
{
char data[64];
// only the first run should remove the flash image file
arg_removeimage = 0;
tw(tr(TR_FUNC, TrDrvInit, "creating new flash image file '%s'\n",
arg_imagename));
image_fd = open(arg_imagename , O_RDWR|O_CREAT,
(S_IRWXU & ~S_IXUSR) |
( S_IRWXG & ~S_IXGRP) | (S_IRWXO & ~S_IXOTH));
if (image_fd == -1) {
perror("Failed to create flash image");
exit(1);
}
// write 1's to the file.
for (i = 0; i < 64; i++)
data[i] = 0xff;
for (i = 0; i < image_size/64; i++) {
write(image_fd, data, 64);
}
close(image_fd);
image_fd = 0;
tw(tr(TR_FUNC, TrDrvInit, "flash image file created\n"));
}
// only open image file if this is the first initialization.
if (image_fd > 0) {
tw(tr(TR_FUNC, TrDrvInit, "re-opening '%s' file of size %d\n",
arg_imagename, image_size));
}
else {
tw(tr(TR_FUNC, TrDrvInit, "opening '%s' file of size %d\n",
arg_imagename, image_size));
image_fd = open(arg_imagename, O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
if (image_fd == -1) {
perror("Failed to open flash image");
exit(1);
}
// memory map the file and update block addresses of binfo array
image_addr = mmap(0, image_size, PROT_READ|PROT_WRITE,
MAP_FILE|MAP_SHARED, image_fd, 0);
}
tw(tr(TR_END, TrDrvInit, "}\n"));
return image_addr;
}
#endif // (TARGET == 0)
/******************************************************************************
* Device Detection and Copying of Driver to RAM
******************************************************************************/
#if (TARGET == 1)
// Note that this function reads device code of any of the three known flash
// families; Intel, AMD and SST. This works because Intel and AMD use
// the same command data for entering READ_IDENTIFIER mode (0x90).
// The function should be copied and executed from RAM!
void ffsdrv_device_id_read(uint16 *manufact, uint16 *device)
{
int addr, i;
// This silly looking code has one purpose; to set addr = 0xAAAA. It is
// necessary in order to force the compiler NOT to produce code that
// uses LDR opcode(s) with PC-relative addressing. The assember code
// produced from this C code is completely relocatable!
for (i = 0, addr = 0; i < 2; i++)
addr |= addr << 8 | 0xAA;
FLASH_WRITE_HALFWORD (addr, 0xAA);
FLASH_WRITE_HALFWORD (addr >> 1, 0x55);
FLASH_WRITE_HALFWORD (addr, 0x90); // Intel/AMD read id command
*manufact = FLASH_READ_HALFWORD (0); // flash a0 = 0
*device = FLASH_READ_HALFWORD (2); // flash a0 = 1
FLASH_WRITE_HALFWORD (0, 0xFF); // Intel read-array command
// AMD devices do not need the two unlock cycles but SST devices do,
// even though the SST datasheets states otherwise ;-)
FLASH_WRITE_HALFWORD (addr, 0xAA);
FLASH_WRITE_HALFWORD (addr >> 1, 0x55);
FLASH_WRITE_HALFWORD (addr, 0xF0); // AMD read-array/reset command
}
// Copy ffsdrv_device_id_read() function code to RAM. The only known way to
// determine the size of the code is to look either in the linker-generated
// map file or in the assember output file.
void ffsdrv_device_id_read_copy_to_ram(uint16 *dst, int size)
{
uint16 *src = (uint16 *) &ffsdrv_device_id_read;
// The ARM7TDMI compiler sets bit 0 for thumb mode function pointers, so
// we need to clear this in order to copy *all* bytes. Otherwise we
// exclude first byte and the resulting copy becomes garbage
src = (uint16 *) (~1 & (int) src);
size /= 2;
while (size--)
*dst++ = *src++;
}
// Copy ffsdrv_xxx_sb_erase() and ffsdrv_xxx_sb_write_halfword() functions
// to RAM. The only known way to determine the size of the code is to look
// either in the linker-generated map file or in the assember output file.
int ffsdrv_driver_copy_to_ram(int type)
{
int size;
uint16 *src, *dst;
extern uint16 ffsdrv_ram_amd_begin[];
extern uint16 ffsdrv_ram_intel_begin[];
uint32 offset_of_init;
uint32 offset_of_erase;
uint32 offset_of_write_halfword;
ttw(ttr(TTrDrvOther, "ffsdrv_driver_copy_to_ram() {" NL));
switch (type) {
case FFS_DRIVER_AMD:
case FFS_DRIVER_AMD_SB:
src = ffsdrv_ram_amd_begin;
offset_of_erase =
(uint32) ffsdrv_ram_amd_sb_erase - (uint32) src;
offset_of_write_halfword =
(uint32) ffsdrv_ram_amd_sb_write_halfword - (uint32) src;
break;
case FFS_DRIVER_INTEL_SB:
src = ffsdrv_ram_intel_begin;
offset_of_init =
(uint32) ffsdrv_ram_intel_sb_init - (uint32) src;
offset_of_erase =
(uint32) ffsdrv_ram_intel_sb_erase - (uint32) src;
offset_of_write_halfword =
(uint32) ffsdrv_ram_intel_sb_write_halfword - (uint32) src;
case FFS_DRIVER_INTEL:
src = ffsdrv_ram_intel_begin;
offset_of_init =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -