|
1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // ubootldr\flash_nor.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #define FILE_ID 0x464C5348 |
|
19 |
|
20 #include "bootldr.h" |
|
21 #include "ubootldrldd.h" |
|
22 #include <e32std.h> |
|
23 #include <e32std_private.h> |
|
24 #include <e32svr.h> |
|
25 #include <e32cons.h> |
|
26 #include <f32file.h> |
|
27 #include <hal.h> |
|
28 #include <u32hal.h> |
|
29 #include "flash_nor.h" |
|
30 |
|
31 const TUint KFlashRetries = 1000000; |
|
32 |
|
33 #ifdef __SUPPORT_FLASH_REPRO__ |
|
34 _LIT(KLitThreadName,"Flash"); |
|
35 |
|
36 TLinAddr FlashImageAddr; |
|
37 TUint32 FlashImageSize; |
|
38 TUint32 * FlashAddress; |
|
39 |
|
40 volatile TUint32 Available; |
|
41 volatile TBool Complete; |
|
42 |
|
43 #define addr_to_page(a) (a&~(0x1000-1)) |
|
44 #define addr_pageoff(a) (a&(0x1000-1)) |
|
45 |
|
46 // Memory |
|
47 RUBootldrLdd LddFlash; |
|
48 RChunk TheFlashChunk; |
|
49 |
|
50 TUint FlashId = FLASH_TYPE_UNKNOWN; |
|
51 |
|
52 |
|
53 #define PRINTF(x) |
|
54 #define SPANSION_PRINTF(x) |
|
55 #define TYAX_PRINTF(x) |
|
56 #define WRITE_PRINTF(x) |
|
57 |
|
58 // Reset prototypes |
|
59 TInt cfiReset (TUint32 flashId, TUint32 address); |
|
60 TInt tyaxReset(TUint32 flashId, TUint32 address); |
|
61 |
|
62 // Erase prototypes |
|
63 TInt spansionErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize); |
|
64 TInt tyaxErase (TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize); |
|
65 |
|
66 // Write prototypes |
|
67 TInt spansionWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS); |
|
68 TInt tyaxWrite (TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS); |
|
69 |
|
70 /////////////////////////////////////////////////////////////////////////////// |
|
71 // |
|
72 // FLASH INFO |
|
73 // |
|
74 // This table holds all the information we have about supported flash devices |
|
75 // |
|
76 /////////////////////////////////////////////////////////////////////////////// |
|
77 const TFlashInfo flashInfo [] = |
|
78 { |
|
79 // Description Manufacturer ID Device ID Reset fn Erase fn Write fn Comments |
|
80 {_L(""), CFI_MANUF_ANY, CFI_DEV_ANY, cfiReset, NULL, NULL, }, // This is the catch-all entry in case we aren't initialised |
|
81 |
|
82 // {_L("Spansion xyz"), CFI_MANUF_SPANSION, CFI_DEV_xyz, xyzReset, xyzErase, xyzWrite, }, // Put new Spansion flash types here, before the CFI_DEV_ANY, or they won't get detected |
|
83 {_L("Spansion S29GL512N"), CFI_MANUF_SPANSION, CFI_DEV_S29GL512N, cfiReset, spansionErase, spansionWrite, }, // NaviEngine Rev B & C |
|
84 {_L("Spansion Generic"), CFI_MANUF_SPANSION, CFI_DEV_ANY, cfiReset, spansionErase, spansionWrite, }, // Generic Spansion flash types |
|
85 |
|
86 // {_L("Intel xyz"), CFI_MANUF_INTEL, CFI_DEV_xyz, xyzReset, xyzErase, xyzWrite, }, // Put new Intel flash types here, before the CFI_DEV_ANY, or they won't get detected |
|
87 {_L("Intel Sibley"), CFI_MANUF_INTEL, CFI_DEV_SIBLEY, tyaxReset, tyaxErase, tyaxWrite, }, // H4 with Intel Tyax flash parts |
|
88 {_L("Intel 28F256L18T"), CFI_MANUF_INTEL, CFI_DEV_28F256L18T, tyaxReset, tyaxErase, tyaxWrite, }, // H4 with Intel Tyax flash parts |
|
89 {_L("Intel Tyax"), CFI_MANUF_INTEL, CFI_DEV_ANY, tyaxReset, tyaxErase, tyaxWrite, }, // Generic Intel Tyax flash support |
|
90 |
|
91 // End Of Table - no more entries after here |
|
92 {_L(""), 0, 0, NULL, NULL, NULL } // NULL entry used to mark end of table |
|
93 }; |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 /////////////////////////////////////////////////////////////////////////////// |
|
100 // CFI Commands |
|
101 /////////////////////////////////////////////////////////////////////////////// |
|
102 // Query |
|
103 const TCfiCommands CfiQuery [] = |
|
104 { |
|
105 {CFI_BASE8, 0xAAA, 0xAA}, |
|
106 {CFI_BASE8, 0x555, 0x55}, |
|
107 {CFI_BASE8, 0xAAA, 0x90}, |
|
108 |
|
109 {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command |
|
110 }; |
|
111 |
|
112 // Erase |
|
113 const TCfiCommands CfiErase [] = |
|
114 { |
|
115 {CFI_BASE8, 0xAAA, 0xAA}, |
|
116 {CFI_BASE8, 0x555, 0x55}, |
|
117 {CFI_BASE8, 0xAAA, 0x80}, |
|
118 {CFI_BASE8, 0xAAA, 0xAA}, |
|
119 {CFI_BASE8, 0x555, 0x55}, |
|
120 {CFI_SECTOR8, 0x000, 0x30}, |
|
121 |
|
122 {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command |
|
123 }; |
|
124 |
|
125 // Write |
|
126 const TCfiCommands CfiWrite [] = |
|
127 { |
|
128 {CFI_BASE8, 0xAAA, 0xAA}, |
|
129 {CFI_BASE8, 0x555, 0x55}, |
|
130 {CFI_BASE8, 0xAAA, 0xA0}, |
|
131 |
|
132 {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command |
|
133 }; |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 /////////////////////////////////////////////////////////////////////////////// |
|
141 // |
|
142 // CFI Command execution |
|
143 // |
|
144 // CFI implements a generic set of commands that can be used on all CFI flash |
|
145 // parts. |
|
146 // |
|
147 // The commands usually write to the base address of the device + an offset, |
|
148 // or to the sector/block address for some commands. |
|
149 // |
|
150 /////////////////////////////////////////////////////////////////////////////// |
|
151 TInt CfiCommand(TUint32 base, TUint32 sector, const TCfiCommands * commands) |
|
152 { |
|
153 if (commands != NULL) |
|
154 { |
|
155 const TCfiCommands * pCmd = commands; |
|
156 while (pCmd->location != CFI_END) |
|
157 { |
|
158 switch (pCmd->location) |
|
159 { |
|
160 case CFI_BASE8: |
|
161 { |
|
162 *(volatile TUint8*)(base + pCmd->offset) = pCmd->command; |
|
163 } |
|
164 break; |
|
165 case CFI_SECTOR8: |
|
166 { |
|
167 *(volatile TUint8*)(sector + pCmd->offset) = pCmd->command; |
|
168 } |
|
169 break; |
|
170 default: |
|
171 return KErrNotSupported; |
|
172 } |
|
173 pCmd++; |
|
174 } |
|
175 } |
|
176 return KErrNone; |
|
177 } |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 /////////////////////////////////////////////////////////////////////////////// |
|
183 // |
|
184 // TYAX specific routines |
|
185 // |
|
186 /////////////////////////////////////////////////////////////////////////////// |
|
187 // Clear the status register |
|
188 /////////////////////////////////////////////////////////////////////////////// |
|
189 void tyaxClearStatus(TUint32 address) |
|
190 { |
|
191 volatile TUint16 *p = (TUint16 *)address; |
|
192 *p=KCmdClearStatus; // clear status reg |
|
193 } |
|
194 |
|
195 /////////////////////////////////////////////////////////////////////////////// |
|
196 // Wait until cmd completes |
|
197 /////////////////////////////////////////////////////////////////////////////// |
|
198 void tyaxWaitUntilReady(TUint32 address, TUint16 cmd) |
|
199 { |
|
200 volatile TUint16 *pF = (TUint16 *)address; |
|
201 TUint16 s=0; |
|
202 TInt i=KFlashRetries; |
|
203 |
|
204 for (; i>0 && ((s&KStatusBusy)!=KStatusBusy); --i) // check ready bit |
|
205 { |
|
206 *pF=cmd; |
|
207 s=*pF; |
|
208 } |
|
209 if (i==0) |
|
210 { |
|
211 PrintToScreen(_L("Write timed out")); |
|
212 BOOT_FAULT(); |
|
213 } |
|
214 if (s&KStatusCmdSeqError) |
|
215 { |
|
216 PrintToScreen(_L("Write error s=%x pF=0x%x\n"), s, pF); |
|
217 } |
|
218 } |
|
219 |
|
220 /////////////////////////////////////////////////////////////////////////////// |
|
221 // Unlock Flash |
|
222 /////////////////////////////////////////////////////////////////////////////// |
|
223 void tyaxUnlock(TUint32 address) |
|
224 { |
|
225 TYAX_PRINTF(RDebug::Printf("tyaxUnlock(0x%08x)", address)); |
|
226 TUint16 * pF = (TUint16*)address; |
|
227 // Unlock |
|
228 *pF=KCmdClearBlockLockBit1; |
|
229 *pF=KCmdClearBlockLockBit2; |
|
230 } |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 /////////////////////////////////////////////////////////////////////////////// |
|
245 // |
|
246 // GENERIC - implementations of the generic routines |
|
247 // |
|
248 // - reset |
|
249 // - erase |
|
250 // - write |
|
251 // |
|
252 /////////////////////////////////////////////////////////////////////////////// |
|
253 // Reset Flash |
|
254 /////////////////////////////////////////////////////////////////////////////// |
|
255 TInt cfiReset(TUint32 flashId, TUint32 address) |
|
256 { |
|
257 SPANSION_PRINTF(RDebug::Printf("cfiReset(0x%08x)", address)); |
|
258 |
|
259 volatile TUint8 * p = (TUint8*)address; |
|
260 *(p)=0xF0; // reset spansion flash |
|
261 return KErrNone; |
|
262 } |
|
263 |
|
264 /////////////////////////////////////////////////////////////////////////////// |
|
265 // Reset Flash |
|
266 /////////////////////////////////////////////////////////////////////////////// |
|
267 TInt tyaxReset(TUint32 flashId, TUint32 address) |
|
268 { |
|
269 TYAX_PRINTF(RDebug::Printf("tyaxReset(0x%08x)", address)); |
|
270 |
|
271 TUint16 * p = (TUint16*)address; |
|
272 |
|
273 // clear the status register |
|
274 tyaxClearStatus((TUint32)address); |
|
275 |
|
276 // write to linear base and set strataflash into readarray mode |
|
277 *p=KCmdReadArrayMode; |
|
278 return KErrNone; |
|
279 } |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 /////////////////////////////////////////////////////////////////////////////// |
|
285 // Erase a block of flash |
|
286 /////////////////////////////////////////////////////////////////////////////// |
|
287 TInt spansionErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize) |
|
288 { |
|
289 SPANSION_PRINTF(RDebug::Printf("spansionErase 0x%08x", anAddr)); |
|
290 |
|
291 volatile TUint32 base=anAddr&~(KFlashEraseBlockSize-1); // round base address down to block |
|
292 volatile TUint32 end=anAddr+aSize; |
|
293 end=(end+KFlashEraseBlockSize-1)&~(KFlashEraseBlockSize-1); // round end address up to block |
|
294 TUint32 size=end-base; |
|
295 volatile TUint8* p=(volatile TUint8*)base; |
|
296 |
|
297 SPANSION_PRINTF(RDebug::Printf("Erase anAddr=0x%08x, aSize=0x%08x, base=0x%08x, end=0x%08x, size=0x%08x, p=0x%08x", anAddr, aSize, base, end, size, p)); |
|
298 |
|
299 cfiReset(flashId, aBase); |
|
300 for (; size; size-=KFlashEraseBlockSize, p+=(KFlashEraseBlockSize>>1)) |
|
301 { |
|
302 CfiCommand(aBase, base, CfiErase); |
|
303 |
|
304 TUint retries = KFlashRetries; |
|
305 while ((*(volatile TUint8*)anAddr != 0xFF) && (retries != 0)) |
|
306 { |
|
307 retries--; |
|
308 } |
|
309 if (retries==0) |
|
310 { |
|
311 RDebug::Printf("Erase Failed anAddr=0x%08x, aSize=0x%08x, base=0x%08x, end=0x%08x, size=0x%08x, p=0x%08x", anAddr, aSize, base, end, size, p); |
|
312 } |
|
313 cfiReset(flashId, aBase); |
|
314 } |
|
315 return 0; |
|
316 } |
|
317 |
|
318 |
|
319 /////////////////////////////////////////////////////////////////////////////// |
|
320 // Erase a block of flash |
|
321 /////////////////////////////////////////////////////////////////////////////// |
|
322 TInt tyaxErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize) |
|
323 { |
|
324 TUint32 base=anAddr&~(KFlashEraseBlockSize-1); // round base address down to block |
|
325 TUint32 end=anAddr+aSize; |
|
326 end=(end+KFlashEraseBlockSize-1)&~(KFlashEraseBlockSize-1); // round end address up to block |
|
327 TUint32 size=end-base; |
|
328 volatile TUint16* p=(volatile TUint16*)base; |
|
329 |
|
330 // write to linear base and set strataflash into readarray mode |
|
331 *p=KCmdReadArrayMode; |
|
332 // clear the status register |
|
333 *p=KCmdClearStatus; |
|
334 for (; size; size-=KFlashEraseBlockSize, p+=(KFlashEraseBlockSize>>1)) |
|
335 { |
|
336 // Unlock |
|
337 *p=KCmdClearBlockLockBit1; |
|
338 *p=KCmdClearBlockLockBit2; |
|
339 // Erase |
|
340 *p=KCmdBlockErase1; // block erase |
|
341 *p=KCmdBlockErase2; // block erase confirm |
|
342 |
|
343 // wait for the erase to finish |
|
344 while ((*p & KStatusBusy)!=KStatusBusy); |
|
345 |
|
346 // put the flash block back to normal |
|
347 TUint32 s=*p; |
|
348 *p=KCmdClearStatus; // clear status reg |
|
349 *p=KCmdReadArrayMode; |
|
350 |
|
351 if (s & KStatusLockBitError) |
|
352 { |
|
353 // error |
|
354 RDebug::Printf("Erase Failed: addr:0x%x status: 0x%x", p, s); |
|
355 return (TUint32)p-anAddr+1; |
|
356 } |
|
357 } |
|
358 return 0; |
|
359 } |
|
360 |
|
361 |
|
362 /////////////////////////////////////////////////////////////////////////////// |
|
363 // Write a block of flash |
|
364 /////////////////////////////////////////////////////////////////////////////// |
|
365 TInt spansionWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS) |
|
366 // Assume aSize <= KFlashWriteBufSize |
|
367 { |
|
368 SPANSION_PRINTF(WRITE_PRINTF(RDebug::Printf("spansionWrite anAddr=0x%08x, aSize=0x%08x", anAddr, aSize))); |
|
369 |
|
370 volatile TUint8 * base = (TUint8 *)FlashAddress; |
|
371 volatile TUint16 * pDest = (TUint16*)anAddr; |
|
372 volatile TUint16 * pSrc = (TUint16*)aPS; |
|
373 volatile TUint16 * pEnd = (TUint16*)(anAddr+aSize); |
|
374 |
|
375 for (; pDest < pEnd; pDest++, pSrc++) |
|
376 { |
|
377 CfiCommand((TUint32)base, (TUint32)base, CfiWrite); |
|
378 *pDest = *pSrc; |
|
379 |
|
380 TUint retries = KFlashRetries; |
|
381 while ((*pDest != *pSrc) && (retries != 0)) |
|
382 { |
|
383 retries--; |
|
384 } |
|
385 |
|
386 if (*pDest != *pSrc) |
|
387 { |
|
388 RDebug::Printf("Write failed 0x%x=0x%x == 0x%x", pDest, *pSrc, *pDest); |
|
389 return 1; |
|
390 } |
|
391 } |
|
392 return 0; |
|
393 } |
|
394 |
|
395 /////////////////////////////////////////////////////////////////////////////// |
|
396 // Write a block of flash |
|
397 /////////////////////////////////////////////////////////////////////////////// |
|
398 // Assume aSize <= KFlashWriteBufSize |
|
399 TInt tyaxWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS) |
|
400 { |
|
401 TYAX_PRINTF(WRITE_PRINTF(RDebug::Printf("tyaxWrite anAddr=0x%08x, aSize=0x%08x", anAddr, aSize))); |
|
402 |
|
403 volatile TUint16* pF=(volatile TUint16*)anAddr; |
|
404 |
|
405 tyaxUnlock(anAddr); |
|
406 tyaxClearStatus(anAddr); |
|
407 |
|
408 if (flashInfo[flashId].deviceId == CFI_DEV_SIBLEY) |
|
409 { |
|
410 tyaxWaitUntilReady(anAddr, KCmdWriteStatusSibley); |
|
411 } |
|
412 else |
|
413 { |
|
414 tyaxWaitUntilReady(anAddr, KCmdWriteStatus); |
|
415 } |
|
416 |
|
417 // convert to words - 1 |
|
418 TInt16 l=(aSize>>1)-1; |
|
419 *pF=l; // Write no of words |
|
420 const TUint16* pS=(const TUint16*)aPS; |
|
421 for (;l>=0;l--) |
|
422 { |
|
423 *pF++=*pS++; |
|
424 } |
|
425 pF=(volatile TUint16*)anAddr; |
|
426 *pF=0xD0; // Confirm |
|
427 |
|
428 tyaxWaitUntilReady(anAddr, KCmdReadStatus); |
|
429 tyaxReset(flashId, anAddr); |
|
430 |
|
431 return 0; |
|
432 } |
|
433 |
|
434 |
|
435 |
|
436 |
|
437 |
|
438 |
|
439 |
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 /////////////////////////////////////////////////////////////////////////////// |
|
446 // |
|
447 // WRAPPERS |
|
448 // |
|
449 // A top level routine to prevent each function checking the flash type |
|
450 // |
|
451 /////////////////////////////////////////////////////////////////////////////// |
|
452 TInt flashReset(TUint32 flashId, TUint32 address) |
|
453 { |
|
454 PRINTF(RDebug::Printf("flashReset()")); |
|
455 |
|
456 TInt retVal = KErrNotSupported; |
|
457 |
|
458 if (flashInfo[flashId].reset != NULL) |
|
459 { |
|
460 retVal = flashInfo[flashId].reset(flashId, address); |
|
461 } |
|
462 |
|
463 return retVal; |
|
464 } |
|
465 |
|
466 TInt flashErase(TUint32 flashId, TUint32 base, TUint32 address, TUint32 size) |
|
467 { |
|
468 PRINTF(RDebug::Printf("flashErase()")); |
|
469 |
|
470 TInt retVal = KErrNone; |
|
471 |
|
472 if (flashInfo[flashId].erase != NULL) |
|
473 { |
|
474 retVal = flashInfo[flashId].erase(flashId, base, address, size); |
|
475 } |
|
476 |
|
477 return retVal; |
|
478 } |
|
479 |
|
480 TInt flashWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS) |
|
481 { |
|
482 WRITE_PRINTF(RDebug::Printf("flashWrite()")); |
|
483 |
|
484 TInt retVal = KErrNone; |
|
485 |
|
486 if (flashInfo[flashId].write != NULL) |
|
487 { |
|
488 retVal = flashInfo[flashId].write(flashId, anAddr, aSize, aPS); |
|
489 } |
|
490 |
|
491 return retVal; |
|
492 } |
|
493 |
|
494 |
|
495 /////////////////////////////////////////////////////////////////////////////// |
|
496 // |
|
497 // Flash ID |
|
498 // |
|
499 // Identify the flash part at the given address |
|
500 // returns an index into the flashInfo structure |
|
501 /////////////////////////////////////////////////////////////////////////////// |
|
502 TInt flashId(TUint32 address) |
|
503 { |
|
504 TUint deviceIndex = FLASH_TYPE_UNKNOWN; |
|
505 |
|
506 volatile TUint16* p16=(volatile TUint16*)address; // used for 16 bit read/write to the flash |
|
507 |
|
508 // Put flash into CFI query mode using 8 bit writes |
|
509 CfiCommand(address, address, CfiQuery); |
|
510 |
|
511 // Read ID codes using 16 bit reads |
|
512 // if we ever need to support 8 bit devices, we may need to change this to 2 x 8 bit reads per attribute |
|
513 TUint16 manufacturerId = *(p16 ); |
|
514 TUint16 deviceId = *(p16+1); |
|
515 |
|
516 for (TUint32 i=0; flashInfo[i].manufacturerId !=0; i++) |
|
517 { |
|
518 PRINTF(RDebug::Printf("Check device: M 0x%04x D 0x%04x", flashInfo[i].manufacturerId, flashInfo[i].deviceId)); |
|
519 |
|
520 if ( ( flashInfo[i].manufacturerId == manufacturerId) |
|
521 && ( (flashInfo[i].deviceId == CFI_DEV_ANY ) // support generic flash devices |
|
522 ||(flashInfo[i].deviceId == deviceId ) |
|
523 ) |
|
524 ) |
|
525 { |
|
526 PRINTF(RDebug::Print(_L("Found device: %s (Manufacturer=%x Device=%x)"), flashInfo[i].name.Ptr(), flashInfo[i].manufacturerId, flashInfo[i].deviceId)); |
|
527 deviceIndex = i; |
|
528 break; |
|
529 } |
|
530 } |
|
531 if (deviceIndex == FLASH_TYPE_UNKNOWN) |
|
532 { |
|
533 RDebug::Printf("Flash type unknown: Manufacturer ID = %04x, Device ID = %04x", manufacturerId, deviceId ); |
|
534 } |
|
535 flashReset(deviceIndex, (TUint32)FlashAddress); |
|
536 return deviceIndex; |
|
537 } |
|
538 |
|
539 |
|
540 /////////////////////////////////////////////////////////////////////////////// |
|
541 /////////////////////////////////////////////////////////////////////////////// |
|
542 |
|
543 |
|
544 |
|
545 |
|
546 |
|
547 GLDEF_C TUint32 * GetFlashChunk() |
|
548 { |
|
549 // return if already initialised |
|
550 if (FlashAddress != NULL) |
|
551 return FlashAddress; |
|
552 |
|
553 TInt r = User::LoadLogicalDevice(KBootldrLddName); |
|
554 |
|
555 r = LddFlash.Open(); |
|
556 if (r!=KErrNone) |
|
557 { |
|
558 PrintToScreen(_L("FAULT due to LddFlash open\r\n")); |
|
559 BOOT_FAULT(); |
|
560 } |
|
561 |
|
562 TUint8* kernelAddress; |
|
563 r=LddFlash.CreateChunk(KNORFlashTargetSize,(TAny**)&kernelAddress); |
|
564 if (r!=KErrNone) |
|
565 { |
|
566 PrintToScreen(_L("FAULT due to chunk create\r\n")); |
|
567 BOOT_FAULT(); |
|
568 } |
|
569 |
|
570 // If we're running from RAM flash will be in a different place... |
|
571 r = LddFlash.CommitMemory(KNORFlashTargetSize,addr_to_page(KNORFlashTargetAddr)); |
|
572 if (r!=KErrNone) |
|
573 { |
|
574 PrintToScreen(_L("FAULT due to commit\r\n")); |
|
575 BOOT_FAULT(); |
|
576 } |
|
577 |
|
578 r = LddFlash.GetChunkHandle(TheFlashChunk); |
|
579 if (r!=KErrNone) |
|
580 { |
|
581 PrintToScreen(_L("FAULT due to handle\r\n")); |
|
582 BOOT_FAULT(); |
|
583 } |
|
584 |
|
585 TUint8* Base = TheFlashChunk.Base(); |
|
586 FlashAddress = (TUint32*)Base; |
|
587 FlashId = flashId((TUint32)FlashAddress); |
|
588 |
|
589 return FlashAddress; |
|
590 } |
|
591 |
|
592 GLDEF_C void NotifyDataAvailable(TInt aTotalAmount) |
|
593 { |
|
594 Available=(TUint32)aTotalAmount; |
|
595 } |
|
596 |
|
597 GLDEF_C void NotifyDownloadComplete() |
|
598 { |
|
599 Complete=ETrue; |
|
600 } |
|
601 |
|
602 GLDEF_C TBool BlankCheck(TUint32 anAddr, TUint32 aSize) |
|
603 { |
|
604 const TUint16* p=(const TUint16*)anAddr; |
|
605 const TUint16* pE=p+(aSize>>1); |
|
606 TBool rv=ETrue; |
|
607 |
|
608 while(p<pE) |
|
609 { |
|
610 if (*p!=0xffff) |
|
611 { |
|
612 PRINTF(RDebug::Printf("BlankCheck %x is not blank! anAddr=0x%08x, aSize=0x%08x, p=0x%08x, *p=0x%08x", anAddr, anAddr, aSize, (TUint32)p, (TUint32)*p)); |
|
613 rv=EFalse; |
|
614 break; |
|
615 } |
|
616 p++; |
|
617 } |
|
618 if (rv) |
|
619 { |
|
620 PRINTF(RDebug::Printf("BlankCheck: %x is blank", anAddr)); |
|
621 } |
|
622 return rv; |
|
623 } |
|
624 |
|
625 /////////////////////////////////////////////////////////////////////////////// |
|
626 // |
|
627 // Erase |
|
628 // |
|
629 // This function is used by the variant code. The variant code shouldn't care |
|
630 // about the Flash ID, so I've left this function here as a wrapper for the |
|
631 // internal flashErase function, passing in a nasty global variable containing |
|
632 // the Flash ID. |
|
633 // |
|
634 /////////////////////////////////////////////////////////////////////////////// |
|
635 GLDEF_C TInt Erase(TUint32 anAddr, TUint32 aSize) |
|
636 { |
|
637 flashErase(FlashId, (TUint32)FlashAddress, anAddr, aSize); |
|
638 return 0; |
|
639 } |
|
640 |
|
641 |
|
642 /////////////////////////////////////////////////////////////////////////////// |
|
643 // |
|
644 // Write |
|
645 // |
|
646 // This function is used by the variant code. As well as the Flash ID comment |
|
647 // from above (see Erase), the variant shouldn't have to care about internal |
|
648 // buffer sizes, etc. |
|
649 // |
|
650 /////////////////////////////////////////////////////////////////////////////// |
|
651 GLDEF_C TInt Write(TUint32 anAddr, TUint32 aSize, const TUint32* aPS) |
|
652 { |
|
653 TInt rv=0; |
|
654 do |
|
655 { |
|
656 if ((rv=flashWrite(FlashId, anAddr, KFlashWriteBufSize, aPS))!=0) |
|
657 { |
|
658 break; |
|
659 } |
|
660 anAddr+=KFlashWriteBufSize; |
|
661 aPS+=KFlashWriteBufSize>>2; |
|
662 aSize-=KFlashWriteBufSize; |
|
663 } while(aSize); |
|
664 return rv; |
|
665 } |
|
666 |
|
667 TInt FlashThread(TAny*) |
|
668 { |
|
669 // If this thread crashes we want it to take the system down |
|
670 User::SetCritical(User::ESystemPermanent); |
|
671 |
|
672 GetFlashChunk(); |
|
673 if (FlashBootLoader) |
|
674 { |
|
675 PrintToScreen(_L("*** Reflashing bootloader ***\r\n")); |
|
676 FlashImageAddr=(TLinAddr)FlashAddress; |
|
677 // sanity check... |
|
678 if ((TUint32)ImageSize > KNORFlashMaxBootloaderSize) |
|
679 { |
|
680 PrintToScreen(_L("Image is larger than the flash area (%d > %d) bytes.\r\n"), ImageSize, KNORFlashMaxBootloaderSize); |
|
681 return KErrNotSupported; |
|
682 } |
|
683 } |
|
684 else |
|
685 { |
|
686 PrintToScreen(_L("*** Writing to NOR Flash ***\r\n")); |
|
687 FlashImageAddr=(TLinAddr)FlashAddress+KNORFlashMaxBootloaderSize; |
|
688 |
|
689 // sanity check... |
|
690 if ((TUint32)ImageSize > KNORFlashMaxImageSize) |
|
691 { |
|
692 PrintToScreen(_L("Image is larger than the flash area (%d > %d) bytes.\r\n"), ImageSize, KNORFlashMaxImageSize); |
|
693 return KErrNotSupported; |
|
694 } |
|
695 } |
|
696 |
|
697 FlashImageSize=(TUint32)ImageSize; |
|
698 Complete=EFalse; |
|
699 |
|
700 TUint32 imgSzMb=(FlashImageSize+0xfffff)&~0xfffff; // round image size up to 1Mb |
|
701 |
|
702 InitProgressBar(1,imgSzMb,_L("ERASE")); |
|
703 TUint32 base=FlashImageAddr; |
|
704 TUint32 end=base+imgSzMb; |
|
705 TInt r=KErrNone; |
|
706 while(base<end) |
|
707 { |
|
708 if (!BlankCheck(base,KFlashEraseBlockSize)) |
|
709 { |
|
710 r=Erase(base, KFlashEraseBlockSize); |
|
711 if (r!=KErrNone) |
|
712 { |
|
713 PrintToScreen(_L("Erase failed 0x%x\r\n"), r); |
|
714 RDebug::Printf("Erase failed 0x%x", r); |
|
715 // make this a rdebug |
|
716 BOOT_FAULT(); |
|
717 } |
|
718 } |
|
719 if (!BlankCheck(base,KFlashEraseBlockSize)) |
|
720 { |
|
721 PrintToScreen(_L("BlankCheck failed 0x%x\r\n"),base); |
|
722 RDebug::Printf("BlankCheck failed at adress 0x%08x with error code 0x%x",base,r); |
|
723 //BOOT_FAULT(); // why crash at this point, retry is better, surely? |
|
724 } |
|
725 else |
|
726 { |
|
727 // only move to next block and update progress if the block erase passed |
|
728 base+=KFlashEraseBlockSize; |
|
729 UpdateProgressBar(1,base-FlashImageAddr); |
|
730 } |
|
731 } |
|
732 |
|
733 base=FlashImageAddr; |
|
734 while(base<end) |
|
735 { |
|
736 |
|
737 if (!BlankCheck(base,KFlashEraseBlockSize)) |
|
738 { |
|
739 PrintToScreen(_L("BlankCheck 2 failed 0x%x\r\n"),base); |
|
740 RDebug::Printf("BlankCheck 2 failed at adress 0x%08x with error code 0x%x",base,r); |
|
741 BOOT_FAULT(); |
|
742 } |
|
743 base+=KFlashEraseBlockSize; |
|
744 } |
|
745 |
|
746 InitProgressBar(1,FlashImageSize,_L("WRITE")); |
|
747 TUint32 source=DestinationAddress(); // start of image in RAM |
|
748 if (ImageHeaderPresent) |
|
749 source+=256; // skip header if present |
|
750 TUint32 target=FlashImageAddr; // target in flash |
|
751 TBool complete=EFalse; |
|
752 TUint32 used_bytes=0; |
|
753 |
|
754 // while the image hasn't been written fully |
|
755 while ((target-FlashImageAddr) < FlashImageSize) |
|
756 { |
|
757 used_bytes=source-DestinationAddress(); |
|
758 |
|
759 complete=Complete; // must check Complete before Available |
|
760 |
|
761 // if there isn't anything ready, go back to the top |
|
762 if (Available<(used_bytes+256) && !complete) |
|
763 { |
|
764 continue; // wait for 256 bytes more data |
|
765 } |
|
766 TUint32 write_block_size=Available-used_bytes; // how much is ready |
|
767 write_block_size &= ~(KFlashWriteBufSize-1); // only write whole buffers |
|
768 |
|
769 while (write_block_size) |
|
770 { |
|
771 TUint32 write_size=Min(write_block_size,(TUint32)0x400); // update progress after each 1K |
|
772 r=Write(target,write_size,(const TUint32*)source); |
|
773 if (r!=KErrNone) |
|
774 { |
|
775 PrintToScreen(_L("Write failed 0x%x"),r); |
|
776 BOOT_FAULT(); |
|
777 } |
|
778 |
|
779 target+=write_size; |
|
780 source+=write_size; |
|
781 write_block_size-=write_size; |
|
782 UpdateProgressBar(1,target-FlashImageAddr); |
|
783 } |
|
784 } |
|
785 |
|
786 PrintToScreen(_L("Verifying image...\r\n")); |
|
787 |
|
788 source=DestinationAddress(); // start of image in RAM |
|
789 if (ImageHeaderPresent) |
|
790 source+=256; // skip header if present |
|
791 base=FlashImageAddr; |
|
792 volatile TUint16* pRam=(volatile TUint16*)source; |
|
793 volatile TUint16* pFlash=(volatile TUint16*)base; |
|
794 volatile TUint16* pFlashEnd=pFlash+(FlashImageSize>>1); |
|
795 |
|
796 InitProgressBar(1, FlashImageSize, _L("VERIFY")); |
|
797 while(pFlash<pFlashEnd) |
|
798 { |
|
799 if (*pFlash++ != *pRam++) |
|
800 { |
|
801 PrintToScreen(_L("Verify error at byte %d (0x%x != 0x%x)\r\n"), |
|
802 ((pFlash-1) - (volatile TUint16*)base) * 2, (*(pFlash-1)), (*(pRam-1))); |
|
803 |
|
804 PrintToScreen(_L("VERIFY %d"),(TInt)(pFlash-1)); |
|
805 BOOT_FAULT(); |
|
806 } |
|
807 |
|
808 if (!((TUint32)pFlash % 0x400)) |
|
809 UpdateProgressBar(1,(TUint32)pFlash-(TUint32)FlashImageAddr); |
|
810 } |
|
811 |
|
812 PrintToScreen(_L("Verify complete\r\n")); |
|
813 |
|
814 if (FlashBootLoader) |
|
815 { |
|
816 PrintToScreen(_L("Rebooting in %d Seconds...\r\n"), KRebootDelaySecs); |
|
817 |
|
818 InitProgressBar(1, KRebootDelaySecs, _L("DELAY ")); |
|
819 for (TUint i=0 ; i<KRebootDelaySecs ; ++i) |
|
820 { |
|
821 User::After(1000000); // Sleep in millisecs |
|
822 UpdateProgressBar(1, i); |
|
823 } |
|
824 UpdateProgressBar(1, KRebootDelaySecs); // let it get to the end |
|
825 PrintToScreen(_L("Rebooting...\r\n")); |
|
826 User::After(10000); |
|
827 Restart(KtRestartReasonHardRestart); |
|
828 } |
|
829 |
|
830 PrintToScreen(_L("Booting Image...\r\n")); |
|
831 Restart(KtRestartReasonBootRestart | KtRestartReasonNORImage); |
|
832 |
|
833 // NOTREACHED |
|
834 return 0; |
|
835 } |
|
836 |
|
837 GLDEF_C TInt InitFlashWrite() |
|
838 { |
|
839 // start thread |
|
840 RThread t; |
|
841 TInt r=t.Create(KLitThreadName,FlashThread,0x2000,NULL,NULL); |
|
842 if (r!=KErrNone) |
|
843 { |
|
844 return r; |
|
845 } |
|
846 t.SetPriority(EPriorityLess); |
|
847 t.Resume(); |
|
848 return KErrNone; |
|
849 } |
|
850 #endif //__SUPPORT_FLASH_REPRO__ |