FreeCalypso > hg > freecalypso-citrine
comparison services/ffs/drv.c @ 0:75a11d740a02
initial import of gsm-fw from freecalypso-sw rev 1033:5ab737ac3ad7
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 09 Jun 2016 00:02:41 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:75a11d740a02 |
---|---|
1 /****************************************************************************** | |
2 * Flash File System (ffs) | |
3 * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com | |
4 * | |
5 * ffs low level flash driver | |
6 * | |
7 * $Id: drv.c 1.30.1.6.1.51.1.1.1.13.1.11 Tue, 06 Jan 2004 14:36:52 +0100 tsj $ | |
8 * | |
9 ******************************************************************************/ | |
10 | |
11 #include "../../include/config.h" | |
12 #include "ffs.h" | |
13 #include "drv.h" | |
14 #include "core.h" /* for FFS_BLOCKS_MAX */ | |
15 #include "ffstrace.h" | |
16 #include "intctl.h" | |
17 #include "ramffs.h" | |
18 #include <string.h> | |
19 | |
20 | |
21 /****************************************************************************** | |
22 * "Block info" stupidity | |
23 ******************************************************************************/ | |
24 | |
25 static struct block_info_s block_info[FFS_BLOCKS_MAX]; | |
26 | |
27 | |
28 /****************************************************************************** | |
29 * Macros | |
30 ******************************************************************************/ | |
31 | |
32 #define addr2offset(address) ( (int) (address) - (int) dev.base ) | |
33 | |
34 | |
35 /****************************************************************************** | |
36 * Generic Driver Functions | |
37 ******************************************************************************/ | |
38 | |
39 // Note: This function is designed for little-endian memory addressing! | |
40 void ffsdrv_write_byte(void *dst, uint8 value) | |
41 { | |
42 uint16 halfword; | |
43 | |
44 tw(tr(TR_FUNC, TrDrvWrite, "ffsdrv_write_byte(0x%05x, 0x%x)\n", | |
45 (int) (addr2offset(dst)), value)); | |
46 ttw(str(TTrDrvWrite, "wb" NL)); | |
47 | |
48 if ((int) dst & 1) | |
49 halfword = (value << 8) | *((uint8 *) dst - 1); | |
50 else | |
51 halfword = (*((uint8 *) dst + 1) << 8) | (value); | |
52 | |
53 ffsdrv.write_halfword((uint16 *) ((int) dst & ~1), halfword); | |
54 } | |
55 | |
56 void ffsdrv_generic_write(void *dst, const void *src, uint16 size) | |
57 { | |
58 uint8 *mydst = dst; | |
59 const uint8 *mysrc = src; | |
60 | |
61 if (size > 0) | |
62 { | |
63 if ((unsigned int) mydst & 1) { | |
64 ffsdrv_write_byte(mydst++, *mysrc++); | |
65 size--; | |
66 } | |
67 while (size >= 2) { | |
68 ffsdrv.write_halfword((uint16 *) mydst, | |
69 mysrc[0] | (mysrc[1] << 8)); | |
70 size -= 2; | |
71 mysrc += 2; | |
72 mydst += 2; | |
73 } | |
74 if (size == 1) | |
75 ffsdrv_write_byte(mydst++, *mysrc++); | |
76 } | |
77 } | |
78 | |
79 /****************************************************************************** | |
80 * Dummy Functions | |
81 ******************************************************************************/ | |
82 | |
83 int ffsdrv_null_init(void) | |
84 { | |
85 ttw(ttr(TTrDrvOther, "ffsdrv_null_init()" NL)); | |
86 | |
87 return 0; | |
88 } | |
89 | |
90 void ffsdrv_null_erase(uint8 block) | |
91 { | |
92 ttw(ttr(TTrDrvErase, "ffsdrv_null_erase(%d)" NL, block)); | |
93 } | |
94 | |
95 void ffsdrv_null_write_halfword(volatile uint16 *addr, uint16 value) | |
96 { | |
97 ttw(ttr(TTrDrvWrite, "ffsdrv_null_write_halfword(0x%x, 0x%x)" NL, addr, value)); | |
98 } | |
99 | |
100 void ffsdrv_null_write(void *dst, const void *src, uint16 size) | |
101 { | |
102 ttw(ttr(TTrDrvWrite, "ffsdrv_null_write(0x%x, 0x%x, %d)" NL, dst, src, size)); | |
103 } | |
104 | |
105 void ffsdrv_null_erase_suspend(void) | |
106 { | |
107 ttw(str(TTrDrvErase, "ffsdrv_null_erase_suspend()" NL)); | |
108 } | |
109 | |
110 void ffsdrv_null_erase_resume(void) | |
111 { | |
112 ttw(str(TTrDrvErase, "ffsdrv_null_erase_resume()" NL)); | |
113 } | |
114 | |
115 void ffsdrv_null_write_end(void) | |
116 { | |
117 ttw(str(TTrDrvWrite, "ffsdrv_null_write_end()" NL)); | |
118 } | |
119 | |
120 void ffsdrv_null_erase_end(void) | |
121 { | |
122 ttw(str(TTrDrvErase, "ffsdrv_null_erase_end()" NL)); | |
123 } | |
124 | |
125 /* | |
126 * FreeCalypso change from TI: we only compile one flash "driver" type | |
127 * based on the build configuration. | |
128 */ | |
129 | |
130 #if FFS_IN_RAM | |
131 | |
132 /****************************************************************************** | |
133 * RAM Family Functions | |
134 ******************************************************************************/ | |
135 | |
136 void ffsdrv_ram_write_halfword(volatile uint16 *dst, uint16 value) | |
137 { | |
138 *dst = value; | |
139 } | |
140 | |
141 #if 0 | |
142 /* duplicates ffsdrv_generic_write */ | |
143 void ffsdrv_ram_write(void *dst, const void *src, uint16 size) | |
144 { | |
145 uint8 *mydst = dst; | |
146 const uint8 *mysrc = src; | |
147 | |
148 if (size == 0) | |
149 return; | |
150 else if (size == 1) | |
151 ffsdrv_write_byte(mydst, *mysrc); | |
152 else { | |
153 if ((int) mydst & 1) { | |
154 ffsdrv_write_byte(mydst++, *mysrc++); | |
155 size--; | |
156 } | |
157 while (size >= 2) { | |
158 ffsdrv_ram_write_halfword((uint16 *) mydst, mysrc[0]|(mysrc[1] << 8)); | |
159 size -= 2; | |
160 mysrc += 2; | |
161 mydst += 2; | |
162 } | |
163 if (size == 1) | |
164 ffsdrv_write_byte(mydst++, *mysrc++); | |
165 } | |
166 } | |
167 #endif | |
168 | |
169 void ffsdrv_ram_erase(uint8 block) | |
170 { | |
171 int i; | |
172 char *addr; | |
173 | |
174 addr = block2addr(block); | |
175 | |
176 for (i = 0; i < (1 << dev.binfo[block].size_ld); i++) { | |
177 *addr++ = 0xFF; | |
178 } | |
179 } | |
180 | |
181 const struct ffsdrv_s ffsdrv = { | |
182 ffsdrv_null_init, | |
183 ffsdrv_ram_erase, | |
184 ffsdrv_ram_write_halfword, | |
185 ffsdrv_generic_write, | |
186 ffsdrv_null_write_end, | |
187 ffsdrv_null_erase_suspend, | |
188 ffsdrv_null_erase_resume | |
189 }; | |
190 | |
191 #elif CONFIG_FLASH_WRITE | |
192 | |
193 #if FLASH_IS_AMD_MULTIBANK | |
194 | |
195 /****************************************************************************** | |
196 * AMD Dual/Multi Bank Driver Functions | |
197 ******************************************************************************/ | |
198 | |
199 // All erase and write operations are performed atomically (interrupts | |
200 // disabled). Otherwise we cannot trust the value of dev.state and we cannot | |
201 // determine exactly how many of the command words have already been | |
202 // written. | |
203 | |
204 // in ffs_end() when we resume an erasure that was previously suspended, how | |
205 // does that affect multiple tasks doing that simultaneously? | |
206 | |
207 void ffsdrv_amd_write_end(void); | |
208 void ffsdrv_amd_erase_end(void); | |
209 | |
210 void ffsdrv_amd_write_halfword(volatile uint16 *addr, uint16 value) | |
211 { | |
212 volatile uint16 *flash = (volatile uint16 *)dev.base; | |
213 uint32 cpsr; | |
214 | |
215 tlw(led_on(LED_WRITE)); | |
216 ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value)); | |
217 | |
218 dev.addr = addr; | |
219 dev.data = value; | |
220 | |
221 if (~*addr & value) { | |
222 ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value)); | |
223 return; | |
224 } | |
225 | |
226 cpsr = int_disable(); | |
227 tlw(led_toggle(LED_WRITE_SUSPEND)); | |
228 dev.state = DEV_WRITE; | |
229 flash[0x555] = 0xAA; // unlock cycle 1 | |
230 flash[0x2AA] = 0x55; // unlock cycle 2 | |
231 flash[0x555] = 0xA0; | |
232 *addr = value; | |
233 int_enable(cpsr); | |
234 tlw(led_toggle(LED_WRITE_SUSPEND)); | |
235 | |
236 ffsdrv_amd_write_end(); | |
237 } | |
238 | |
239 #if 0 | |
240 /* duplicates ffsdrv_generic_write */ | |
241 void ffsdrv_amd_write(void *dst, const void *src, uint16 size) | |
242 { | |
243 uint8 *mydst = dst; | |
244 const uint8 *mysrc = src; | |
245 | |
246 if (size > 0) | |
247 { | |
248 if ((unsigned int) mydst & 1) { | |
249 ffsdrv_write_byte(mydst++, *mysrc++); | |
250 size--; | |
251 } | |
252 while (size >= 2) { | |
253 ffsdrv_amd_write_halfword((uint16 *) mydst, | |
254 mysrc[0] | (mysrc[1] << 8)); | |
255 size -= 2; | |
256 mysrc += 2; | |
257 mydst += 2; | |
258 } | |
259 if (size == 1) | |
260 ffsdrv_write_byte(mydst++, *mysrc++); | |
261 } | |
262 } | |
263 #endif | |
264 | |
265 void ffsdrv_amd_write_end(void) | |
266 { | |
267 while ((*dev.addr ^ dev.data) & 0x80) | |
268 tlw(led_toggle(LED_WRITE_SUSPEND)); | |
269 | |
270 dev.state = DEV_READ; | |
271 | |
272 tlw(led_off(LED_WRITE)); | |
273 } | |
274 | |
275 void ffsdrv_amd_erase(uint8 block) | |
276 { | |
277 volatile uint16 *flash = (volatile uint16 *)dev.base; | |
278 uint32 cpsr; | |
279 | |
280 tlw(led_on(LED_ERASE)); | |
281 ttw(ttr(TTrDrvErase, "e(%d)" NL, block)); | |
282 | |
283 dev.addr = (uint16 *) block2addr(block); | |
284 | |
285 cpsr = int_disable(); | |
286 dev.state = DEV_ERASE; | |
287 flash[0x555] = 0xAA; // unlock cycle 1 | |
288 flash[0x2AA] = 0x55; // unlock cycle 2 | |
289 flash[0x555] = 0x80; | |
290 flash[0x555] = 0xAA; // unlock cycle 1 | |
291 flash[0x2AA] = 0x55; // unlock cycle 2 | |
292 *dev.addr = 0x30; // AMD erase sector command | |
293 int_enable(cpsr); | |
294 | |
295 ffsdrv_amd_erase_end(); | |
296 } | |
297 | |
298 void ffsdrv_amd_erase_end(void) | |
299 { | |
300 while ((*dev.addr & 0x80) == 0) | |
301 ; | |
302 | |
303 dev.state = DEV_READ; | |
304 | |
305 tlw(led_off(LED_ERASE)); | |
306 } | |
307 | |
308 void ffsdrv_amd_erase_suspend(void) | |
309 { | |
310 uint32 cpsr; | |
311 | |
312 tlw(led_on(LED_ERASE_SUSPEND)); | |
313 ttw(str(TTrDrvErase, "es" NL)); | |
314 | |
315 // if erase has finished then all is ok | |
316 if (*dev.addr & 0x80) { | |
317 ffsdrv_amd_erase_end(); | |
318 tlw(led_off(LED_ERASE_SUSPEND)); | |
319 return; | |
320 } | |
321 | |
322 // NOTEME: As there is no way to be absolutely certain that erase | |
323 // doesn't finish between last poll and the following erase suspend | |
324 // command, we assume that the erase suspend is safe even though the | |
325 // erase IS actually already finished. | |
326 | |
327 cpsr = int_disable(); | |
328 dev.state = DEV_ERASE_SUSPEND; | |
329 *dev.addr = 0xB0; | |
330 | |
331 // Wait for erase suspend to finish | |
332 while ((*dev.addr & 0x80) == 0) | |
333 ; | |
334 | |
335 int_enable(cpsr); | |
336 } | |
337 | |
338 void ffsdrv_amd_erase_resume(void) | |
339 { | |
340 uint32 cpsr; | |
341 | |
342 ttw(str(TTrDrvErase, "er" NL)); | |
343 | |
344 // NOTEME: See note in erase_suspend()... We assume that the erase | |
345 // resume is safe even though the erase IS actually already finished. | |
346 cpsr = int_disable(); | |
347 dev.state = DEV_ERASE; | |
348 *dev.addr = 0x30; | |
349 int_enable(cpsr); | |
350 | |
351 tlw(led_off(LED_ERASE_SUSPEND)); | |
352 } | |
353 | |
354 const struct ffsdrv_s ffsdrv = { | |
355 ffsdrv_null_init, | |
356 ffsdrv_amd_erase, | |
357 ffsdrv_amd_write_halfword, | |
358 ffsdrv_generic_write, | |
359 ffsdrv_amd_write_end, | |
360 ffsdrv_amd_erase_suspend, | |
361 ffsdrv_amd_erase_resume | |
362 }; | |
363 | |
364 #elif FLASH_IS_INTEL_ONEBANK | |
365 | |
366 extern int ffsdrv_ram_intel_sb_init(void); | |
367 extern void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, | |
368 uint16 value); | |
369 extern void ffsdrv_ram_intel_sb_erase(uint8 block); | |
370 | |
371 const struct ffsdrv_s ffsdrv = { | |
372 ffsdrv_ram_intel_sb_init, | |
373 ffsdrv_ram_intel_sb_erase, | |
374 ffsdrv_ram_intel_sb_write_halfword, | |
375 ffsdrv_generic_write, | |
376 ffsdrv_null_write_end, | |
377 ffsdrv_null_erase_suspend, | |
378 ffsdrv_null_erase_resume | |
379 }; | |
380 | |
381 #else | |
382 | |
383 #error "Flash hardware type unknown" | |
384 | |
385 #endif /* flash hardware type */ | |
386 | |
387 #else | |
388 | |
389 /* | |
390 * This part will get compiled if we have real FFS (FFS_IN_RAM=0), | |
391 * but not allowed to write to flash (CONFIG_FLASH_WRITE=0). | |
392 */ | |
393 | |
394 const struct ffsdrv_s ffsdrv = { | |
395 ffsdrv_null_init, | |
396 ffsdrv_null_erase, | |
397 ffsdrv_null_write_halfword, | |
398 ffsdrv_null_write, | |
399 ffsdrv_null_write_end, | |
400 ffsdrv_null_erase_suspend, | |
401 ffsdrv_null_erase_resume | |
402 }; | |
403 | |
404 #endif | |
405 | |
406 | |
407 /****************************************************************************** | |
408 * Initialization | |
409 * | |
410 * Significantly simplified in FreeCalypso. | |
411 * | |
412 ******************************************************************************/ | |
413 | |
414 effs_t ffsdrv_init(void) | |
415 { | |
416 int error; | |
417 unsigned i; | |
418 uint32 offset; | |
419 | |
420 tw(tr(TR_BEGIN, TrDrvInit, "drv_init() {\n")); | |
421 ttw(str(TTrDrvOther, "ffsdrv_init() {" NL)); | |
422 | |
423 dev.state = DEV_READ; | |
424 dev.atomlog2 = FFS_ATOM_LOG2; | |
425 dev.atomsize = 1 << dev.atomlog2; | |
426 dev.atomnotmask = dev.atomsize - 1; | |
427 | |
428 offset = 0; | |
429 for (i = 0; i < dev.numblocks; i++) { | |
430 block_info[i].offset = offset; | |
431 block_info[i].size_ld = dev.blocksize_ld; | |
432 offset += dev.blocksize; | |
433 } | |
434 dev.binfo = block_info; | |
435 | |
436 error = ffsdrv.init(); | |
437 | |
438 tw(tr(TR_FUNC, TrDrvInit, "dev.binfo = 0x%x\n", (unsigned int) dev.binfo)); | |
439 tw(tr(TR_FUNC, TrDrvInit, "dev.base = 0x%x\n", (unsigned int) dev.base)); | |
440 tw(tr(TR_FUNC, TrDrvInit, "dev.numblocks = %d\n", dev.numblocks)); | |
441 tw(tr(TR_FUNC, TrDrvInit, "dev.blocksize = %d\n", dev.blocksize)); | |
442 tw(tr(TR_FUNC, TrDrvInit, "dev.atomlog2/atomsize/atomnotmask = %d/%d/%x\n", | |
443 dev.atomlog2, dev.atomsize, dev.atomnotmask)); | |
444 tw(tr(TR_END, TrDrvInit, "} %d\n", error)); | |
445 ttw(ttr(TTrDrvOther, "} %d" NL, error)); | |
446 | |
447 return error; | |
448 } |