diff gsm-fw/services/ffs/intelsbdrv.c @ 938:1db4da08b9b4

gsm-fw/services/ffs/intelsbdrv.c: initial import from TCS211 source
author Mychaela Falconia <falcon@ivan.Harhan.ORG>
date Sat, 31 Oct 2015 23:02:20 +0000
parents
children 62ca61292b77
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gsm-fw/services/ffs/intelsbdrv.c	Sat Oct 31 23:02:20 2015 +0000
@@ -0,0 +1,248 @@
+/******************************************************************************
+ * 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
+
+asm("        .label _ffsdrv_ram_intel_begin");
+asm("        .def   _ffsdrv_ram_intel_begin");
+
+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
+ ******************************************************************************/
+
+uint32 intel_int_disable(void)
+{
+    asm("        .state16");
+    asm("        mov       A1, #0xC0");
+    asm("        ldr       A2, tct_intel_disable");
+    asm("        bx        A2      ");
+
+    asm("tct_intel_disable 	.field     _TCT_Control_Interrupts+0,32");
+    asm("	                .global	   _TCT_Control_Interrupts");
+}
+
+void intel_int_enable(uint32 cpsr)
+{
+    asm("        .state16");
+    asm("        ldr       A2, tct_intel_enable");
+    asm("        bx        A2      ");
+
+    asm("tct_intel_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_intel_end");
+asm("        .def   _ffsdrv_ram_intel_end");