aboutsummaryrefslogtreecommitdiff
path: root/tmk_core/common/chibios/eeprom.c
diff options
context:
space:
mode:
authorfredizzimo <fsundvik@gmail.com>2016-07-01 17:04:53 +0300
committerJack Humbert <jack.humb@gmail.com>2016-07-01 10:04:53 -0400
commit4d4f7684e684bec319f166121463a88cd4a62703 (patch)
tree4c04ce03e49356283925556342845b1bd656e930 /tmk_core/common/chibios/eeprom.c
parenta8b55f8c858933a0f7641f7bf2dede640235aa70 (diff)
downloadqmk_firmware-4d4f7684e684bec319f166121463a88cd4a62703.tar.gz
qmk_firmware-4d4f7684e684bec319f166121463a88cd4a62703.zip
Add ChibiOS support for QMK (#465)
* Modularity and gcc warnings fixes. * Add ChibiOS support (USB stack + support files). * Make usb_main more USB_DRIVER #define independent. * Move chibios to tool. * Implement jump-to-bootloader. * Small updates. * Fix bootloader-jump compiling. * Move AVR specific sleep_led.c into avr. * Add basic sleep_led for chibios. * Update chibios README. * NKRO fixes. * Rename some Makefile defines. * Move STM32 bootloader address config to separate .h file. * Add ARM Teensies bootloader code. * Fix chibios/usb_main GET_REPORT handing. * Add missing #include to keymap.c. * Make bootmagic.c code portable (_delay_ms -> wait_ms). * Move declaration of keymap_config. Should really not declare variables in .h files - since it's included in different .c files, a proper linker then complains that the same variable is declared more than once (once for each .c file that the offending .h is included in). * Add eeprom support for chibios/kinetis. * Rename chibios example keyboard. * Move chibios/cortex selection to local Makefiles. * Chibios: use WFI in idle. WIP suspend stuff. * ChibiOS/kinetis: sending remote wakeup. * ChibiOS/STM32: send remote wakeup. * Fix report size of boot protocol. * Fix drop key stroke Keyboard report should be checked if its transfer finishs successfully. Otherwise key stroke can be missing when other key event occurs before the last report transfer is done. Boot protocol 10ms interval probably causes this problem in case it receives key events in a row within the period. NKRO protocol suffers less or nothing due to its interval 1ms. * Chibios/usb_main: rename a variable for clarity. * Add correct chibios/bootloader_jump for infinity KB. * ChibiOS: make reset request more CMSISy. * Chibios: Add breathing sleep LED on Kinetis MCUs. * ChibiOS: Update infinity bootloader code to match updated ChibiOS. * ChibiOS: prettify/document sleep_led code. * Chibios: Remove the wait in the main loop. * Add maple mini code. * Do timeout when writing to CONSOLE EP queue. Fixes TMK bug #266. * Chibios: add 'core/protocol' to the makefiles' search path. * Chibios: Update to new USB API. * Chibios: add more guards for transmitting (fix a deadlock bug). * Add update for chibios in README * Chibios: Fix a HardFault bug (wait after start). * Chibios: cleanup usb_main code. * Chibios: Revert common.mk change (fix AVR linking problem). * core: Fix chibios user compile options Compile options can be defined in project Makefile such as UDEFS, UADEFS, UINCDIR, ULIBDIR and ULIBS. * Sysv format for ChibiOS arm-none-eabi-size Some new patches to ChibiOS puts heap as it's own section. So the berkeley format is now useless, as the heap will be included in the BSS report. The sysv format displays the bss size correctly. * Fix hard-coded path of CHIBIOS * Add support for new version of ChibiOS and Contrib The Kinetis support has moved to a separate Contrib repository in the newest version of Chibios. There has also been some structure changes. So this adds support for those, while maintaining back- wards compability. * Update ChibiOS instructions * Chibios: implement sleep LED for STM32. * Chibios: Update the main chibios README. * Chibios: fix STM32_BOOTLOADER_ADDRESS name. * Chibios: make the default bootloader_jump redefinable (weak). * Chibios: disable LTO (link-time optimisation). With LTO enabled, sometimes things fail for mysterious reasons (e.g. bootloader jump on WF with LEDs enabled), just because the linker optimisation is too aggressive. * Chibios: add default location for chibios-contrib. * ChibiOS: update mk to match chibios/master. * ChibiOS: update instructions.md. * Add chibi_onekey example. * Add comments to chibi_onekey Makefile. * Rename some Makefile defines. * Move STM32 bootloader address config to separate .h file. * Rename chibios example keyboard. * Move chibios/cortex selection to local Makefiles. * Add Teensy LC onekey example. * Chibios: use WFI in idle. WIP suspend stuff. * Update chibi/teensy instructions. * Update chibios/Teensy instructions. * Add infinity_chibios * Add keymap_hasu.c * Infinity_chibios: select correct bootloader_jump. * Infinity_chibios: improve comments. * Add generic STM32F103C8T6 example. * Add maple mini code. * STM32F103x fixes. * Add maple mini pinout pic. * Chibios: updates for 3.0.4 git. * Chibios: rename example stm32_onekey -> stm32_f072_onekey. * Chibios: add makefiles for Teensy 3.x examples. * Chibios: update Teensy 3.x instructions. * Chibios: Tsy LC is cortex-m0plus. * Chibios: add more guards for transmitting (fix a deadlock bug). * Change README for chibios * Chibios: update examples to current chibios git. Match the changes in mainline chibios: - update chconf.h - update supplied ld scripts structure - update Teensy instructions (switch to official chibios and introduce contrib) * Add ChibiOS and ChibiOS-Contrib submodules Also fix the makefile path for them. * Moves chibios keyboards to keyboards folder * First version of ChibiOS compilation Only the stm32_f072_onkey keyboard is ported at the moment. It compiles, but still doesn't link. * More chibios fixes It now compiles without warnings and links * Move the teensy_lc_onekey to the keyboards folder * Clean up the make file rule structure * Remove keymap_fn_to_action * Update more ChibiOS keyboards to QMK Most of them does not compile at the moment though. * Use older version of Chibios libraries The newest ones have problems with compilation * Remove USB_UNCONFIGURED event It isn't present in the older version of ChibiOS * Fix the infinity_chibios compilation * Fix potentially uninitialized variable * Add missing include * Fix the ChibiOS makefile * Fix some Chibios keyboard compilation * Revert the rules.mk file back to master version * Combine the chibios and AVR makefiles With just the required overrides in the respective platform specific one. * Slight makefile restrucuring Platform specific compiler options * Move avr specific targets out of the main rules * Fix ChibiOS objcopy The ChibiOS objcopy needs different parameters, so the parameters are moved to the corresponding platform rule file * Fix the objcopy for real this time The comands were moved around, so chibios used avr and the ohter way around. Also change the objsize output format * Fix the thumb flags * Fix the infinity hasu keymap * Per platform cpp flags * Add gcc-arm-none-eabi package to travis * Add arm-none-eabi-newlib to travis * Fix the name of the libnewlib-arm-none-eabi lib * Fix the ChibiOS paths So that they are properly relative, and builds don't generate extra folders * Fix the board path of stm32_f103_onekey * Only consider folders with Makefiles as subproject
Diffstat (limited to 'tmk_core/common/chibios/eeprom.c')
-rw-r--r--tmk_core/common/chibios/eeprom.c588
1 files changed, 588 insertions, 0 deletions
diff --git a/tmk_core/common/chibios/eeprom.c b/tmk_core/common/chibios/eeprom.c
new file mode 100644
index 000000000..5ff8ee86f
--- /dev/null
+++ b/tmk_core/common/chibios/eeprom.c
@@ -0,0 +1,588 @@
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
82void 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
114uint8_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
122uint16_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
130uint32_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
138void 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
151int eeprom_is_ready(void)
152{
153 return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
154}
155
156static void flexram_wait(void)
157{
158 while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
159 // TODO: timeout
160 }
161}
162
163void 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
175void 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
202void 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
245void 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/*
294void do_flash_cmd(volatile uint8_t *fstat)
295{
296 *fstat = 0x80;
297 while ((*fstat & 0x80) == 0) ; // wait
298}
29900000000 <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
313extern uint32_t __eeprom_workarea_start__;
314extern uint32_t __eeprom_workarea_end__;
315
316#define EEPROM_SIZE 128
317
318static uint32_t flashend = 0;
319
320void 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
333uint8_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
354static 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
370void 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 val = 0;
400 for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
401 val = *p;
402 if ((val & 255) < EEPROM_SIZE) {
403 buf[val & 255] = val >> 8;
404 }
405 }
406 buf[offset] = data;
407 for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
408 *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
409 __disable_irq();
410 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
411 __enable_irq();
412 val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
413 if (val) FTFA->FSTAT = val;
414 MCM->PLACR |= MCM_PLACR_CFCC;
415 }
416 flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
417 for (i=0; i < EEPROM_SIZE; i++) {
418 if (buf[i] == 0xFF) continue;
419 if ((flashaddr & 2) == 0) {
420 val = (buf[i] << 8) | i;
421 } else {
422 val = val | (buf[i] << 24) | (i << 16);
423 flash_write(do_flash_cmd, flashaddr, val);
424 }
425 flashaddr += 2;
426 }
427 flashend = flashaddr;
428 if ((flashaddr & 2)) {
429 val |= 0xFFFF0000;
430 flash_write(do_flash_cmd, flashaddr, val);
431 }
432 }
433}
434
435/*
436void do_flash_cmd(volatile uint8_t *fstat)
437{
438 *fstat = 0x80;
439 while ((*fstat & 0x80) == 0) ; // wait
440}
44100000000 <do_flash_cmd>:
442 0: 2380 movs r3, #128 ; 0x80
443 2: 7003 strb r3, [r0, #0]
444 4: 7803 ldrb r3, [r0, #0]
445 6: b25b sxtb r3, r3
446 8: 2b00 cmp r3, #0
447 a: dafb bge.n 4 <do_flash_cmd+0x4>
448 c: 4770 bx lr
449*/
450
451
452uint16_t eeprom_read_word(const uint16_t *addr)
453{
454 const uint8_t *p = (const uint8_t *)addr;
455 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
456}
457
458uint32_t eeprom_read_dword(const uint32_t *addr)
459{
460 const uint8_t *p = (const uint8_t *)addr;
461 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
462 | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
463}
464
465void eeprom_read_block(void *buf, const void *addr, uint32_t len)
466{
467 const uint8_t *p = (const uint8_t *)addr;
468 uint8_t *dest = (uint8_t *)buf;
469 while (len--) {
470 *dest++ = eeprom_read_byte(p++);
471 }
472}
473
474int eeprom_is_ready(void)
475{
476 return 1;
477}
478
479void eeprom_write_word(uint16_t *addr, uint16_t value)
480{
481 uint8_t *p = (uint8_t *)addr;
482 eeprom_write_byte(p++, value);
483 eeprom_write_byte(p, value >> 8);
484}
485
486void eeprom_write_dword(uint32_t *addr, uint32_t value)
487{
488 uint8_t *p = (uint8_t *)addr;
489 eeprom_write_byte(p++, value);
490 eeprom_write_byte(p++, value >> 8);
491 eeprom_write_byte(p++, value >> 16);
492 eeprom_write_byte(p, value >> 24);
493}
494
495void eeprom_write_block(const void *buf, void *addr, uint32_t len)
496{
497 uint8_t *p = (uint8_t *)addr;
498 const uint8_t *src = (const uint8_t *)buf;
499 while (len--) {
500 eeprom_write_byte(p++, *src++);
501 }
502}
503
504#else
505// No EEPROM supported, so emulate it
506
507#define EEPROM_SIZE 32
508static uint8_t buffer[EEPROM_SIZE];
509
510uint8_t eeprom_read_byte(const uint8_t *addr) {
511 uint32_t offset = (uint32_t)addr;
512 return buffer[offset];
513}
514
515void eeprom_write_byte(uint8_t *addr, uint8_t value) {
516 uint32_t offset = (uint32_t)addr;
517 buffer[offset] = value;
518}
519
520uint16_t eeprom_read_word(const uint16_t *addr) {
521 const uint8_t *p = (const uint8_t *)addr;
522 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
523}
524
525uint32_t eeprom_read_dword(const uint32_t *addr) {
526 const uint8_t *p = (const uint8_t *)addr;
527 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
528 | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
529}
530
531void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
532 const uint8_t *p = (const uint8_t *)addr;
533 uint8_t *dest = (uint8_t *)buf;
534 while (len--) {
535 *dest++ = eeprom_read_byte(p++);
536 }
537}
538
539void eeprom_write_word(uint16_t *addr, uint16_t value) {
540 uint8_t *p = (uint8_t *)addr;
541 eeprom_write_byte(p++, value);
542 eeprom_write_byte(p, value >> 8);
543}
544
545void eeprom_write_dword(uint32_t *addr, uint32_t value) {
546 uint8_t *p = (uint8_t *)addr;
547 eeprom_write_byte(p++, value);
548 eeprom_write_byte(p++, value >> 8);
549 eeprom_write_byte(p++, value >> 16);
550 eeprom_write_byte(p, value >> 24);
551}
552
553void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
554 uint8_t *p = (uint8_t *)addr;
555 const uint8_t *src = (const uint8_t *)buf;
556 while (len--) {
557 eeprom_write_byte(p++, *src++);
558 }
559}
560
561#endif /* chip selection */
562// The update functions just calls write for now, but could probably be optimized
563
564void eeprom_update_byte(uint8_t *addr, uint8_t value) {
565 eeprom_write_byte(addr, value);
566}
567
568void eeprom_update_word(uint16_t *addr, uint16_t value) {
569 uint8_t *p = (uint8_t *)addr;
570 eeprom_write_byte(p++, value);
571 eeprom_write_byte(p, value >> 8);
572}
573
574void eeprom_update_dword(uint32_t *addr, uint32_t value) {
575 uint8_t *p = (uint8_t *)addr;
576 eeprom_write_byte(p++, value);
577 eeprom_write_byte(p++, value >> 8);
578 eeprom_write_byte(p++, value >> 16);
579 eeprom_write_byte(p, value >> 24);
580}
581
582void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
583 uint8_t *p = (uint8_t *)addr;
584 const uint8_t *src = (const uint8_t *)buf;
585 while (len--) {
586 eeprom_write_byte(p++, *src++);
587 }
588}