📄 drv.c
字号:
(uint32) ffsdrv_ram_intel_sb_init - (uint32) src;
offset_of_erase =
(uint32) ffsdrv_ram_intel_erase - (uint32) src;
offset_of_write_halfword =
(uint32) ffsdrv_ram_intel_sb_write_halfword - (uint32) src;
break;
default:
ttw(ttr(TTrDrvOther, "}" NL));
return 0;
}
// Make sure we are handling a half-word aligned address (Thumb mode
// function pointers have lsb set!)
src = (uint16 *) (~1 & (int) src);
// If we detect that the linker allocated the driver to RUN in RAM, the
// user has obviously NOT removed those linker lines and we bail out!
if (offset_of_erase > FFSDRV_CODE_SIZE)
return EFFS_DRIVER;
dst = (uint16 *) &ffsdrv_code;
// Code size in halfwords
size = FFSDRV_CODE_SIZE / 2;
// Rebind the two changed driver functions
if (type == FFS_DRIVER_AMD_SB || type == FFS_DRIVER_INTEL_SB) {
ffsdrv.erase =
(void (*)(uint8))
(offset_of_erase + (uint32) dst);
ffsdrv.write_halfword =
(void (*)(volatile uint16 *, uint16))
(offset_of_write_halfword + (uint32) dst);
}
if (type == FFS_DRIVER_INTEL_SB) {
ffsdrv.init =
(int (*)(void))
(offset_of_init + (uint32) dst);
}
ttw(ttr(TTrDrvOther, "ffsdrv_code, init, write, erase = 0x%07x, 0x%07x, 0x%07x, 0x%07x" NL,
dst, (uint32) ffsdrv.init,
(uint32) ffsdrv.write_halfword, (uint32) ffsdrv.erase));
ttw(ttr(TTrDrvOther, "amd_begin, init, write, erase = 0x%07x, 0x%07x, 0x%07x, 0x%07x" NL,
ffsdrv_ram_amd_begin, ffsdrv_null_init,
ffsdrv_ram_amd_sb_write_halfword, ffsdrv_ram_amd_sb_erase));
ttw(ttr(TTrDrvOther, "intel_begin, init, write, erase = 0x%07x, 0x%07x, 0x%07x, 0x%07x" NL,
ffsdrv_ram_intel_begin, ffsdrv_ram_intel_sb_init,
ffsdrv_ram_intel_sb_write_halfword, ffsdrv_ram_intel_sb_erase));
// Copy the code to RAM
while (size--)
*dst++ = *src++;
ttw(ttr(TTrDrvOther, "}" NL));
return 0;
}
#else // (TARGET == 0)
void ffsdrv_device_id_read(uint16 *manufact, uint16 *device) {}
int ffsdrv_driver_copy_to_ram(int type) { return 0; }
#endif // (TARGET == 1)
#if (BOARD == 34)
/******************************************************************************
* RAM Family Functions
******************************************************************************/
void ffsdrv_ram_write_halfword(volatile uint16 *dst, uint16 value)
{
*dst = value;
}
void ffsdrv_ram_write(void *dst, const void *src, uint16 size)
{
uint8 *mydst = dst;
const uint8 *mysrc = src;
if (size == 0)
return;
else if (size == 1)
ffsdrv_write_byte(mydst, *mysrc);
else {
if ((int) mydst & 1) {
ffsdrv_write_byte(mydst++, *mysrc++);
size--;
}
while (size >= 2) {
ffsdrv_ram_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_ram_erase(uint8 block)
{
int i;
char *addr;
addr = block2addr(block);
for (i = 0; i < 1 << dev.binfo[block].size_ld; i++) {
*addr++ = 0xFF;
}
}
void ffsdrv_void_write_end(void)
{
}
void ffsdrv_void_erase_suspend(void)
{
}
void ffsdrv_void_erase_resume(void)
{
}
#endif // BOARD = 34
/******************************************************************************
* Initialization
******************************************************************************/
const struct ffsdrv_s ffsdrv_amd = {
ffsdrv_null_init,
ffsdrv_amd_erase,
ffsdrv_amd_write_halfword,
ffsdrv_amd_write,
ffsdrv_amd_write_end,
ffsdrv_amd_erase_suspend,
ffsdrv_amd_erase_resume
};
const struct ffsdrv_s ffsdrv_amd_sb = {
ffsdrv_null_init,
ffsdrv_ram_amd_sb_erase,
ffsdrv_ram_amd_sb_write_halfword,
ffsdrv_generic_write,
ffsdrv_null_write_end,
ffsdrv_null_erase_suspend,
ffsdrv_null_erase_resume
};
const struct ffsdrv_s ffsdrv_sst = {
ffsdrv_null_init,
ffsdrv_sst_erase,
ffsdrv_amd_write_halfword, // Use AMD driver function
ffsdrv_sst_write,
ffsdrv_amd_write_end, // Use AMD driver function
ffsdrv_sst_erase_suspend,
ffsdrv_null_erase_resume
};
const struct ffsdrv_s ffsdrv_sst_sb = {
ffsdrv_null_init,
ffsdrv_null_erase,
ffsdrv_null_write_halfword,
ffsdrv_null_write,
ffsdrv_null_write_end,
ffsdrv_null_erase_suspend,
ffsdrv_null_erase_resume
};
// We use the functions ffsdrv_ram_intel_sb_write_halfword and
// ffsdrv_ram_intel_erase due to the bug in the intel wireless flash
// device. See 28F640W30.pdf specification Errata 5.
const struct ffsdrv_s ffsdrv_intel = {
ffsdrv_null_init,
ffsdrv_intel_erase,
ffsdrv_intel_write_halfword,
ffsdrv_generic_write,
ffsdrv_intel_write_end,
ffsdrv_intel_erase_suspend,
ffsdrv_intel_erase_resume
};
const struct ffsdrv_s ffsdrv_intel_sb = {
ffsdrv_null_init,
ffsdrv_ram_intel_sb_erase,
ffsdrv_ram_intel_sb_write_halfword,
ffsdrv_generic_write,
ffsdrv_null_write_end,
ffsdrv_null_erase_suspend,
ffsdrv_null_erase_resume
};
const struct ffsdrv_s ffsdrv_null = {
ffsdrv_null_init,
ffsdrv_null_erase,
ffsdrv_null_write_halfword,
ffsdrv_null_write,
ffsdrv_null_write_end,
ffsdrv_null_erase_suspend,
ffsdrv_null_erase_resume
};
const struct ffsdrv_s ffsdrv_amd_pseudo_sb = {
ffsdrv_null_init,
ffsdrv_amd_pseudo_sb_erase,
ffsdrv_amd_pseudo_sb_write_halfword,
ffsdrv_generic_write,
ffsdrv_null_write_end,
ffsdrv_null_erase_suspend,
ffsdrv_null_erase_resume
};
#if (TARGET == 0)
const struct ffsdrv_s ffsdrv_test = {
ffsdrv_null_init,
ffsdrv_test_erase,
ffsdrv_test_write_halfword,
ffsdrv_test_write,
ffsdrv_null_write_end,
ffsdrv_null_erase_suspend,
ffsdrv_null_erase_resume
};
#endif
#if (BOARD == 34)
const struct ffsdrv_s ffsdrv_test = {
ffsdrv_null_init,
ffsdrv_ram_erase,
ffsdrv_ram_write_halfword,
ffsdrv_ram_write,
ffsdrv_void_write_end,
ffsdrv_void_erase_suspend,
ffsdrv_void_erase_resume
};
#endif
// Note: This function is designed for little-endian memory addressing!
void ffsdrv_write_byte(void *dst, uint8 value)
{
uint16 halfword;
tw(tr(TR_FUNC, TrDrvWrite, "ffsdrv_write_byte(0x%05x, 0x%x)\n",
(int) (addr2offset(dst)), value));
ttw(str(TTrDrvWrite, "wb" NL));
if ((int) dst & 1)
halfword = (value << 8) | *((uint8 *) dst - 1);
else
halfword = (*((uint8 *) dst + 1) << 8) | (value);
ffsdrv.write_halfword((uint16 *) ((int) dst & ~1), halfword);
}
extern uint16 ffs_flash_manufact;
extern uint16 ffs_flash_device;
effs_t ffsdrv_init(void)
{
const struct ffsdrv_s *p;
const struct flash_info_s *flash = &flash_info[0];
int error;
#if (BOARD == 34)
// Initialize dummy flash with default values
dev.state = DEV_READ;
dev.binfo = (struct block_info_s *) flash->binfo;
dev.base = (char *) flash->base;
dev.manufact = flash->manufact;
dev.device = flash->device;
dev.numblocks = flash->numblocks;
dev.atomlog2 = FFS_ATOM_LOG2;
dev.atomsize = 1 << dev.atomlog2;
dev.atomnotmask = dev.atomsize - 1;
dev.driver = flash->driver;
// We assume that ALL blocks are of equal size
dev.blocksize_ld = dev.binfo[0].size_ld;
dev.blocksize = (1 << dev.blocksize_ld);
// Supply structure pointer for ffs write/read functions
p = &ffsdrv_test;
// Bind the driver functions
ffsdrv.init = p->init;
ffsdrv.erase = p->erase;
ffsdrv.write_halfword = p->write_halfword;
ffsdrv.write = p->write;
ffsdrv.write_end = p->write_end;
ffsdrv.erase_suspend = p->erase_suspend;
ffsdrv.erase_resume = p->erase_resume;
return EFFS_OK;
#else
tw(tr(TR_BEGIN, TrDrvInit, "drv_init() {\n"));
ttw(str(TTrDrvOther, "ffsdrv_init() {" NL));
dev.state = DEV_READ;
dev.binfo = 0;
dev.base = 0;
dev.numblocks = 0;
// If ffs_flash_device is zero, detect device automatically by copying
// the detect function into RAM and execute it from there...
if (ffs_flash_manufact == 0 && ffs_flash_device == 0)
{
#if (TARGET == 1)
char detect_code[80];
typedef (*pf_t)(uint16 *, uint16 *);
pf_t myfp;
ffsdrv_device_id_read_copy_to_ram((uint16 *) detect_code,
sizeof(detect_code));
// Combine bit 0 of the thumb mode function pointer with the address
// of the code in RAM. Then call the detect function in RAM.
myfp = (pf_t) (((int) &ffsdrv_device_id_read & 1) | (int) detect_code);
(*myfp)(&dev.manufact, &dev.device);
// This code does not work but it is unknown as to why not.
// ((pf_t)detect_code)(&dev.manufact, &dev.device);
#endif
}
else {
dev.manufact = ffs_flash_manufact;
dev.device = ffs_flash_device;
}
tw(tr(TR_FUNC, TrDrvInit, "TARGET = %d\n", TARGET));
tw(tr(TR_FUNC, TrDrvInit, "Looking up device (0x%2x,0x%4x): ",
dev.manufact, dev.device));
while (flash->manufact) {
tw(tr(TR_NULL, TrDrvInit, "(0x%02x,0x%04x) ",
flash->manufact, flash->device));
if (dev.manufact == flash->manufact && dev.device == flash->device) {
tw(tr(TR_NULL, TrDrvInit, "FOUND "));
break;
}
flash++;
}
tw(tr(TR_NULL, TrDrvInit, "\n"));
if (flash->manufact == 0) {
tw(tr(TR_END, TrDrvInit, "} (%d)\n", EFFS_NODEVICE));
return EFFS_NODEVICE;
}
dev.binfo = (struct block_info_s *) flash->binfo;
dev.base = (char *) flash->base;
dev.numblocks = flash->numblocks;
dev.driver = flash->driver;
// We assume that ALL blocks are of equal size
dev.blocksize_ld = dev.binfo[0].size_ld;
dev.blocksize = (1 << dev.blocksize_ld);
dev.atomlog2 = FFS_ATOM_LOG2;
dev.atomsize = 1 << dev.atomlog2;
dev.atomnotmask = dev.atomsize - 1;
#if (TARGET == 0)
if (dev.manufact == MANUFACT_TEST)
dev.base = ffsdrv_test_create();
p = &ffsdrv_test;
#else // (TARGET == 1)
// Initialize hardware independent driver functions array
switch (dev.driver) {
case FFS_DRIVER_AMD: p = &ffsdrv_amd; break;
case FFS_DRIVER_AMD_SB: p = &ffsdrv_amd_sb; break;
case FFS_DRIVER_SST: p = &ffsdrv_sst; break;
case FFS_DRIVER_SST_SB: p = &ffsdrv_sst_sb; break;
case FFS_DRIVER_INTEL: p = &ffsdrv_intel; break;
case FFS_DRIVER_INTEL_SB: p = &ffsdrv_intel_sb; break;
case FFS_DRIVER_AMD_PSEUDO_SB: p = &ffsdrv_amd_pseudo_sb; break;
default: p = &ffsdrv_null; break;
}
#endif // (TARGET == 0)
// Bind the driver functions
ffsdrv.init = p->init;
ffsdrv.erase = p->erase;
ffsdrv.write_halfword = p->write_halfword;
ffsdrv.write = p->write;
ffsdrv.write_end = p->write_end;
ffsdrv.erase_suspend = p->erase_suspend;
ffsdrv.erase_resume = p->erase_resume;
// Copy single bank driver code to RAM (and possibly re-bind some of the
// driver functions)
error = ffsdrv_driver_copy_to_ram(dev.driver);
// FIXME: ffsdrv_intel_sb_init() does NOT work. Target freezes!
if (error >= 0)
error = ffsdrv.init();
tw(tr(TR_FUNC, TrDrvInit, "dev.binfo = 0x%x\n", (unsigned int) dev.binfo));
tw(tr(TR_FUNC, TrDrvInit, "dev.base = 0x%x\n", (unsigned int) dev.base));
tw(tr(TR_FUNC, TrDrvInit, "dev.numblocks = %d\n", dev.numblocks));
tw(tr(TR_FUNC, TrDrvInit, "dev.blocksize = %d\n", dev.blocksize));
tw(tr(TR_FUNC, TrDrvInit, "dev.atomlog2/atomsize/atomnotmask = %d/%d/%x\n",
dev.atomlog2, dev.atomsize, dev.atomnotmask));
tw(tr(TR_END, TrDrvInit, "} %d\n", error));
ttw(ttr(TTrDrvOther, "} %d" NL, error));
return error;
#endif // BOARD = 34
}
/******************************************************************************
* Interrupt Enable/Disable
******************************************************************************/
// IMPORTANT NOTE! Apparently, locating this ARM assembly code at the top of
// this file will make the compiler trash the A1 register between the calls
// of arm_int_disable and arm_int_enable() thus crashing the whole system.
// If the code is placed AFTER the usage of the functions, the compiler
// saves the A1 register. Strange but true.
// IMPORTANT NOTE! Apparently, another strange thing is that if the
// functions are declared static, they don't work!
// Executing code from RAM is NOT trivial when we need to jump between ROM
// (flash) and RAM memory. The ARM only supports 26-bit relative branch
// offsets. This is the reason why we have a local copy of the
// arm_int_disable/enable() functions in this file plus each of the
// single-bank drivers.
#if (TARGET == 1)
// Note that we use our own interrupt disable/enable function because
// Nucleus allegedly should have a bug in its implementation for this.
uint32 int_disable(void)
{
asm(" .state16");
asm(" mov A1, #0xC0");
asm(" ldr A2, tct_disable");
asm(" bx A2 ");
asm("tct_disable .field _TCT_Control_Interrupts+0,32");
asm(" .global _TCT_Control_Interrupts");
}
void int_enable(uint32 cpsr)
{
asm(" .state16");
asm(" ldr A2, tct_enable");
asm(" bx A2 ");
asm("tct_enable .field _TCT_Control_Interrupts+0,32");
asm(" .global _TCT_Control_Interrupts");
}
#else
uint32 int_disable(void) { return 0; }
void int_enable(uint32 tmp) {}
#endif // (TARGET == 1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -