]> git.friedersdorff.com Git - max/tmk_keyboard.git/commitdiff
Add eeprom support for chibios/kinetis.
authorflabbergast <s3+flabbergast@sdfeu.org>
Mon, 12 Oct 2015 08:47:27 +0000 (09:47 +0100)
committerflabbergast <s3+flabbergast@sdfeu.org>
Mon, 12 Oct 2015 08:47:27 +0000 (09:47 +0100)
tmk_core/common/chibios/eeconfig.c [new file with mode: 0644]
tmk_core/tool/chibios/common.mk

diff --git a/tmk_core/common/chibios/eeconfig.c b/tmk_core/common/chibios/eeconfig.c
new file mode 100644 (file)
index 0000000..f9e2718
--- /dev/null
@@ -0,0 +1,551 @@
+#include "ch.h"
+#include "hal.h"
+
+#include "eeconfig.h"
+
+/*************************************/
+/*          Hardware backend         */
+/*                                   */
+/*    Code from PJRC/Teensyduino     */
+/*************************************/
+
+/* Teensyduino Core Library
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2013 PJRC.COM, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be 
+ * included in all copies or substantial portions of the Software.
+ *
+ * 2. If the Software is incorporated into a build system that allows 
+ * selection among a list of target devices, then similar target
+ * devices manufactured by PJRC.COM must be included in the list of
+ * target devices and selectable in the same manner.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#if defined(K20x) /* chip selection */
+/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
+
+// The EEPROM is really RAM with a hardware-based backup system to
+// flash memory.  Selecting a smaller size EEPROM allows more wear
+// leveling, for higher write endurance.  If you edit this file,
+// set this to the smallest size your application can use.  Also,
+// due to Freescale's implementation, writing 16 or 32 bit words
+// (aligned to 2 or 4 byte boundaries) has twice the endurance
+// compared to writing 8 bit bytes.
+//
+#define EEPROM_SIZE 32
+
+// Writing unaligned 16 or 32 bit data is handled automatically when
+// this is defined, but at a cost of extra code size.  Without this,
+// any unaligned write will cause a hard fault exception!  If you're
+// absolutely sure all 16 and 32 bit writes will be aligned, you can
+// remove the extra unnecessary code.
+//
+#define HANDLE_UNALIGNED_WRITES
+
+// Minimum EEPROM Endurance
+// ------------------------
+#if (EEPROM_SIZE == 2048)      // 35000 writes/byte or 70000 writes/word
+  #define EEESIZE 0x33
+#elif (EEPROM_SIZE == 1024)    // 75000 writes/byte or 150000 writes/word
+  #define EEESIZE 0x34
+#elif (EEPROM_SIZE == 512)     // 155000 writes/byte or 310000 writes/word
+  #define EEESIZE 0x35
+#elif (EEPROM_SIZE == 256)     // 315000 writes/byte or 630000 writes/word
+  #define EEESIZE 0x36
+#elif (EEPROM_SIZE == 128)     // 635000 writes/byte or 1270000 writes/word
+  #define EEESIZE 0x37
+#elif (EEPROM_SIZE == 64)      // 1275000 writes/byte or 2550000 writes/word
+  #define EEESIZE 0x38
+#elif (EEPROM_SIZE == 32)      // 2555000 writes/byte or 5110000 writes/word
+  #define EEESIZE 0x39
+#endif
+
+void eeprom_initialize(void)
+{
+       uint32_t count=0;
+       uint16_t do_flash_cmd[] = {
+               0xf06f, 0x037f, 0x7003, 0x7803,
+               0xf013, 0x0f80, 0xd0fb, 0x4770};
+       uint8_t status;
+
+       if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
+               // FlexRAM is configured as traditional RAM
+               // We need to reconfigure for EEPROM usage
+               FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
+               FTFL->FCCOB4 = EEESIZE; // EEPROM Size
+               FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
+               __disable_irq();
+               // do_flash_cmd() must execute from RAM.  Luckily the C syntax is simple...
+               (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
+               __enable_irq();
+               status = FTFL->FSTAT;
+               if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) {
+                       FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL));
+                       return; // error
+               }
+       }
+       // wait for eeprom to become ready (is this really necessary?)
+       while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+               if (++count > 20000) break;
+       }
+}
+
+#define FlexRAM ((uint8_t *)0x14000000)
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+       uint32_t offset = (uint32_t)addr;
+       if (offset >= EEPROM_SIZE) return 0;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       return FlexRAM[offset];
+}
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+       uint32_t offset = (uint32_t)addr;
+       if (offset >= EEPROM_SIZE-1) return 0;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       return *(uint16_t *)(&FlexRAM[offset]);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+       uint32_t offset = (uint32_t)addr;
+       if (offset >= EEPROM_SIZE-3) return 0;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       return *(uint32_t *)(&FlexRAM[offset]);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+       uint32_t offset = (uint32_t)addr;
+       uint8_t *dest = (uint8_t *)buf;
+       uint32_t end = offset + len;
+       
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       if (end > EEPROM_SIZE) end = EEPROM_SIZE;
+       while (offset < end) {
+               *dest++ = FlexRAM[offset++];
+       }
+}
+
+int eeprom_is_ready(void)
+{
+       return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
+}
+
+static void flexram_wait(void)
+{
+       while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+               // TODO: timeout
+       }
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t value)
+{
+       uint32_t offset = (uint32_t)addr;
+
+       if (offset >= EEPROM_SIZE) return;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       if (FlexRAM[offset] != value) {
+               FlexRAM[offset] = value;
+               flexram_wait();
+       }
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+       uint32_t offset = (uint32_t)addr;
+
+       if (offset >= EEPROM_SIZE-1) return;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+       if ((offset & 1) == 0) {
+#endif
+               if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+                       *(uint16_t *)(&FlexRAM[offset]) = value;
+                       flexram_wait();
+               }
+#ifdef HANDLE_UNALIGNED_WRITES
+       } else {
+               if (FlexRAM[offset] != value) {
+                       FlexRAM[offset] = value;
+                       flexram_wait();
+               }
+               if (FlexRAM[offset + 1] != (value >> 8)) {
+                       FlexRAM[offset + 1] = value >> 8;
+                       flexram_wait();
+               }
+       }
+#endif
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+       uint32_t offset = (uint32_t)addr;
+
+       if (offset >= EEPROM_SIZE-3) return;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+       switch (offset & 3) {
+       case 0:
+#endif
+               if (*(uint32_t *)(&FlexRAM[offset]) != value) {
+                       *(uint32_t *)(&FlexRAM[offset]) = value;
+                       flexram_wait();
+               }
+               return;
+#ifdef HANDLE_UNALIGNED_WRITES
+       case 2:
+               if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+                       *(uint16_t *)(&FlexRAM[offset]) = value;
+                       flexram_wait();
+               }
+               if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
+                       *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
+                       flexram_wait();
+               }
+               return;
+       default:
+               if (FlexRAM[offset] != value) {
+                       FlexRAM[offset] = value;
+                       flexram_wait();
+               }
+               if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
+                       *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
+                       flexram_wait();
+               }
+               if (FlexRAM[offset + 3] != (value >> 24)) {
+                       FlexRAM[offset + 3] = value >> 24;
+                       flexram_wait();
+               }
+       }
+#endif
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+       uint32_t offset = (uint32_t)addr;
+       const uint8_t *src = (const uint8_t *)buf;
+
+       if (offset >= EEPROM_SIZE) return;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
+       if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
+       while (len > 0) {
+               uint32_t lsb = offset & 3;
+               if (lsb == 0 && len >= 4) {
+                       // write aligned 32 bits
+                       uint32_t val32;
+                       val32 = *src++;
+                       val32 |= (*src++ << 8);
+                       val32 |= (*src++ << 16);
+                       val32 |= (*src++ << 24);
+                       if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
+                               *(uint32_t *)(&FlexRAM[offset]) = val32;
+                               flexram_wait();
+                       }
+                       offset += 4;
+                       len -= 4;
+               } else if ((lsb == 0 || lsb == 2) && len >= 2) {
+                       // write aligned 16 bits
+                       uint16_t val16;
+                       val16 = *src++;
+                       val16 |= (*src++ << 8);
+                       if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
+                               *(uint16_t *)(&FlexRAM[offset]) = val16;
+                               flexram_wait();
+                       }
+                       offset += 2;
+                       len -= 2;
+               } else {
+                       // write 8 bits
+                       uint8_t val8 = *src++;
+                       if (FlexRAM[offset] != val8) {
+                               FlexRAM[offset] = val8;
+                               flexram_wait();
+                       }
+                       offset++;
+                       len--;
+               }
+       }
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+       *fstat = 0x80;
+       while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+   0:  f06f 037f       mvn.w   r3, #127        ; 0x7f
+   4:  7003            strb    r3, [r0, #0]
+   6:  7803            ldrb    r3, [r0, #0]
+   8:  f013 0f80       tst.w   r3, #128        ; 0x80
+   c:  d0fb            beq.n   6 <do_flash_cmd+0x6>
+   e:  4770            bx      lr
+*/
+
+#elif defined(KL2x) /* chip selection */
+/* Teensy LC (emulated) */
+
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+
+extern uint32_t __eeprom_workarea_start__;
+extern uint32_t __eeprom_workarea_end__;
+
+#define EEPROM_SIZE 128
+
+static uint32_t flashend = 0;
+
+void eeprom_initialize(void)
+{
+       const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+
+       do {
+               if (*p++ == 0xFFFF) {
+                       flashend = (uint32_t)(p - 2);
+                       return;
+               }
+       } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
+       flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
+}
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+       uint32_t offset = (uint32_t)addr;
+       const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+       const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
+       uint16_t val;
+       uint8_t data=0xFF;
+
+       if (!end) {
+               eeprom_initialize();
+               end = (const uint16_t *)((uint32_t)flashend);
+       }
+       if (offset < EEPROM_SIZE) {
+               while (p <= end) {
+                       val = *p++;
+                       if ((val & 255) == offset) data = val >> 8;
+               }
+       }
+       return data;
+}
+
+static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
+{
+       // with great power comes great responsibility....
+       uint32_t stat;
+       *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
+       *(uint32_t *)&(FTFA->FCCOB7) = data;
+       __disable_irq();
+       (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
+       __enable_irq();
+       stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
+       if (stat) {
+               FTFA->FSTAT = stat;
+       }
+       MCM->PLACR |= MCM_PLACR_CFCC;
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t data)
+{
+       uint32_t offset = (uint32_t)addr;
+       const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
+       uint32_t i, val, flashaddr;
+       uint16_t do_flash_cmd[] = {
+               0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
+       uint8_t buf[EEPROM_SIZE];
+
+       if (offset >= EEPROM_SIZE) return;
+       if (!end) {
+               eeprom_initialize();
+               end = (const uint16_t *)((uint32_t)flashend);
+       }
+       if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
+               val = (data << 8) | offset;
+               flashaddr = (uint32_t)end;
+               flashend = flashaddr;
+               if ((flashaddr & 2) == 0) {
+                       val |= 0xFFFF0000;
+               } else {
+                       val <<= 16;
+                       val |= 0x0000FFFF;
+               }
+               flash_write(do_flash_cmd, flashaddr, val);
+       } else {
+               for (i=0; i < EEPROM_SIZE; i++) {
+                       buf[i] = 0xFF;
+               }
+               for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
+                       val = *p;
+                       if ((val & 255) < EEPROM_SIZE) {
+                               buf[val & 255] = val >> 8;
+                       }
+               }
+               buf[offset] = data;
+               for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
+                       *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
+                       __disable_irq();
+                       (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
+                       __enable_irq();
+                       val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
+                       if (val) FTFA->FSTAT = val;
+                       MCM->PLACR |= MCM_PLACR_CFCC;
+               }
+               flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
+               for (i=0; i < EEPROM_SIZE; i++) {
+                       if (buf[i] == 0xFF) continue;
+                       if ((flashaddr & 2) == 0) {
+                               val = (buf[i] << 8) | i;
+                       } else {
+                               val = val | (buf[i] << 24) | (i << 16);
+                               flash_write(do_flash_cmd, flashaddr, val);
+                       }
+                       flashaddr += 2;
+               }
+               flashend = flashaddr;
+               if ((flashaddr & 2)) {
+                       val |= 0xFFFF0000;
+                       flash_write(do_flash_cmd, flashaddr, val);
+               }
+       }
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+        *fstat = 0x80;
+        while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+   0:  2380            movs    r3, #128        ; 0x80
+   2:  7003            strb    r3, [r0, #0]
+   4:  7803            ldrb    r3, [r0, #0]
+   6:  b25b            sxtb    r3, r3
+   8:  2b00            cmp     r3, #0
+   a:  dafb            bge.n   4 <do_flash_cmd+0x4>
+   c:  4770            bx      lr
+*/
+
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+       const uint8_t *p = (const uint8_t *)addr;
+       return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+       const uint8_t *p = (const uint8_t *)addr;
+       return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
+               | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+       const uint8_t *p = (const uint8_t *)addr;
+       uint8_t *dest = (uint8_t *)buf;
+       while (len--) {
+               *dest++ = eeprom_read_byte(p++);
+       }
+}
+
+int eeprom_is_ready(void)
+{
+       return 1;
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+       uint8_t *p = (uint8_t *)addr;
+       eeprom_write_byte(p++, value);
+       eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+       uint8_t *p = (uint8_t *)addr;
+       eeprom_write_byte(p++, value);
+       eeprom_write_byte(p++, value >> 8);
+       eeprom_write_byte(p++, value >> 16);
+       eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+       uint8_t *p = (uint8_t *)addr;
+       const uint8_t *src = (const uint8_t *)buf;
+       while (len--) {
+               eeprom_write_byte(p++, *src++);
+       }
+}
+
+#else
+#error EEPROM support not implemented for your chip
+#endif /* chip selection */
+
+
+/*****************/
+/* TMK functions */
+/*****************/
+
+void eeconfig_init(void)
+{
+    eeprom_write_word(EECONFIG_MAGIC,          EECONFIG_MAGIC_NUMBER);
+    eeprom_write_byte(EECONFIG_DEBUG,          0);
+    eeprom_write_byte(EECONFIG_DEFAULT_LAYER,  0);
+    eeprom_write_byte(EECONFIG_KEYMAP,         0);
+    eeprom_write_byte(EECONFIG_MOUSEKEY_ACCEL, 0);
+#ifdef BACKLIGHT_ENABLE
+    eeprom_write_byte(EECONFIG_BACKLIGHT,      0);
+#endif
+}
+
+void eeconfig_enable(void)
+{
+    eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
+}
+
+void eeconfig_disable(void)
+{
+    eeprom_write_word(EECONFIG_MAGIC, 0xFFFF);
+}
+
+bool eeconfig_is_enabled(void)
+{
+    return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER);
+}
+
+uint8_t eeconfig_read_debug(void)      { return eeprom_read_byte(EECONFIG_DEBUG); }
+void eeconfig_write_debug(uint8_t val) { eeprom_write_byte(EECONFIG_DEBUG, val); }
+
+uint8_t eeconfig_read_default_layer(void)      { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); }
+void eeconfig_write_default_layer(uint8_t val) { eeprom_write_byte(EECONFIG_DEFAULT_LAYER, val); }
+
+uint8_t eeconfig_read_keymap(void)      { return eeprom_read_byte(EECONFIG_KEYMAP); }
+void eeconfig_write_keymap(uint8_t val) { eeprom_write_byte(EECONFIG_KEYMAP, val); }
+
+#ifdef BACKLIGHT_ENABLE
+uint8_t eeconfig_read_backlight(void)      { return eeprom_read_byte(EECONFIG_BACKLIGHT); }
+void eeconfig_write_backlight(uint8_t val) { eeprom_write_byte(EECONFIG_BACKLIGHT, val); }
+#endif
index f0d39f318101c0845da871394f3b2aaaea7abcf6..883054a45d501bd18ca2189e6b201af689bcf2de 100644 (file)
@@ -18,7 +18,6 @@ SRC +=        $(COMMON_DIR)/host.c \
 
 # Option modules
 ifdef BOOTMAGIC_ENABLE
-    $(error Bootmagic Not Supported)
     SRC += $(COMMON_DIR)/bootmagic.c
     SRC += $(COMMON_DIR)/chibios/eeconfig.c
     OPT_DEFS += -DBOOTMAGIC_ENABLE