altos: Add driver for STM internal flash
authorKeith Packard <keithp@keithp.com>
Mon, 30 Jul 2012 02:48:08 +0000 (19:48 -0700)
committerKeith Packard <keithp@keithp.com>
Mon, 30 Jul 2012 02:48:08 +0000 (19:48 -0700)
Signed-off-by: Keith Packard <keithp@keithp.com>
src/stm/ao_eeprom_stm.c [new file with mode: 0644]
src/stm/stm32l.h

diff --git a/src/stm/ao_eeprom_stm.c b/src/stm/ao_eeprom_stm.c
new file mode 100644 (file)
index 0000000..1e51b41
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_storage.h>
+
+/* Total bytes of available storage */
+ao_pos_t       ao_storage_total = 4096;
+
+/* Block size - device is erased in these units. */
+ao_pos_t       ao_storage_block = 1024;
+
+/* Byte offset of config block. Will be ao_storage_block bytes long */
+ao_pos_t       ao_storage_config = 0;
+
+/* Storage unit size - device reads and writes must be within blocks of this size. */
+uint16_t       ao_storage_unit = 1024;
+
+/* Location of eeprom in address space */
+#define stm_eeprom     ((uint8_t *) 0x08080000)
+
+/*
+ * The internal flash chip is arranged in 8 byte sectors; the
+ * chip cannot erase in units smaller than that.
+ *
+ * Writing happens in units of 2 bytes and
+ * can only change bits from 1 to 0. So, you can rewrite
+ * the same contents, or append to an existing page easily enough
+ */
+
+/*
+ * Erase the specified sector
+ */
+uint8_t
+ao_storage_erase(ao_pos_t pos) __reentrant
+{
+       /* Not necessary */
+       return 1;
+}
+
+static void
+ao_intflash_unlock(void)
+{
+       /* Unlock Data EEPROM and FLASH_PECR register */
+       stm_flash.pekeyr = STM_FLASH_PEKEYR_PEKEY1;
+       stm_flash.pekeyr = STM_FLASH_PEKEYR_PEKEY2;
+
+       /* Configure the FTDW bit (FLASH_PECR[8]) to execute
+        * word write, whatever the previous value of the word
+        * being written to
+        */
+       stm_flash.pecr = ((0 << STM_FLASH_PECR_OBL_LAUNCH) |
+                         (0 << STM_FLASH_PECR_ERRIE) |
+                         (0 << STM_FLASH_PECR_EOPIE) |
+                         (0 << STM_FLASH_PECR_FPRG) |
+                         (0 << STM_FLASH_PECR_ERASE) |
+                         (0 << STM_FLASH_PECR_FTDW) |
+                         (1 << STM_FLASH_PECR_DATA) |
+                         (0 << STM_FLASH_PECR_PROG) |
+                         (0 << STM_FLASH_PECR_OPTLOCK) |
+                         (0 << STM_FLASH_PECR_PRGLOCK) |
+                         (0 << STM_FLASH_PECR_PELOCK));
+}
+
+static void
+ao_intflash_lock(void)
+{
+       stm_flash.pecr |= (1 << STM_FLASH_PECR_PELOCK);
+}
+
+static void
+ao_intflash_write32(uint16_t pos, uint32_t w)
+{
+       uint32_t        *addr;
+
+       addr = (uint32_t *) (stm_eeprom + pos);
+
+       /* Write a word to a valid address in the data EEPROM */
+       *addr = w;
+
+       /* Wait for the flash unit to go idle */
+       while (stm_flash.sr & (1 << STM_FLASH_SR_BSY))
+               ;
+}
+
+static void
+ao_intflash_write8(uint16_t pos, uint8_t d)
+{
+       uint32_t        w, *addr, mask;
+       uint8_t         shift;
+       
+       addr = (uint32_t *) (stm_eeprom + (pos & ~3));
+
+       /* Compute word to be written */
+       shift = (pos & 3) << 3;
+       mask = 0xff << shift;
+       w = (*addr & ~mask) | (d << shift);
+
+       ao_intflash_write32(pos & ~3, w);
+}
+
+static uint8_t
+ao_intflash_read(uint16_t pos)
+{
+       return stm_eeprom[pos];
+}
+
+/*
+ * Write to flash
+ */
+
+uint8_t
+ao_storage_device_write(ao_pos_t pos32, __xdata void *v, uint16_t len) __reentrant
+{
+       uint16_t pos = pos32;
+       __xdata uint8_t *d = v;
+
+       if (pos >= ao_storage_total || pos + len > ao_storage_total)
+               return 0;
+
+       ao_intflash_unlock();
+       while (len) {
+               if ((pos & 3) == 0 && len >= 4) {
+                       uint32_t        w;
+
+                       w = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
+                       ao_intflash_write32(pos, w);
+                       pos += 4;
+                       d += 4;
+                       len -= 4;
+               } else {
+                       ao_intflash_write8(pos, *d);
+                       pos += 1;
+                       d += 1;
+                       len -= 1;
+               }
+       }
+       ao_intflash_lock();
+
+       return 1;
+}
+
+/*
+ * Read from flash
+ */
+uint8_t
+ao_storage_device_read(ao_pos_t pos, __xdata void *v, uint16_t len) __reentrant
+{
+       uint8_t *d = v;
+       
+       if (pos >= ao_storage_total || pos + len > ao_storage_total)
+               return 0;
+       while (len--)
+               *d++ = ao_intflash_read(pos++);
+       return 1;
+}
+
+void
+ao_storage_flush(void) __reentrant
+{
+}
+
+void
+ao_storage_setup(void)
+{
+}
+
+void
+ao_storage_device_info(void) __reentrant
+{
+       printf ("Using internal flash\n");
+}
+
+void
+ao_storage_device_init(void)
+{
+}
index ff8dddffc2bb1cbb95947f5fb995a917020f0288..4d665e8beda9fcb55f937d17b3d8809907db1727 100644 (file)
@@ -281,6 +281,30 @@ extern struct stm_flash    stm_flash;
 #define STM_FLASH_ACR_PRFEN    (1)
 #define STM_FLASH_ACR_LATENCY  (0)
 
 #define STM_FLASH_ACR_PRFEN    (1)
 #define STM_FLASH_ACR_LATENCY  (0)
 
