FreeCalypso > hg > fc-selenite
diff src/cs/drivers/drv_app/ffs/board/amdsbdrv.c @ 0:b6a5e36de839
src/cs: initial import from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 15 Jul 2018 04:39:26 +0000 |
parents | |
children | 559a8b3ef10b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/drivers/drv_app/ffs/board/amdsbdrv.c Sun Jul 15 04:39:26 2018 +0000 @@ -0,0 +1,164 @@ +/****************************************************************************** + * Flash File System (ffs) + * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com + * + * FFS AMD single bank low level flash driver RAM code + * + * $Id: amdsbdrv.c 1.5.1.3 Tue, 06 Jan 2004 10:57:45 +0100 tsj $ + * + ******************************************************************************/ + +#include "ffs.cfg" + +#include "ffs/ffs.h" +#include "ffs/board/drv.h" +#include "ffs/board/ffstrace.h" + + +// Due to long branches, we disable all tracing and led function calls. +#undef tlw +#define tlw(contents) +#undef ttw +#define ttw(contents) + + +asm(" .label _ffsdrv_ram_amd_begin"); +asm(" .def _ffsdrv_ram_amd_begin"); + + +// IMPORTANT! Apparently, placing the int_disable/enable() function code +// here instead of at the bottom of the file, makes the code crash or +// freeze. Reason is as of yet unknown. + +uint32 amd_int_disable(void); +void amd_int_enable(uint32 tmp); + + +/****************************************************************************** + * AMD Single Bank Driver Functions + ******************************************************************************/ + +void ffsdrv_ram_amd_sb_write_halfword(volatile uint16 *addr, uint16 value) +{ + volatile char *flash = dev.base; + uint32 cpsr; + + ttw(ttr(TTrDrv, "wh(%x,%x)" NL, addr, value)); + + if (~*addr & value) { + ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value)); + return; + } + + cpsr = amd_int_disable(); + tlw(led_on(LED_WRITE)); + + flash[0xAAAA] = 0xAA; // AMD unlock cycle 1 + flash[0x5555] = 0x55; // AMD unlock cycle 2 + flash[0xAAAA] = 0xA0; + *addr = value; + + while ((*addr ^ value) & 0x80) + ; + + tlw(led_off(LED_WRITE)); + amd_int_enable(cpsr); +} + +// This VERY simple way of erase suspension only works because we run under +// a pre-emptive operating system, so whenever an interrupt occurs, another +// task takes the CPU, and at the end of the interrupt, FFS gets the CPU +// again. +void ffsdrv_ram_amd_sb_erase(uint8 block) +{ + volatile char *flash = dev.base; + volatile char *addr; + uint32 cpsr; + uint16 flashpoll; + + addr = block2addr(block); + + ttw(ttr(TTrDrvEra, "e(%d)" NL, block)); + + cpsr = amd_int_disable(); + tlw(led_on(LED_ERASE)); + + flash[0xAAAA] = 0xAA; // AMD unlock cycle 1 + flash[0x5555] = 0x55; // AMD unlock cycle 2 + flash[0xAAAA] = 0x80; + flash[0xAAAA] = 0xAA; // AMD unlock cycle 1 + flash[0x5555] = 0x55; // AMD unlock cycle 2 + *addr = 0x30; // AMD erase sector command + + // Wait for erase to finish. + while ((*addr & 0x80) == 0) { + tlw(led_toggle(LED_ERASE)); + // Poll interrupts, taking interrupt mask into account. + if (INT_REQUESTED) + { + // 1. suspend erase + // 2. enable interrupts + // .. now the interrupt code executes + // 3. disable interrupts + // 4. resume erase + + tlw(led_on(LED_ERASE_SUSPEND)); + *addr = 0xB0; + + // wait for erase suspend to finish + while ((*addr & 0x80) == 0) + ; + + tlw(led_off(LED_ERASE_SUSPEND)); + amd_int_enable(cpsr); + + // Other interrupts and tasks run now... + + cpsr = amd_int_disable(); + tlw(led_on(LED_ERASE_SUSPEND)); + + // Before resuming erase we must? check if the erase is really + // suspended or if it did finish + flashpoll = *addr; + *addr = 0x30; + + tlw(led_off(LED_ERASE_SUSPEND)); + } + } + + tlw(led_on(LED_ERASE)); + tlw(led_off(LED_ERASE)); + amd_int_enable(cpsr); +} + + +/****************************************************************************** + * Interrupt Enable/Disable + ******************************************************************************/ + +uint32 amd_int_disable(void) +{ + asm(" .state16"); + asm(" mov A1, #0xC0"); + asm(" ldr A2, tct_amd_disable"); + asm(" bx A2 "); + + asm("tct_amd_disable .field _TCT_Control_Interrupts+0,32"); + asm(" .global _TCT_Control_Interrupts"); +} + +void amd_int_enable(uint32 cpsr) +{ + asm(" .state16"); + asm(" ldr A2, tct_amd_enable"); + asm(" bx A2 "); + + asm("tct_amd_enable .field _TCT_Control_Interrupts+0,32"); + asm(" .global _TCT_Control_Interrupts"); +} + +// Even though we have this end label, we cannot determine the number of +// constant/PC-relative data following the code! +asm(" .state32"); +asm(" .label _ffsdrv_ram_amd_end"); +asm(" .def _ffsdrv_ram_amd_end");