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");