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