aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios-contrib/testhal/KINETIS/TEENSY_LC/EEPROM_EMU/eeprom.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios-contrib/testhal/KINETIS/TEENSY_LC/EEPROM_EMU/eeprom.c')
-rw-r--r--lib/chibios-contrib/testhal/KINETIS/TEENSY_LC/EEPROM_EMU/eeprom.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/lib/chibios-contrib/testhal/KINETIS/TEENSY_LC/EEPROM_EMU/eeprom.c b/lib/chibios-contrib/testhal/KINETIS/TEENSY_LC/EEPROM_EMU/eeprom.c
new file mode 100644
index 000000000..05ee313d3
--- /dev/null
+++ b/lib/chibios-contrib/testhal/KINETIS/TEENSY_LC/EEPROM_EMU/eeprom.c
@@ -0,0 +1,241 @@
1/*
2 * Eeprom emulation for KL2x chips.
3 * (c) 2015 flabbergast
4 * Most of the code is from PJRC/Teensyduino (license below)
5 *
6 * Notes: Some wear-levelling is done:
7 * - emulating 128 bytes of eeprom; i.e. 7 bit "eeprom addresses"
8 * - using 2048 bytes of flash
9 * - new values are written consecutively into flash
10 * as 16bit ("eeprom address",value) pairs
11 * - if all 2048 bytes of flash is used, it is erased and writes
12 * start from the beginning again
13 * - the 2048 bytes of flash used are at the end of the flash
14 * - BEWARE: there is no protection! Use a custom .ld script
15 * to make sure this area is never used for code!
16 */
17
18/* Teensyduino Core Library
19 * http://www.pjrc.com/teensy/
20 * Copyright (c) 2013 PJRC.COM, LLC.
21 *
22 * Permission is hereby granted, free of charge, to any person obtaining
23 * a copy of this software and associated documentation files (the
24 * "Software"), to deal in the Software without restriction, including
25 * without limitation the rights to use, copy, modify, merge, publish,
26 * distribute, sublicense, and/or sell copies of the Software, and to
27 * permit persons to whom the Software is furnished to do so, subject to
28 * the following conditions:
29 *
30 * 1. The above copyright notice and this permission notice shall be
31 * included in all copies or substantial portions of the Software.
32 *
33 * 2. If the Software is incorporated into a build system that allows
34 * selection among a list of target devices, then similar target
35 * devices manufactured by PJRC.COM must be included in the list of
36 * target devices and selectable in the same manner.
37 *
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
39 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
41 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
42 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
43 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
44 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
45 * SOFTWARE.
46 */
47
48#include "ch.h"
49#include "hal.h"
50
51#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
52
53extern uint32_t __eeprom_workarea_start__;
54extern uint32_t __eeprom_workarea_end__;
55
56#define EEPROM_SIZE 128
57
58static uint32_t flashend = 0;
59
60void eeprom_initialize(void)
61{
62 const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
63
64 do {
65 if (*p++ == 0xFFFF) {
66 flashend = (uint32_t)(p - 2);
67 return;
68 }
69 } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
70 flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
71}
72
73uint8_t eeprom_read_byte(const uint8_t *addr)
74{
75 uint32_t offset = (uint32_t)addr;
76 const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
77 const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
78 uint16_t val;
79 uint8_t data=0xFF;
80
81 if (!end) {
82 eeprom_initialize();
83 end = (const uint16_t *)((uint32_t)flashend);
84 }
85 if (offset < EEPROM_SIZE) {
86 while (p <= end) {
87 val = *p++;
88 if ((val & 255) == offset) data = val >> 8;
89 }
90 }
91 return data;
92}
93
94static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
95{
96 // with great power comes great responsibility....
97 uint32_t stat;
98 *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
99 *(uint32_t *)&(FTFA->FCCOB7) = data;
100 __disable_irq();
101 (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
102 __enable_irq();
103 stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
104 if (stat) {
105 FTFA->FSTAT = stat;
106 }
107 MCM->PLACR |= MCM_PLACR_CFCC;
108}
109
110void eeprom_write_byte(uint8_t *addr, uint8_t data)
111{
112 uint32_t offset = (uint32_t)addr;
113 const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
114 uint32_t i, val, flashaddr;
115 uint16_t do_flash_cmd[] = {
116 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
117 uint8_t buf[EEPROM_SIZE];
118
119 if (offset >= EEPROM_SIZE) return;
120 if (!end) {
121 eeprom_initialize();
122 end = (const uint16_t *)((uint32_t)flashend);
123 }
124 if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
125 val = (data << 8) | offset;
126 flashaddr = (uint32_t)end;
127 flashend = flashaddr;
128 if ((flashaddr & 2) == 0) {
129 val |= 0xFFFF0000;
130 } else {
131 val <<= 16;
132 val |= 0x0000FFFF;
133 }
134 flash_write(do_flash_cmd, flashaddr, val);
135 } else {
136 for (i=0; i < EEPROM_SIZE; i++) {
137 buf[i] = 0xFF;
138 }
139 for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
140 val = *p;
141 if ((val & 255) < EEPROM_SIZE) {
142 buf[val & 255] = val >> 8;
143 }
144 }
145 buf[offset] = data;
146 for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
147 *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
148 __disable_irq();
149 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
150 __enable_irq();
151 val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
152 if (val) FTFA->FSTAT = val;
153 MCM->PLACR |= MCM_PLACR_CFCC;
154 }
155 flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
156 for (i=0; i < EEPROM_SIZE; i++) {
157 if (buf[i] == 0xFF) continue;
158 if ((flashaddr & 2) == 0) {
159 val = (buf[i] << 8) | i;
160 } else {
161 val = val | (buf[i] << 24) | (i << 16);
162 flash_write(do_flash_cmd, flashaddr, val);
163 }
164 flashaddr += 2;
165 }
166 flashend = flashaddr;
167 if ((flashaddr & 2)) {
168 val |= 0xFFFF0000;
169 flash_write(do_flash_cmd, flashaddr, val);
170 }
171 }
172}
173
174/*
175void do_flash_cmd(volatile uint8_t *fstat)
176{
177 *fstat = 0x80;
178 while ((*fstat & 0x80) == 0) ; // wait
179}
18000000000 <do_flash_cmd>:
181 0: 2380 movs r3, #128 ; 0x80
182 2: 7003 strb r3, [r0, #0]
183 4: 7803 ldrb r3, [r0, #0]
184 6: b25b sxtb r3, r3
185 8: 2b00 cmp r3, #0
186 a: dafb bge.n 4 <do_flash_cmd+0x4>
187 c: 4770 bx lr
188*/
189
190
191uint16_t eeprom_read_word(const uint16_t *addr)
192{
193 const uint8_t *p = (const uint8_t *)addr;
194 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
195}
196
197uint32_t eeprom_read_dword(const uint32_t *addr)
198{
199 const uint8_t *p = (const uint8_t *)addr;
200 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
201 | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
202}
203
204void eeprom_read_block(void *buf, const void *addr, uint32_t len)
205{
206 const uint8_t *p = (const uint8_t *)addr;
207 uint8_t *dest = (uint8_t *)buf;
208 while (len--) {
209 *dest++ = eeprom_read_byte(p++);
210 }
211}
212
213int eeprom_is_ready(void)
214{
215 return 1;
216}
217
218void eeprom_write_word(uint16_t *addr, uint16_t value)
219{
220 uint8_t *p = (uint8_t *)addr;
221 eeprom_write_byte(p++, value);
222 eeprom_write_byte(p, value >> 8);
223}
224
225void eeprom_write_dword(uint32_t *addr, uint32_t value)
226{
227 uint8_t *p = (uint8_t *)addr;
228 eeprom_write_byte(p++, value);
229 eeprom_write_byte(p++, value >> 8);
230 eeprom_write_byte(p++, value >> 16);
231 eeprom_write_byte(p, value >> 24);
232}
233
234void eeprom_write_block(const void *buf, void *addr, uint32_t len)
235{
236 uint8_t *p = (uint8_t *)addr;
237 const uint8_t *src = (const uint8_t *)buf;
238 while (len--) {
239 eeprom_write_byte(p++, *src++);
240 }
241}