qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

eeprom_kinetis_flexram.c (17442B)


      1 #include <ch.h>
      2 #include <hal.h>
      3 
      4 #include "eeprom_kinetis_flexram.h"
      5 #include "eeconfig.h"
      6 
      7 /*************************************/
      8 /*          Hardware backend         */
      9 /*                                   */
     10 /*    Code from PJRC/Teensyduino     */
     11 /*************************************/
     12 
     13 /* Teensyduino Core Library
     14  * http://www.pjrc.com/teensy/
     15  * Copyright (c) 2013 PJRC.COM, LLC.
     16  *
     17  * Permission is hereby granted, free of charge, to any person obtaining
     18  * a copy of this software and associated documentation files (the
     19  * "Software"), to deal in the Software without restriction, including
     20  * without limitation the rights to use, copy, modify, merge, publish,
     21  * distribute, sublicense, and/or sell copies of the Software, and to
     22  * permit persons to whom the Software is furnished to do so, subject to
     23  * the following conditions:
     24  *
     25  * 1. The above copyright notice and this permission notice shall be
     26  * included in all copies or substantial portions of the Software.
     27  *
     28  * 2. If the Software is incorporated into a build system that allows
     29  * selection among a list of target devices, then similar target
     30  * devices manufactured by PJRC.COM must be included in the list of
     31  * target devices and selectable in the same manner.
     32  *
     33  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     34  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     35  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     36  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     37  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     38  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     39  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     40  * SOFTWARE.
     41  */
     42 
     43 #if defined(K20x) /* chip selection */
     44 /* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
     45 
     46 /*
     47     ^^^ Here be dragons:
     48         NXP AppNote AN4282 section 3.1 states that partitioning must only be done once.
     49         Once EEPROM partitioning is done, the size is locked to this initial configuration.
     50         Attempts to modify the EEPROM_SIZE setting may brick your board.
     51 */
     52 
     53 // Writing unaligned 16 or 32 bit data is handled automatically when
     54 // this is defined, but at a cost of extra code size.  Without this,
     55 // any unaligned write will cause a hard fault exception!  If you're
     56 // absolutely sure all 16 and 32 bit writes will be aligned, you can
     57 // remove the extra unnecessary code.
     58 //
     59 #    define HANDLE_UNALIGNED_WRITES
     60 
     61 // Minimum EEPROM Endurance
     62 // ------------------------
     63 #    if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
     64 #        define EEESIZE 0x33
     65 #    elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
     66 #        define EEESIZE 0x34
     67 #    elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
     68 #        define EEESIZE 0x35
     69 #    elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
     70 #        define EEESIZE 0x36
     71 #    elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
     72 #        define EEESIZE 0x37
     73 #    elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
     74 #        define EEESIZE 0x38
     75 #    elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
     76 #        define EEESIZE 0x39
     77 #    endif
     78 
     79 /** \brief eeprom initialization
     80  *
     81  * FIXME: needs doc
     82  */
     83 void eeprom_initialize(void) {
     84     uint32_t count          = 0;
     85     uint16_t do_flash_cmd[] = {0xf06f, 0x037f, 0x7003, 0x7803, 0xf013, 0x0f80, 0xd0fb, 0x4770};
     86     uint8_t  status;
     87 
     88     if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
     89         // FlexRAM is configured as traditional RAM
     90         // We need to reconfigure for EEPROM usage
     91         FTFL->FCCOB0 = 0x80;    // PGMPART = Program Partition Command
     92         FTFL->FCCOB4 = EEESIZE; // EEPROM Size
     93         FTFL->FCCOB5 = 0x03;    // 0K for Dataflash, 32K for EEPROM backup
     94         __disable_irq();
     95         // do_flash_cmd() must execute from RAM.  Luckily the C syntax is simple...
     96         (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
     97         __enable_irq();
     98         status = FTFL->FSTAT;
     99         if (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL)) {
    100             FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL));
    101             return; // error
    102         }
    103     }
    104     // wait for eeprom to become ready (is this really necessary?)
    105     while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
    106         if (++count > 20000) break;
    107     }
    108 }
    109 
    110 #    define FlexRAM ((uint8_t *)0x14000000)
    111 
    112 /** \brief eeprom read byte
    113  *
    114  * FIXME: needs doc
    115  */
    116 uint8_t eeprom_read_byte(const uint8_t *addr) {
    117     uint32_t offset = (uint32_t)addr;
    118     if (offset >= EEPROM_SIZE) return 0;
    119     if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
    120     return FlexRAM[offset];
    121 }
    122 
    123 /** \brief eeprom read word
    124  *
    125  * FIXME: needs doc
    126  */
    127 uint16_t eeprom_read_word(const uint16_t *addr) {
    128     uint32_t offset = (uint32_t)addr;
    129     if (offset >= EEPROM_SIZE - 1) return 0;
    130     if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
    131     return *(uint16_t *)(&FlexRAM[offset]);
    132 }
    133 
    134 /** \brief eeprom read dword
    135  *
    136  * FIXME: needs doc
    137  */
    138 uint32_t eeprom_read_dword(const uint32_t *addr) {
    139     uint32_t offset = (uint32_t)addr;
    140     if (offset >= EEPROM_SIZE - 3) return 0;
    141     if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
    142     return *(uint32_t *)(&FlexRAM[offset]);
    143 }
    144 
    145 /** \brief eeprom read block
    146  *
    147  * FIXME: needs doc
    148  */
    149 void eeprom_read_block(void *buf, const void *addr, size_t len) {
    150     uint32_t offset = (uint32_t)addr;
    151     uint8_t *dest   = (uint8_t *)buf;
    152     uint32_t end    = offset + len;
    153 
    154     if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
    155     if (end > EEPROM_SIZE) end = EEPROM_SIZE;
    156     while (offset < end) {
    157         *dest++ = FlexRAM[offset++];
    158     }
    159 }
    160 
    161 /** \brief eeprom is ready
    162  *
    163  * FIXME: needs doc
    164  */
    165 int eeprom_is_ready(void) {
    166     return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
    167 }
    168 
    169 /** \brief flexram wait
    170  *
    171  * FIXME: needs doc
    172  */
    173 static void flexram_wait(void) {
    174     while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
    175         // TODO: timeout
    176     }
    177 }
    178 
    179 /** \brief eeprom_write_byte
    180  *
    181  * FIXME: needs doc
    182  */
    183 void eeprom_write_byte(uint8_t *addr, uint8_t value) {
    184     uint32_t offset = (uint32_t)addr;
    185 
    186     if (offset >= EEPROM_SIZE) return;
    187     if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
    188     if (FlexRAM[offset] != value) {
    189         FlexRAM[offset] = value;
    190         flexram_wait();
    191     }
    192 }
    193 
    194 /** \brief eeprom write word
    195  *
    196  * FIXME: needs doc
    197  */
    198 void eeprom_write_word(uint16_t *addr, uint16_t value) {
    199     uint32_t offset = (uint32_t)addr;
    200 
    201     if (offset >= EEPROM_SIZE - 1) return;
    202     if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
    203 #    ifdef HANDLE_UNALIGNED_WRITES
    204     if ((offset & 1) == 0) {
    205 #    endif
    206         if (*(uint16_t *)(&FlexRAM[offset]) != value) {
    207             *(uint16_t *)(&FlexRAM[offset]) = value;
    208             flexram_wait();
    209         }
    210 #    ifdef HANDLE_UNALIGNED_WRITES
    211     } else {
    212         if (FlexRAM[offset] != value) {
    213             FlexRAM[offset] = value;
    214             flexram_wait();
    215         }
    216         if (FlexRAM[offset + 1] != (value >> 8)) {
    217             FlexRAM[offset + 1] = value >> 8;
    218             flexram_wait();
    219         }
    220     }
    221 #    endif
    222 }
    223 
    224 /** \brief eeprom write dword
    225  *
    226  * FIXME: needs doc
    227  */
    228 void eeprom_write_dword(uint32_t *addr, uint32_t value) {
    229     uint32_t offset = (uint32_t)addr;
    230 
    231     if (offset >= EEPROM_SIZE - 3) return;
    232     if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
    233 #    ifdef HANDLE_UNALIGNED_WRITES
    234     switch (offset & 3) {
    235         case 0:
    236 #    endif
    237             if (*(uint32_t *)(&FlexRAM[offset]) != value) {
    238                 *(uint32_t *)(&FlexRAM[offset]) = value;
    239                 flexram_wait();
    240             }
    241             return;
    242 #    ifdef HANDLE_UNALIGNED_WRITES
    243         case 2:
    244             if (*(uint16_t *)(&FlexRAM[offset]) != value) {
    245                 *(uint16_t *)(&FlexRAM[offset]) = value;
    246                 flexram_wait();
    247             }
    248             if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
    249                 *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
    250                 flexram_wait();
    251             }
    252             return;
    253         default:
    254             if (FlexRAM[offset] != value) {
    255                 FlexRAM[offset] = value;
    256                 flexram_wait();
    257             }
    258             if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
    259                 *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
    260                 flexram_wait();
    261             }
    262             if (FlexRAM[offset + 3] != (value >> 24)) {
    263                 FlexRAM[offset + 3] = value >> 24;
    264                 flexram_wait();
    265             }
    266     }
    267 #    endif
    268 }
    269 
    270 /** \brief eeprom write block
    271  *
    272  * FIXME: needs doc
    273  */
    274 void eeprom_write_block(const void *buf, void *addr, size_t len) {
    275     uint32_t       offset = (uint32_t)addr;
    276     const uint8_t *src    = (const uint8_t *)buf;
    277 
    278     if (offset >= EEPROM_SIZE) return;
    279     if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
    280     if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
    281     if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
    282     while (len > 0) {
    283         uint32_t lsb = offset & 3;
    284         if (lsb == 0 && len >= 4) {
    285             // write aligned 32 bits
    286             uint32_t val32;
    287             val32 = *src++;
    288             val32 |= (*src++ << 8);
    289             val32 |= (*src++ << 16);
    290             val32 |= (*src++ << 24);
    291             if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
    292                 *(uint32_t *)(&FlexRAM[offset]) = val32;
    293                 flexram_wait();
    294             }
    295             offset += 4;
    296             len -= 4;
    297         } else if ((lsb == 0 || lsb == 2) && len >= 2) {
    298             // write aligned 16 bits
    299             uint16_t val16;
    300             val16 = *src++;
    301             val16 |= (*src++ << 8);
    302             if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
    303                 *(uint16_t *)(&FlexRAM[offset]) = val16;
    304                 flexram_wait();
    305             }
    306             offset += 2;
    307             len -= 2;
    308         } else {
    309             // write 8 bits
    310             uint8_t val8 = *src++;
    311             if (FlexRAM[offset] != val8) {
    312                 FlexRAM[offset] = val8;
    313                 flexram_wait();
    314             }
    315             offset++;
    316             len--;
    317         }
    318     }
    319 }
    320 
    321 /*
    322 void do_flash_cmd(volatile uint8_t *fstat)
    323 {
    324     *fstat = 0x80;
    325     while ((*fstat & 0x80) == 0) ; // wait
    326 }
    327 00000000 <do_flash_cmd>:
    328    0:	f06f 037f 	mvn.w	r3, #127	; 0x7f
    329    4:	7003      	strb	r3, [r0, #0]
    330    6:	7803      	ldrb	r3, [r0, #0]
    331    8:	f013 0f80 	tst.w	r3, #128	; 0x80
    332    c:	d0fb      	beq.n	6 <do_flash_cmd+0x6>
    333    e:	4770      	bx	lr
    334 */
    335 
    336 #elif defined(KL2x) /* chip selection */
    337 /* Teensy LC (emulated) */
    338 
    339 #    define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
    340 
    341 extern uint32_t __eeprom_workarea_start__;
    342 extern uint32_t __eeprom_workarea_end__;
    343 
    344 static uint32_t flashend = 0;
    345 
    346 void eeprom_initialize(void) {
    347     const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
    348 
    349     do {
    350         if (*p++ == 0xFFFF) {
    351             flashend = (uint32_t)(p - 2);
    352             return;
    353         }
    354     } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
    355     flashend = (uint32_t)(p - 1);
    356 }
    357 
    358 uint8_t eeprom_read_byte(const uint8_t *addr) {
    359     uint32_t        offset = (uint32_t)addr;
    360     const uint16_t *p      = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
    361     const uint16_t *end    = (const uint16_t *)((uint32_t)flashend);
    362     uint16_t        val;
    363     uint8_t         data = 0xFF;
    364 
    365     if (!end) {
    366         eeprom_initialize();
    367         end = (const uint16_t *)((uint32_t)flashend);
    368     }
    369     if (offset < EEPROM_SIZE) {
    370         while (p <= end) {
    371             val = *p++;
    372             if ((val & 255) == offset) data = val >> 8;
    373         }
    374     }
    375     return data;
    376 }
    377 
    378 static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data) {
    379     // with great power comes great responsibility....
    380     uint32_t stat;
    381     *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
    382     *(uint32_t *)&(FTFA->FCCOB7) = data;
    383     __disable_irq();
    384     (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
    385     __enable_irq();
    386     stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL);
    387     if (stat) {
    388         FTFA->FSTAT = stat;
    389     }
    390     MCM->PLACR |= MCM_PLACR_CFCC;
    391 }
    392 
    393 void eeprom_write_byte(uint8_t *addr, uint8_t data) {
    394     uint32_t        offset = (uint32_t)addr;
    395     const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
    396     uint32_t        i, val, flashaddr;
    397     uint16_t        do_flash_cmd[] = {0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
    398     uint8_t         buf[EEPROM_SIZE];
    399 
    400     if (offset >= EEPROM_SIZE) return;
    401     if (!end) {
    402         eeprom_initialize();
    403         end = (const uint16_t *)((uint32_t)flashend);
    404     }
    405     if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
    406         val       = (data << 8) | offset;
    407         flashaddr = (uint32_t)end;
    408         flashend  = flashaddr;
    409         if ((flashaddr & 2) == 0) {
    410             val |= 0xFFFF0000;
    411         } else {
    412             val <<= 16;
    413             val |= 0x0000FFFF;
    414         }
    415         flash_write(do_flash_cmd, flashaddr, val);
    416     } else {
    417         for (i = 0; i < EEPROM_SIZE; i++) {
    418             buf[i] = 0xFF;
    419         }
    420         val = 0;
    421         for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
    422             val = *p;
    423             if ((val & 255) < EEPROM_SIZE) {
    424                 buf[val & 255] = val >> 8;
    425             }
    426         }
    427         buf[offset] = data;
    428         for (flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
    429             *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
    430             __disable_irq();
    431             (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
    432             __enable_irq();
    433             val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL);
    434             ;
    435             if (val) FTFA->FSTAT = val;
    436             MCM->PLACR |= MCM_PLACR_CFCC;
    437         }
    438         flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
    439         for (i = 0; i < EEPROM_SIZE; i++) {
    440             if (buf[i] == 0xFF) continue;
    441             if ((flashaddr & 2) == 0) {
    442                 val = (buf[i] << 8) | i;
    443             } else {
    444                 val = val | (buf[i] << 24) | (i << 16);
    445                 flash_write(do_flash_cmd, flashaddr, val);
    446             }
    447             flashaddr += 2;
    448         }
    449         flashend = flashaddr;
    450         if ((flashaddr & 2)) {
    451             val |= 0xFFFF0000;
    452             flash_write(do_flash_cmd, flashaddr, val);
    453         }
    454     }
    455 }
    456 
    457 /*
    458 void do_flash_cmd(volatile uint8_t *fstat)
    459 {
    460         *fstat = 0x80;
    461         while ((*fstat & 0x80) == 0) ; // wait
    462 }
    463 00000000 <do_flash_cmd>:
    464    0:	2380      	movs	r3, #128	; 0x80
    465    2:	7003      	strb	r3, [r0, #0]
    466    4:	7803      	ldrb	r3, [r0, #0]
    467    6:	b25b      	sxtb	r3, r3
    468    8:	2b00      	cmp	r3, #0
    469    a:	dafb      	bge.n	4 <do_flash_cmd+0x4>
    470    c:	4770      	bx	lr
    471 */
    472 
    473 uint16_t eeprom_read_word(const uint16_t *addr) {
    474     const uint8_t *p = (const uint8_t *)addr;
    475     return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
    476 }
    477 
    478 uint32_t eeprom_read_dword(const uint32_t *addr) {
    479     const uint8_t *p = (const uint8_t *)addr;
    480     return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
    481 }
    482 
    483 void eeprom_read_block(void *buf, const void *addr, size_t len) {
    484     const uint8_t *p    = (const uint8_t *)addr;
    485     uint8_t       *dest = (uint8_t *)buf;
    486     while (len--) {
    487         *dest++ = eeprom_read_byte(p++);
    488     }
    489 }
    490 
    491 int eeprom_is_ready(void) {
    492     return 1;
    493 }
    494 
    495 void eeprom_write_word(uint16_t *addr, uint16_t value) {
    496     uint8_t *p = (uint8_t *)addr;
    497     eeprom_write_byte(p++, value);
    498     eeprom_write_byte(p, value >> 8);
    499 }
    500 
    501 void eeprom_write_dword(uint32_t *addr, uint32_t value) {
    502     uint8_t *p = (uint8_t *)addr;
    503     eeprom_write_byte(p++, value);
    504     eeprom_write_byte(p++, value >> 8);
    505     eeprom_write_byte(p++, value >> 16);
    506     eeprom_write_byte(p, value >> 24);
    507 }
    508 
    509 void eeprom_write_block(const void *buf, void *addr, size_t len) {
    510     uint8_t       *p   = (uint8_t *)addr;
    511     const uint8_t *src = (const uint8_t *)buf;
    512     while (len--) {
    513         eeprom_write_byte(p++, *src++);
    514     }
    515 }
    516 
    517 #else
    518 #    error Unsupported Teensy EEPROM.
    519 #endif /* chip selection */
    520 // The update functions just calls write for now, but could probably be optimized
    521 
    522 void eeprom_update_byte(uint8_t *addr, uint8_t value) {
    523     eeprom_write_byte(addr, value);
    524 }
    525 
    526 void eeprom_update_word(uint16_t *addr, uint16_t value) {
    527     uint8_t *p = (uint8_t *)addr;
    528     eeprom_write_byte(p++, value);
    529     eeprom_write_byte(p, value >> 8);
    530 }
    531 
    532 void eeprom_update_dword(uint32_t *addr, uint32_t value) {
    533     uint8_t *p = (uint8_t *)addr;
    534     eeprom_write_byte(p++, value);
    535     eeprom_write_byte(p++, value >> 8);
    536     eeprom_write_byte(p++, value >> 16);
    537     eeprom_write_byte(p, value >> 24);
    538 }
    539 
    540 void eeprom_update_block(const void *buf, void *addr, size_t len) {
    541     uint8_t       *p   = (uint8_t *)addr;
    542     const uint8_t *src = (const uint8_t *)buf;
    543     while (len--) {
    544         eeprom_write_byte(p++, *src++);
    545     }
    546 }