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