+#define STM_FLASH_PECR_OBL_LAUNCH      18
+#define STM_FLASH_PECR_ERRIE           17
+#define STM_FLASH_PECR_EOPIE           16
+#define STM_FLASH_PECR_FPRG            10
+#define STM_FLASH_PECR_ERASE           9
+#define STM_FLASH_PECR_FTDW            8
+#define STM_FLASH_PECR_DATA            4
+#define STM_FLASH_PECR_PROG            3
+#define STM_FLASH_PECR_OPTLOCK         2
+#define STM_FLASH_PECR_PRGLOCK         1
+#define STM_FLASH_PECR_PELOCK          0
+
+#define STM_FLASH_SR_OPTVERR           11
+#define STM_FLASH_SR_SIZERR            10
+#define STM_FLASH_SR_PGAERR            9
+#define STM_FLASH_SR_WRPERR            8
+#define STM_FLASH_SR_READY             3
+#define STM_FLASH_SR_ENDHV             2
+#define STM_FLASH_SR_EOP               1
+#define STM_FLASH_SR_BSY               0
+
+#define STM_FLASH_PEKEYR_PEKEY1        0x89ABCDEF
+#define STM_FLASH_PEKEYR_PEKEY2 0x02030405
+
 struct stm_rcc {
        vuint32_t       cr;
        vuint32_t       icscr;
 struct stm_rcc {
        vuint32_t       cr;
        vuint32_t       icscr;