diff gsm-fw/services/ffs/drv.c @ 209:6f4a12b4582f

gsm-fw FFS: starting to integrate C code
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Thu, 26 Dec 2013 03:59:59 +0000
parents
children fee45482aa2a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gsm-fw/services/ffs/drv.c	Thu Dec 26 03:59:59 2013 +0000
@@ -0,0 +1,423 @@
+/******************************************************************************
+ * Flash File System (ffs)
+ * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
+ *
+ * ffs low level flash driver
+ *
+ * $Id: drv.c 1.30.1.6.1.51.1.1.1.13.1.11 Tue, 06 Jan 2004 14:36:52 +0100 tsj $
+ *
+ ******************************************************************************/
+
+#include "../../include/config.h"
+#include "ffs.h"
+#include "drv.h"
+#include "ffstrace.h"
+#include "intctl.h"
+#include "ramffs.h"
+#include <string.h>
+
+
+/******************************************************************************
+ * Macros
+ ******************************************************************************/
+
+#define addr2offset(address) ( (int) (address) - (int) dev.base )
+
+
+/******************************************************************************
+ * Generic Driver Functions
+ ******************************************************************************/
+
+// 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);
+}
+
+void ffsdrv_generic_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.write_halfword((uint16 *) mydst,
+                                  mysrc[0] | (mysrc[1] << 8));
+            size -= 2;
+            mysrc += 2;
+            mydst += 2;
+        }
+        if (size == 1)
+            ffsdrv_write_byte(mydst++, *mysrc++);
+    }
+}
+
+/******************************************************************************
+ * Dummy 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));
+}
+
+/*
+ * FreeCalypso change from TI: we only compile one flash "driver" type
+ * based on the build configuration.
+ */
+
+#if FFS_IN_RAM
+
+/******************************************************************************
+ * RAM Family Functions
+ ******************************************************************************/
+
+struct block_info_s ramffs_block_info[RAMFFS_NBLOCKS];
+
+int ffsdrv_ram_init(void)
+{
+    unsigned i;
+    uint32 offset;
+
+    ttw(ttr(TTrDrvOther, "ffsdrv_ram_init()" NL));
+    memset(_RAMFFS_area, 0xFF, RAMFFS_TOTAL_SIZE);
+    offset = 0;
+    for (i = 0; i < RAMFFS_NBLOCKS; i++) {
+	ramffs_block_info[i].offset = offset;
+	ramffs_block_info[i].size_ld = RAMFFS_BLKSIZE_LOG2;
+	offset += RAMFFS_BLKSIZE_BYTES;
+    }
+    return 0;
+}
+
+void ffsdrv_ram_write_halfword(volatile uint16 *dst, uint16 value)
+{
+  *dst = value;
+}
+
+#if 0
+/* duplicates ffsdrv_generic_write */
+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++);
+    }
+}
+#endif
+
+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;
+    }
+}
+
+const struct ffsdrv_s ffsdrv = {
+    ffsdrv_ram_init,
+    ffsdrv_ram_erase,
+    ffsdrv_ram_write_halfword,
+    ffsdrv_generic_write,
+    ffsdrv_null_write_end,
+    ffsdrv_null_erase_suspend,
+    ffsdrv_null_erase_resume
+};
+
+#elif CONFIG_FLASH_WRITE
+
+/******************************************************************************
+ * AMD Dual/Multi Bank Driver Functions
+ ******************************************************************************/
+
+// All erase and write operations are performed atomically (interrupts
+// disabled). Otherwise we cannot trust the value of dev.state and we cannot
+// determine exactly how many of the command words have already been
+// written.
+
+// in ffs_end() when we resume an erasure that was previously suspended, how
+// does that affect multiple tasks doing that simultaneously?
+
+void ffsdrv_amd_write_end(void);
+void ffsdrv_amd_erase_end(void);
+
+void ffsdrv_amd_write_halfword(volatile uint16 *addr, uint16 value)
+{
+    volatile char *flash = dev.base;
+    uint32 cpsr;
+
+    tlw(led_on(LED_WRITE));
+    ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value));
+
+    dev.addr = addr;
+    dev.data = value;
+
+    if (~*addr & value) {
+        ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value));
+        return;
+    }
+
+    cpsr = int_disable();
+    tlw(led_toggle(LED_WRITE_SUSPEND));
+    dev.state = DEV_WRITE;
+    flash[0xAAAA] = 0xAA; // unlock cycle 1
+    flash[0x5555] = 0x55; // unlock cycle 2
+    flash[0xAAAA] = 0xA0;
+    *addr         = value;
+    int_enable(cpsr);
+    tlw(led_toggle(LED_WRITE_SUSPEND));
+
+    ffsdrv_amd_write_end();
+}
+
+#if 0
+/* duplicates ffsdrv_generic_write */
+void ffsdrv_amd_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_amd_write_halfword((uint16 *) mydst,
+                                      mysrc[0] | (mysrc[1] << 8));
+            size -= 2;
+            mysrc += 2;
+            mydst += 2;
+        }
+        if (size == 1)
+            ffsdrv_write_byte(mydst++, *mysrc++);
+    }
+}
+#endif
+
+void ffsdrv_amd_write_end(void)
+{
+    while ((*dev.addr ^ dev.data) & 0x80)
+        tlw(led_toggle(LED_WRITE_SUSPEND));
+
+    dev.state = DEV_READ;
+
+    tlw(led_off(LED_WRITE));
+}
+
+void ffsdrv_amd_erase(uint8 block)
+{
+    volatile char *flash = dev.base;
+    uint32 cpsr;
+
+    tlw(led_on(LED_ERASE));
+    ttw(ttr(TTrDrvErase, "e(%d)" NL, block));
+
+    dev.addr = (uint16 *) block2addr(block);
+
+    cpsr = int_disable();
+    dev.state = DEV_ERASE;
+    flash[0xAAAA] = 0xAA; // unlock cycle 1
+    flash[0x5555] = 0x55; // unlock cycle 2
+    flash[0xAAAA] = 0x80; 
+    flash[0xAAAA] = 0xAA; // unlock cycle 1
+    flash[0x5555] = 0x55; // unlock cycle 2
+    *dev.addr = 0x30; // AMD erase sector command
+    int_enable(cpsr);
+
+    ffsdrv_amd_erase_end();
+}
+
+void ffsdrv_amd_erase_end(void)
+{
+    while ((*dev.addr & 0x80) == 0)
+        ;
+
+    dev.state = DEV_READ;
+
+    tlw(led_off(LED_ERASE));
+}
+
+void ffsdrv_amd_erase_suspend(void)
+{
+    uint32 cpsr;
+
+    tlw(led_on(LED_ERASE_SUSPEND));
+    ttw(str(TTrDrvErase, "es" NL));
+
+    // if erase has finished then all is ok
+    if (*dev.addr & 0x80) {
+        ffsdrv_amd_erase_end();
+        tlw(led_off(LED_ERASE_SUSPEND));
+        return;
+    }
+
+    // NOTEME: As there is no way to be absolutely certain that erase
+    // doesn't finish between last poll and the following erase suspend
+    // command, we assume that the erase suspend is safe even though the
+    // erase IS actually already finished.
+
+    cpsr = int_disable();
+    dev.state = DEV_ERASE_SUSPEND;
+    *dev.addr = 0xB0;
+
+    // Wait for erase suspend to finish
+    while ((*dev.addr & 0x80) == 0)
+        ;
+
+    int_enable(cpsr);
+}
+
+void ffsdrv_amd_erase_resume(void)
+{
+    uint32 cpsr;
+
+    ttw(str(TTrDrvErase, "er" NL));
+
+    // NOTEME: See note in erase_suspend()... We assume that the erase
+    // resume is safe even though the erase IS actually already finished.
+    cpsr = int_disable();
+    dev.state = DEV_ERASE;
+    *dev.addr = 0x30;
+    int_enable(cpsr);
+
+    tlw(led_off(LED_ERASE_SUSPEND));
+}
+
+const struct ffsdrv_s ffsdrv = {
+    ffsdrv_null_init,
+    ffsdrv_amd_erase,
+    ffsdrv_amd_write_halfword,
+    ffsdrv_generic_write,
+    ffsdrv_amd_write_end,
+    ffsdrv_amd_erase_suspend,
+    ffsdrv_amd_erase_resume
+};
+
+#else
+
+/*
+ * This part will get compiled if we have real FFS (FFS_IN_RAM=0),
+ * but not allowed to write to flash (CONFIG_FLASH_WRITE=0).
+ */
+
+const struct ffsdrv_s ffsdrv = {
+    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
+};
+
+#endif
+
+
+/******************************************************************************
+ * Initialization
+ *
+ * Significantly simplified in FreeCalypso.
+ *
+ ******************************************************************************/
+
+effs_t ffsdrv_init(void)
+{
+    int error;
+
+    tw(tr(TR_BEGIN, TrDrvInit, "drv_init() {\n"));
+    ttw(str(TTrDrvOther, "ffsdrv_init() {" NL));
+
+    dev.state = DEV_READ;
+    dev.atomlog2 = FFS_ATOM_LOG2;
+    dev.atomsize = 1 << dev.atomlog2;
+    dev.atomnotmask = dev.atomsize - 1;
+
+    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;
+}