FreeCalypso > hg > fc-tourmaline
view src/cs/drivers/drv_app/ffs/board/amdsbdrv.c @ 294:e17bdedfbf2b
VIBR SWE initial implementation
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 27 Mar 2022 08:46:10 +0000 |
parents | 4e78acac3d88 |
children |
line wrap: on
line source
/****************************************************************************** * 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) #ifdef __GNUC__ asm(".globl ffsdrv_ram_amd_begin"); asm("ffsdrv_ram_amd_begin:"); #else asm(" .label _ffsdrv_ram_amd_begin"); asm(" .def _ffsdrv_ram_amd_begin"); #endif // 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 ******************************************************************************/ #ifdef __GNUC__ #define NOINLINE __attribute__ ((noinline)) #else #define NOINLINE #endif uint32 NOINLINE amd_int_disable(void) { #ifdef __GNUC__ asm(" .code 16"); #else asm(" .state16"); #endif asm(" mov A1, #0xC0"); asm(" ldr A2, tct_amd_disable"); asm(" bx A2 "); #ifdef __GNUC__ asm(".balign 4"); asm("tct_amd_disable:"); asm(" .word TCT_Control_Interrupts"); #else asm("tct_amd_disable .field _TCT_Control_Interrupts+0,32"); asm(" .global _TCT_Control_Interrupts"); #endif } void NOINLINE amd_int_enable(uint32 cpsr) { #ifdef __GNUC__ asm(" .code 16"); #else asm(" .state16"); #endif asm(" ldr A2, tct_amd_enable"); asm(" bx A2 "); #ifdef __GNUC__ asm(".balign 4"); asm("tct_amd_enable:"); asm(" .word TCT_Control_Interrupts"); #else asm("tct_amd_enable .field _TCT_Control_Interrupts+0,32"); asm(" .global _TCT_Control_Interrupts"); #endif } // Even though we have this end label, we cannot determine the number of // constant/PC-relative data following the code! #ifdef __GNUC__ asm(".globl ffsdrv_ram_amd_end"); asm("ffsdrv_ram_amd_end:"); #else asm(" .state32"); asm(" .label _ffsdrv_ram_amd_end"); asm(" .def _ffsdrv_ram_amd_end"); #endif