FreeCalypso > hg > fc-tourmaline
diff src/cs/drivers/drv_app/ffs/board/intelsbdrv.c @ 0:4e78acac3d88
src/{condat,cs,gpf,nucleus}: import from Selenite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 06:23:26 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/drivers/drv_app/ffs/board/intelsbdrv.c Fri Oct 16 06:23:26 2020 +0000 @@ -0,0 +1,284 @@ +/****************************************************************************** + * 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: intelsbdrv.c 1.13 Thu, 08 Jan 2004 15:05:23 +0100 tsj $ + * + ******************************************************************************/ + +#include "ffs.cfg" + +#include "ffs/ffs.h" +#include "ffs/board/drv.h" +#include "ffs/board/ffstrace.h" + + +#define INTEL_UNLOCK_SLOW 1 + + +#undef tlw +#define tlw(contents) +#undef ttw +#define ttw(contents) + +// Status bits for Intel flash memory devices +#define INTEL_STATE_MACHINE_DONE (1<<7) +#define FLASH_READ(addr) (*(volatile uint16 *) (addr)) +#define FLASH_WRITE(addr, data) (*(volatile uint16 *) (addr)) = data + +#ifdef __GNUC__ +asm(".globl ffsdrv_ram_intel_begin"); +asm("ffsdrv_ram_intel_begin:"); +#else +asm(" .label _ffsdrv_ram_intel_begin"); +asm(" .def _ffsdrv_ram_intel_begin"); +#endif + +uint32 intel_int_disable(void); +void intel_int_enable(uint32 tmp); + +/****************************************************************************** + * INTEL Single Bank Driver Functions + ******************************************************************************/ +// Actually we should have disabled and enable the interrupts in this +// function, but when the interrupt functions are used Target don't run! +// Anyway, currently the interrupts are already disabled at this point thus +// it does not cause any problems. +int ffsdrv_ram_intel_sb_init(void) +{ + uint32 cpsr, i; + volatile char *addr; + uint16 status; + + for (i = 0; i < dev.numblocks; i++) + { + addr = block2addr(i); + + *addr = 0x50; // Intel Clear Status Register + *addr = 0xFF; // Intel read array + + *addr = 0x60; // Intel Config Setup + *addr = 0xD0; // Intel Unlock Block + + // Wait for unlock to finish + do { + status = FLASH_READ(addr); + } while (!(status & INTEL_STATE_MACHINE_DONE)); + + *addr = 0x70; // Intel Read Status Register + status = FLASH_READ(addr); + + // Is there an erase suspended? + if ((status & 0x40) != 0) { + *addr = 0xD0; // Intel erase resume + + *addr = 0x70; // Intel Read Status Register + // wait for erase to finish + do { + status = FLASH_READ(addr); + } while (!(status & INTEL_STATE_MACHINE_DONE)); + } + + *addr = 0xFF; // Intel Read Array + } + + return 0; +} + +void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value) +{ + 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 = intel_int_disable(); + tlw(led_on(LED_WRITE)); + +#if (INTEL_UNLOCK_SLOW == 1) + *addr = 0x60; // Intel Config Setup + *addr = 0xD0; // Intel Unlock Block +#endif + + *addr = 0x50; // Intel Clear Status Register + *addr = 0x40; // Intel program byte/word + *addr = value; + while ((*addr & 0x80) == 0) + ; + *addr = 0xFF; // Intel read array + tlw(led_off(LED_WRITE)); + intel_int_enable(cpsr); +} + +void ffsdrv_ram_intel_sb_erase(uint8 block) +{ + volatile char *addr; + uint32 cpsr; + uint16 poll; + + ttw(ttr(TTrDrvEra, "e(%d)" NL, block)); + + addr = block2addr(block); + + cpsr = intel_int_disable(); + tlw(led_on(LED_ERASE)); + +#if (INTEL_UNLOCK_SLOW == 1) + *addr = 0x60; // Intel Config Setup + *addr = 0xD0; // Intel Unlock Block +#endif + + *addr = 0x50; // Intel Clear Status Register + *addr = 0x20; // Intel Erase Setup + *addr = 0xD0; // Intel Erase Confirm + *addr = 0x70; // Intel Read Status Register + + // 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; // Intel Erase Suspend + *addr = 0x70; // Intel Read Status Register + while (((poll = *addr) & 0x80) == 0) + ; + + // If erase is complete, exit immediately + if ((poll & 0x40) == 0) + break; + + *addr = 0xFF; // Intel read array + + tlw(led_off(LED_ERASE_SUSPEND)); + intel_int_enable(cpsr); + + // Other interrupts and tasks run now... + + cpsr = intel_int_disable(); + tlw(led_on(LED_ERASE_SUSPEND)); + + *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") + *addr = 0x70; // Intel Read Status Register + + tlw(led_off(LED_ERASE_SUSPEND)); + } + } + *addr = 0xFF; // Intel read array + + tlw(led_on(LED_ERASE)); + tlw(led_off(LED_ERASE)); + intel_int_enable(cpsr); +} + +// TODO: remove below function, not in use anymore. +void ffsdrv_ram_intel_erase(uint8 block) +{ + uint32 cpsr; + uint16 status; + + ttw(ttr(TTrDrvErase, "e(%d)" NL, block)); + tlw(led_on(LED_ERASE)); + + dev.addr = (uint16 *) block2addr(block); + + cpsr = intel_int_disable(); + dev.state = DEV_ERASE; + + *dev.addr = 0x60; // Intel Config setup + *dev.addr = 0xD0; // Intel Unlock block + + *dev.addr = 0x50; // Intel clear status register (not really necessary) + *dev.addr = 0x20; // Intel erase setup + *dev.addr = 0xD0; // Intel erase confirm + + intel_int_enable(cpsr); + + while ((*dev.addr & 0x80) == 0) + ; + + *dev.addr = 0xFF; // Intel read array + dev.state = DEV_READ; + tlw(led_off(LED_WRITE)); +} + + +/****************************************************************************** + * Interrupt Enable/Disable + ******************************************************************************/ + +#ifdef __GNUC__ +#define NOINLINE __attribute__ ((noinline)) +#else +#define NOINLINE +#endif + +uint32 NOINLINE intel_int_disable(void) +{ +#ifdef __GNUC__ + asm(" .code 16"); +#else + asm(" .state16"); +#endif + asm(" mov A1, #0xC0"); + asm(" ldr A2, tct_intel_disable"); + asm(" bx A2 "); + +#ifdef __GNUC__ + asm(".balign 4"); + asm("tct_intel_disable:"); + asm(" .word TCT_Control_Interrupts"); +#else + asm("tct_intel_disable .field _TCT_Control_Interrupts+0,32"); + asm(" .global _TCT_Control_Interrupts"); +#endif +} + +void NOINLINE intel_int_enable(uint32 cpsr) +{ +#ifdef __GNUC__ + asm(" .code 16"); +#else + asm(" .state16"); +#endif + asm(" ldr A2, tct_intel_enable"); + asm(" bx A2 "); + +#ifdef __GNUC__ + asm(".balign 4"); + asm("tct_intel_enable:"); + asm(" .word TCT_Control_Interrupts"); +#else + asm("tct_intel_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_intel_end"); +asm("ffsdrv_ram_intel_end:"); +#else +asm(" .state32"); +asm(" .label _ffsdrv_ram_intel_end"); +asm(" .def _ffsdrv_ram_intel_end"); +#endif