Update contrib.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // ubootldr\flash_nor.cpp
18 #define FILE_ID 0x464C5348
21 #include "ubootldrldd.h"
23 #include <e32std_private.h>
29 #include "flash_nor.h"
31 const TUint KFlashRetries = 1000000;
33 #ifdef __SUPPORT_FLASH_REPRO__
34 _LIT(KLitThreadName,"Flash");
36 TLinAddr FlashImageAddr;
37 TUint32 FlashImageSize;
38 TUint32 * FlashAddress;
40 volatile TUint32 Available;
41 volatile TBool Complete;
43 #define addr_to_page(a) (a&~(0x1000-1))
44 #define addr_pageoff(a) (a&(0x1000-1))
47 RUBootldrLdd LddFlash;
50 TUint FlashId = FLASH_TYPE_UNKNOWN;
54 #define SPANSION_PRINTF(x)
55 #define TYAX_PRINTF(x)
56 #define WRITE_PRINTF(x)
59 TInt cfiReset (TUint32 flashId, TUint32 address);
60 TInt tyaxReset(TUint32 flashId, TUint32 address);
63 TInt spansionErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize);
64 TInt tyaxErase (TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize);
67 TInt spansionWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS);
68 TInt tyaxWrite (TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS);
70 ///////////////////////////////////////////////////////////////////////////////
74 // This table holds all the information we have about supported flash devices
76 ///////////////////////////////////////////////////////////////////////////////
77 const TFlashInfo flashInfo [] =
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
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
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
91 // End Of Table - no more entries after here
92 {_L(""), 0, 0, NULL, NULL, NULL } // NULL entry used to mark end of table
99 ///////////////////////////////////////////////////////////////////////////////
101 ///////////////////////////////////////////////////////////////////////////////
103 const TCfiCommands CfiQuery [] =
105 {CFI_BASE8, 0xAAA, 0xAA},
106 {CFI_BASE8, 0x555, 0x55},
107 {CFI_BASE8, 0xAAA, 0x90},
109 {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command
113 const TCfiCommands CfiErase [] =
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},
122 {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command
126 const TCfiCommands CfiWrite [] =
128 {CFI_BASE8, 0xAAA, 0xAA},
129 {CFI_BASE8, 0x555, 0x55},
130 {CFI_BASE8, 0xAAA, 0xA0},
132 {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command
140 ///////////////////////////////////////////////////////////////////////////////
142 // CFI Command execution
144 // CFI implements a generic set of commands that can be used on all CFI flash
147 // The commands usually write to the base address of the device + an offset,
148 // or to the sector/block address for some commands.
150 ///////////////////////////////////////////////////////////////////////////////
151 TInt CfiCommand(TUint32 base, TUint32 sector, const TCfiCommands * commands)
153 if (commands != NULL)
155 const TCfiCommands * pCmd = commands;
156 while (pCmd->location != CFI_END)
158 switch (pCmd->location)
162 *(volatile TUint8*)(base + pCmd->offset) = pCmd->command;
167 *(volatile TUint8*)(sector + pCmd->offset) = pCmd->command;
171 return KErrNotSupported;
182 ///////////////////////////////////////////////////////////////////////////////
184 // TYAX specific routines
186 ///////////////////////////////////////////////////////////////////////////////
187 // Clear the status register
188 ///////////////////////////////////////////////////////////////////////////////
189 void tyaxClearStatus(TUint32 address)
191 volatile TUint16 *p = (TUint16 *)address;
192 *p=KCmdClearStatus; // clear status reg
195 ///////////////////////////////////////////////////////////////////////////////
196 // Wait until cmd completes
197 ///////////////////////////////////////////////////////////////////////////////
198 void tyaxWaitUntilReady(TUint32 address, TUint16 cmd)
200 volatile TUint16 *pF = (TUint16 *)address;
202 TInt i=KFlashRetries;
204 for (; i>0 && ((s&KStatusBusy)!=KStatusBusy); --i) // check ready bit
211 PrintToScreen(_L("Write timed out"));
214 if (s&KStatusCmdSeqError)
216 PrintToScreen(_L("Write error s=%x pF=0x%x\n"), s, pF);
220 ///////////////////////////////////////////////////////////////////////////////
222 ///////////////////////////////////////////////////////////////////////////////
223 void tyaxUnlock(TUint32 address)
225 TYAX_PRINTF(RDebug::Printf("tyaxUnlock(0x%08x)", address));
226 TUint16 * pF = (TUint16*)address;
228 *pF=KCmdClearBlockLockBit1;
229 *pF=KCmdClearBlockLockBit2;
244 ///////////////////////////////////////////////////////////////////////////////
246 // GENERIC - implementations of the generic routines
252 ///////////////////////////////////////////////////////////////////////////////
254 ///////////////////////////////////////////////////////////////////////////////
255 TInt cfiReset(TUint32 flashId, TUint32 address)
257 SPANSION_PRINTF(RDebug::Printf("cfiReset(0x%08x)", address));
259 volatile TUint8 * p = (TUint8*)address;
260 *(p)=0xF0; // reset spansion flash
264 ///////////////////////////////////////////////////////////////////////////////
266 ///////////////////////////////////////////////////////////////////////////////
267 TInt tyaxReset(TUint32 flashId, TUint32 address)
269 TYAX_PRINTF(RDebug::Printf("tyaxReset(0x%08x)", address));
271 TUint16 * p = (TUint16*)address;
273 // clear the status register
274 tyaxClearStatus((TUint32)address);
276 // write to linear base and set strataflash into readarray mode
277 *p=KCmdReadArrayMode;
284 ///////////////////////////////////////////////////////////////////////////////
285 // Erase a block of flash
286 ///////////////////////////////////////////////////////////////////////////////
287 TInt spansionErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize)
289 SPANSION_PRINTF(RDebug::Printf("spansionErase 0x%08x", anAddr));
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;
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));
299 cfiReset(flashId, aBase);
300 for (; size; size-=KFlashEraseBlockSize, p+=(KFlashEraseBlockSize>>1))
302 CfiCommand(aBase, base, CfiErase);
304 TUint retries = KFlashRetries;
305 while ((*(volatile TUint8*)anAddr != 0xFF) && (retries != 0))
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);
313 cfiReset(flashId, aBase);
319 ///////////////////////////////////////////////////////////////////////////////
320 // Erase a block of flash
321 ///////////////////////////////////////////////////////////////////////////////
322 TInt tyaxErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize)
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;
330 // write to linear base and set strataflash into readarray mode
331 *p=KCmdReadArrayMode;
332 // clear the status register
334 for (; size; size-=KFlashEraseBlockSize, p+=(KFlashEraseBlockSize>>1))
337 *p=KCmdClearBlockLockBit1;
338 *p=KCmdClearBlockLockBit2;
340 *p=KCmdBlockErase1; // block erase
341 *p=KCmdBlockErase2; // block erase confirm
343 // wait for the erase to finish
344 while ((*p & KStatusBusy)!=KStatusBusy);
346 // put the flash block back to normal
348 *p=KCmdClearStatus; // clear status reg
349 *p=KCmdReadArrayMode;
351 if (s & KStatusLockBitError)
354 RDebug::Printf("Erase Failed: addr:0x%x status: 0x%x", p, s);
355 return (TUint32)p-anAddr+1;
362 ///////////////////////////////////////////////////////////////////////////////
363 // Write a block of flash
364 ///////////////////////////////////////////////////////////////////////////////
365 TInt spansionWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
366 // Assume aSize <= KFlashWriteBufSize
368 SPANSION_PRINTF(WRITE_PRINTF(RDebug::Printf("spansionWrite anAddr=0x%08x, aSize=0x%08x", anAddr, aSize)));
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);
375 for (; pDest < pEnd; pDest++, pSrc++)
377 CfiCommand((TUint32)base, (TUint32)base, CfiWrite);
380 TUint retries = KFlashRetries;
381 while ((*pDest != *pSrc) && (retries != 0))
388 RDebug::Printf("Write failed 0x%x=0x%x == 0x%x", pDest, *pSrc, *pDest);
395 ///////////////////////////////////////////////////////////////////////////////
396 // Write a block of flash
397 ///////////////////////////////////////////////////////////////////////////////
398 // Assume aSize <= KFlashWriteBufSize
399 TInt tyaxWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
401 TYAX_PRINTF(WRITE_PRINTF(RDebug::Printf("tyaxWrite anAddr=0x%08x, aSize=0x%08x", anAddr, aSize)));
403 volatile TUint16* pF=(volatile TUint16*)anAddr;
406 tyaxClearStatus(anAddr);
408 if (flashInfo[flashId].deviceId == CFI_DEV_SIBLEY)
410 tyaxWaitUntilReady(anAddr, KCmdWriteStatusSibley);
414 tyaxWaitUntilReady(anAddr, KCmdWriteStatus);
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;
425 pF=(volatile TUint16*)anAddr;
428 tyaxWaitUntilReady(anAddr, KCmdReadStatus);
429 tyaxReset(flashId, anAddr);
445 ///////////////////////////////////////////////////////////////////////////////
449 // A top level routine to prevent each function checking the flash type
451 ///////////////////////////////////////////////////////////////////////////////
452 TInt flashReset(TUint32 flashId, TUint32 address)
454 PRINTF(RDebug::Printf("flashReset()"));
456 TInt retVal = KErrNotSupported;
458 if (flashInfo[flashId].reset != NULL)
460 retVal = flashInfo[flashId].reset(flashId, address);
466 TInt flashErase(TUint32 flashId, TUint32 base, TUint32 address, TUint32 size)
468 PRINTF(RDebug::Printf("flashErase()"));
470 TInt retVal = KErrNone;
472 if (flashInfo[flashId].erase != NULL)
474 retVal = flashInfo[flashId].erase(flashId, base, address, size);
480 TInt flashWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
482 WRITE_PRINTF(RDebug::Printf("flashWrite()"));
484 TInt retVal = KErrNone;
486 if (flashInfo[flashId].write != NULL)
488 retVal = flashInfo[flashId].write(flashId, anAddr, aSize, aPS);
495 ///////////////////////////////////////////////////////////////////////////////
499 // Identify the flash part at the given address
500 // returns an index into the flashInfo structure
501 ///////////////////////////////////////////////////////////////////////////////
502 TInt flashId(TUint32 address)
504 TUint deviceIndex = FLASH_TYPE_UNKNOWN;
506 volatile TUint16* p16=(volatile TUint16*)address; // used for 16 bit read/write to the flash
508 // Put flash into CFI query mode using 8 bit writes
509 CfiCommand(address, address, CfiQuery);
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);
516 for (TUint32 i=0; flashInfo[i].manufacturerId !=0; i++)
518 PRINTF(RDebug::Printf("Check device: M 0x%04x D 0x%04x", flashInfo[i].manufacturerId, flashInfo[i].deviceId));
520 if ( ( flashInfo[i].manufacturerId == manufacturerId)
521 && ( (flashInfo[i].deviceId == CFI_DEV_ANY ) // support generic flash devices
522 ||(flashInfo[i].deviceId == deviceId )
526 PRINTF(RDebug::Print(_L("Found device: %s (Manufacturer=%x Device=%x)"), flashInfo[i].name.Ptr(), flashInfo[i].manufacturerId, flashInfo[i].deviceId));
531 if (deviceIndex == FLASH_TYPE_UNKNOWN)
533 RDebug::Printf("Flash type unknown: Manufacturer ID = %04x, Device ID = %04x", manufacturerId, deviceId );
535 flashReset(deviceIndex, (TUint32)FlashAddress);
540 ///////////////////////////////////////////////////////////////////////////////
541 ///////////////////////////////////////////////////////////////////////////////
547 GLDEF_C TUint32 * GetFlashChunk()
549 // return if already initialised
550 if (FlashAddress != NULL)
553 TInt r = User::LoadLogicalDevice(KBootldrLddName);
558 PrintToScreen(_L("FAULT due to LddFlash open\r\n"));
562 TUint8* kernelAddress;
563 r=LddFlash.CreateChunk(KNORFlashTargetSize,(TAny**)&kernelAddress);
566 PrintToScreen(_L("FAULT due to chunk create\r\n"));
570 // If we're running from RAM flash will be in a different place...
571 r = LddFlash.CommitMemory(KNORFlashTargetSize,addr_to_page(KNORFlashTargetAddr));
574 PrintToScreen(_L("FAULT due to commit\r\n"));
578 r = LddFlash.GetChunkHandle(TheFlashChunk);
581 PrintToScreen(_L("FAULT due to handle\r\n"));
585 TUint8* Base = TheFlashChunk.Base();
586 FlashAddress = (TUint32*)Base;
587 FlashId = flashId((TUint32)FlashAddress);
592 GLDEF_C void NotifyDataAvailable(TInt aTotalAmount)
594 Available=(TUint32)aTotalAmount;
597 GLDEF_C void NotifyDownloadComplete()
602 GLDEF_C TBool BlankCheck(TUint32 anAddr, TUint32 aSize)
604 const TUint16* p=(const TUint16*)anAddr;
605 const TUint16* pE=p+(aSize>>1);
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));
620 PRINTF(RDebug::Printf("BlankCheck: %x is blank", anAddr));
625 ///////////////////////////////////////////////////////////////////////////////
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
634 ///////////////////////////////////////////////////////////////////////////////
635 GLDEF_C TInt Erase(TUint32 anAddr, TUint32 aSize)
637 flashErase(FlashId, (TUint32)FlashAddress, anAddr, aSize);
642 ///////////////////////////////////////////////////////////////////////////////
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.
650 ///////////////////////////////////////////////////////////////////////////////
651 GLDEF_C TInt Write(TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
656 if ((rv=flashWrite(FlashId, anAddr, KFlashWriteBufSize, aPS))!=0)
660 anAddr+=KFlashWriteBufSize;
661 aPS+=KFlashWriteBufSize>>2;
662 aSize-=KFlashWriteBufSize;
667 TInt FlashThread(TAny*)
669 // If this thread crashes we want it to take the system down
670 User::SetCritical(User::ESystemPermanent);
675 PrintToScreen(_L("*** Reflashing bootloader ***\r\n"));
676 FlashImageAddr=(TLinAddr)FlashAddress;
678 if ((TUint32)ImageSize > KNORFlashMaxBootloaderSize)
680 PrintToScreen(_L("Image is larger than the flash area (%d > %d) bytes.\r\n"), ImageSize, KNORFlashMaxBootloaderSize);
681 return KErrNotSupported;
686 PrintToScreen(_L("*** Writing to NOR Flash ***\r\n"));
687 FlashImageAddr=(TLinAddr)FlashAddress+KNORFlashMaxBootloaderSize;
690 if ((TUint32)ImageSize > KNORFlashMaxImageSize)
692 PrintToScreen(_L("Image is larger than the flash area (%d > %d) bytes.\r\n"), ImageSize, KNORFlashMaxImageSize);
693 return KErrNotSupported;
697 FlashImageSize=(TUint32)ImageSize;
700 TUint32 imgSzMb=(FlashImageSize+0xfffff)&~0xfffff; // round image size up to 1Mb
702 InitProgressBar(1,imgSzMb,_L("ERASE"));
703 TUint32 base=FlashImageAddr;
704 TUint32 end=base+imgSzMb;
708 if (!BlankCheck(base,KFlashEraseBlockSize))
710 r=Erase(base, KFlashEraseBlockSize);
713 PrintToScreen(_L("Erase failed 0x%x\r\n"), r);
714 RDebug::Printf("Erase failed 0x%x", r);
715 // make this a rdebug
719 if (!BlankCheck(base,KFlashEraseBlockSize))
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?
727 // only move to next block and update progress if the block erase passed
728 base+=KFlashEraseBlockSize;
729 UpdateProgressBar(1,base-FlashImageAddr);
737 if (!BlankCheck(base,KFlashEraseBlockSize))
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);
743 base+=KFlashEraseBlockSize;
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;
754 // while the image hasn't been written fully
755 while ((target-FlashImageAddr) < FlashImageSize)
757 used_bytes=source-DestinationAddress();
759 complete=Complete; // must check Complete before Available
761 // if there isn't anything ready, go back to the top
762 if (Available<(used_bytes+256) && !complete)
764 continue; // wait for 256 bytes more data
766 TUint32 write_block_size=Available-used_bytes; // how much is ready
767 write_block_size &= ~(KFlashWriteBufSize-1); // only write whole buffers
769 while (write_block_size)
771 TUint32 write_size=Min(write_block_size,(TUint32)0x400); // update progress after each 1K
772 r=Write(target,write_size,(const TUint32*)source);
775 PrintToScreen(_L("Write failed 0x%x"),r);
781 write_block_size-=write_size;
782 UpdateProgressBar(1,target-FlashImageAddr);
786 PrintToScreen(_L("Verifying image...\r\n"));
788 source=DestinationAddress(); // start of image in RAM
789 if (ImageHeaderPresent)
790 source+=256; // skip header if present
792 volatile TUint16* pRam=(volatile TUint16*)source;
793 volatile TUint16* pFlash=(volatile TUint16*)base;
794 volatile TUint16* pFlashEnd=pFlash+(FlashImageSize>>1);
796 InitProgressBar(1, FlashImageSize, _L("VERIFY"));
797 while(pFlash<pFlashEnd)
799 if (*pFlash++ != *pRam++)
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)));
804 PrintToScreen(_L("VERIFY %d"),(TInt)(pFlash-1));
808 if (!((TUint32)pFlash % 0x400))
809 UpdateProgressBar(1,(TUint32)pFlash-(TUint32)FlashImageAddr);
812 PrintToScreen(_L("Verify complete\r\n"));
816 PrintToScreen(_L("Rebooting in %d Seconds...\r\n"), KRebootDelaySecs);
818 InitProgressBar(1, KRebootDelaySecs, _L("DELAY "));
819 for (TUint i=0 ; i<KRebootDelaySecs ; ++i)
821 User::After(1000000); // Sleep in millisecs
822 UpdateProgressBar(1, i);
824 UpdateProgressBar(1, KRebootDelaySecs); // let it get to the end
825 PrintToScreen(_L("Rebooting...\r\n"));
827 Restart(KtRestartReasonHardRestart);
830 PrintToScreen(_L("Booting Image...\r\n"));
831 Restart(KtRestartReasonBootRestart | KtRestartReasonNORImage);
837 GLDEF_C TInt InitFlashWrite()
841 TInt r=t.Create(KLitThreadName,FlashThread,0x2000,NULL,NULL);
846 t.SetPriority(EPriorityLess);
850 #endif //__SUPPORT_FLASH_REPRO__