--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/brdbootldr/ubootldr/flash_nor.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,850 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// ubootldr\flash_nor.cpp
+//
+//
+
+#define FILE_ID 0x464C5348
+
+#include "bootldr.h"
+#include "ubootldrldd.h"
+#include <e32std.h>
+#include <e32std_private.h>
+#include <e32svr.h>
+#include <e32cons.h>
+#include <f32file.h>
+#include <hal.h>
+#include <u32hal.h>
+#include "flash_nor.h"
+
+const TUint KFlashRetries = 1000000;
+
+#ifdef __SUPPORT_FLASH_REPRO__
+_LIT(KLitThreadName,"Flash");
+
+TLinAddr FlashImageAddr;
+TUint32 FlashImageSize;
+TUint32 * FlashAddress;
+
+volatile TUint32 Available;
+volatile TBool Complete;
+
+#define addr_to_page(a) (a&~(0x1000-1))
+#define addr_pageoff(a) (a&(0x1000-1))
+
+// Memory
+RUBootldrLdd LddFlash;
+RChunk TheFlashChunk;
+
+TUint FlashId = FLASH_TYPE_UNKNOWN;
+
+
+#define PRINTF(x)
+#define SPANSION_PRINTF(x)
+#define TYAX_PRINTF(x)
+#define WRITE_PRINTF(x)
+
+// Reset prototypes
+TInt cfiReset (TUint32 flashId, TUint32 address);
+TInt tyaxReset(TUint32 flashId, TUint32 address);
+
+// Erase prototypes
+TInt spansionErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize);
+TInt tyaxErase (TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize);
+
+// Write prototypes
+TInt spansionWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS);
+TInt tyaxWrite (TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS);
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// FLASH INFO
+//
+// This table holds all the information we have about supported flash devices
+//
+///////////////////////////////////////////////////////////////////////////////
+const TFlashInfo flashInfo [] =
+ {
+// Description Manufacturer ID Device ID Reset fn Erase fn Write fn Comments
+ {_L(""), CFI_MANUF_ANY, CFI_DEV_ANY, cfiReset, NULL, NULL, }, // This is the catch-all entry in case we aren't initialised
+
+// {_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
+ {_L("Spansion S29GL512N"), CFI_MANUF_SPANSION, CFI_DEV_S29GL512N, cfiReset, spansionErase, spansionWrite, }, // NaviEngine Rev B & C
+ {_L("Spansion Generic"), CFI_MANUF_SPANSION, CFI_DEV_ANY, cfiReset, spansionErase, spansionWrite, }, // Generic Spansion flash types
+
+// {_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
+ {_L("Intel Sibley"), CFI_MANUF_INTEL, CFI_DEV_SIBLEY, tyaxReset, tyaxErase, tyaxWrite, }, // H4 with Intel Tyax flash parts
+ {_L("Intel 28F256L18T"), CFI_MANUF_INTEL, CFI_DEV_28F256L18T, tyaxReset, tyaxErase, tyaxWrite, }, // H4 with Intel Tyax flash parts
+ {_L("Intel Tyax"), CFI_MANUF_INTEL, CFI_DEV_ANY, tyaxReset, tyaxErase, tyaxWrite, }, // Generic Intel Tyax flash support
+
+ // End Of Table - no more entries after here
+ {_L(""), 0, 0, NULL, NULL, NULL } // NULL entry used to mark end of table
+ };
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CFI Commands
+///////////////////////////////////////////////////////////////////////////////
+// Query
+const TCfiCommands CfiQuery [] =
+ {
+ {CFI_BASE8, 0xAAA, 0xAA},
+ {CFI_BASE8, 0x555, 0x55},
+ {CFI_BASE8, 0xAAA, 0x90},
+
+ {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command
+ };
+
+// Erase
+const TCfiCommands CfiErase [] =
+ {
+ {CFI_BASE8, 0xAAA, 0xAA},
+ {CFI_BASE8, 0x555, 0x55},
+ {CFI_BASE8, 0xAAA, 0x80},
+ {CFI_BASE8, 0xAAA, 0xAA},
+ {CFI_BASE8, 0x555, 0x55},
+ {CFI_SECTOR8, 0x000, 0x30},
+
+ {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command
+ };
+
+// Write
+const TCfiCommands CfiWrite [] =
+ {
+ {CFI_BASE8, 0xAAA, 0xAA},
+ {CFI_BASE8, 0x555, 0x55},
+ {CFI_BASE8, 0xAAA, 0xA0},
+
+ {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command
+ };
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CFI Command execution
+//
+// CFI implements a generic set of commands that can be used on all CFI flash
+// parts.
+//
+// The commands usually write to the base address of the device + an offset,
+// or to the sector/block address for some commands.
+//
+///////////////////////////////////////////////////////////////////////////////
+TInt CfiCommand(TUint32 base, TUint32 sector, const TCfiCommands * commands)
+ {
+ if (commands != NULL)
+ {
+ const TCfiCommands * pCmd = commands;
+ while (pCmd->location != CFI_END)
+ {
+ switch (pCmd->location)
+ {
+ case CFI_BASE8:
+ {
+ *(volatile TUint8*)(base + pCmd->offset) = pCmd->command;
+ }
+ break;
+ case CFI_SECTOR8:
+ {
+ *(volatile TUint8*)(sector + pCmd->offset) = pCmd->command;
+ }
+ break;
+ default:
+ return KErrNotSupported;
+ }
+ pCmd++;
+ }
+ }
+ return KErrNone;
+ }
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// TYAX specific routines
+//
+///////////////////////////////////////////////////////////////////////////////
+// Clear the status register
+///////////////////////////////////////////////////////////////////////////////
+void tyaxClearStatus(TUint32 address)
+ {
+ volatile TUint16 *p = (TUint16 *)address;
+ *p=KCmdClearStatus; // clear status reg
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Wait until cmd completes
+///////////////////////////////////////////////////////////////////////////////
+void tyaxWaitUntilReady(TUint32 address, TUint16 cmd)
+ {
+ volatile TUint16 *pF = (TUint16 *)address;
+ TUint16 s=0;
+ TInt i=KFlashRetries;
+
+ for (; i>0 && ((s&KStatusBusy)!=KStatusBusy); --i) // check ready bit
+ {
+ *pF=cmd;
+ s=*pF;
+ }
+ if (i==0)
+ {
+ PrintToScreen(_L("Write timed out"));
+ BOOT_FAULT();
+ }
+ if (s&KStatusCmdSeqError)
+ {
+ PrintToScreen(_L("Write error s=%x pF=0x%x\n"), s, pF);
+ }
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Unlock Flash
+///////////////////////////////////////////////////////////////////////////////
+void tyaxUnlock(TUint32 address)
+ {
+ TYAX_PRINTF(RDebug::Printf("tyaxUnlock(0x%08x)", address));
+ TUint16 * pF = (TUint16*)address;
+ // Unlock
+ *pF=KCmdClearBlockLockBit1;
+ *pF=KCmdClearBlockLockBit2;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// GENERIC - implementations of the generic routines
+//
+// - reset
+// - erase
+// - write
+//
+///////////////////////////////////////////////////////////////////////////////
+// Reset Flash
+///////////////////////////////////////////////////////////////////////////////
+TInt cfiReset(TUint32 flashId, TUint32 address)
+ {
+ SPANSION_PRINTF(RDebug::Printf("cfiReset(0x%08x)", address));
+
+ volatile TUint8 * p = (TUint8*)address;
+ *(p)=0xF0; // reset spansion flash
+ return KErrNone;
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Reset Flash
+///////////////////////////////////////////////////////////////////////////////
+TInt tyaxReset(TUint32 flashId, TUint32 address)
+ {
+ TYAX_PRINTF(RDebug::Printf("tyaxReset(0x%08x)", address));
+
+ TUint16 * p = (TUint16*)address;
+
+ // clear the status register
+ tyaxClearStatus((TUint32)address);
+
+ // write to linear base and set strataflash into readarray mode
+ *p=KCmdReadArrayMode;
+ return KErrNone;
+ }
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Erase a block of flash
+///////////////////////////////////////////////////////////////////////////////
+TInt spansionErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize)
+ {
+ SPANSION_PRINTF(RDebug::Printf("spansionErase 0x%08x", anAddr));
+
+ volatile TUint32 base=anAddr&~(KFlashEraseBlockSize-1); // round base address down to block
+ volatile TUint32 end=anAddr+aSize;
+ end=(end+KFlashEraseBlockSize-1)&~(KFlashEraseBlockSize-1); // round end address up to block
+ TUint32 size=end-base;
+ volatile TUint8* p=(volatile TUint8*)base;
+
+ 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));
+
+ cfiReset(flashId, aBase);
+ for (; size; size-=KFlashEraseBlockSize, p+=(KFlashEraseBlockSize>>1))
+ {
+ CfiCommand(aBase, base, CfiErase);
+
+ TUint retries = KFlashRetries;
+ while ((*(volatile TUint8*)anAddr != 0xFF) && (retries != 0))
+ {
+ retries--;
+ }
+ if (retries==0)
+ {
+ 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);
+ }
+ cfiReset(flashId, aBase);
+ }
+ return 0;
+ }
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Erase a block of flash
+///////////////////////////////////////////////////////////////////////////////
+TInt tyaxErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize)
+ {
+ TUint32 base=anAddr&~(KFlashEraseBlockSize-1); // round base address down to block
+ TUint32 end=anAddr+aSize;
+ end=(end+KFlashEraseBlockSize-1)&~(KFlashEraseBlockSize-1); // round end address up to block
+ TUint32 size=end-base;
+ volatile TUint16* p=(volatile TUint16*)base;
+
+ // write to linear base and set strataflash into readarray mode
+ *p=KCmdReadArrayMode;
+ // clear the status register
+ *p=KCmdClearStatus;
+ for (; size; size-=KFlashEraseBlockSize, p+=(KFlashEraseBlockSize>>1))
+ {
+ // Unlock
+ *p=KCmdClearBlockLockBit1;
+ *p=KCmdClearBlockLockBit2;
+ // Erase
+ *p=KCmdBlockErase1; // block erase
+ *p=KCmdBlockErase2; // block erase confirm
+
+ // wait for the erase to finish
+ while ((*p & KStatusBusy)!=KStatusBusy);
+
+ // put the flash block back to normal
+ TUint32 s=*p;
+ *p=KCmdClearStatus; // clear status reg
+ *p=KCmdReadArrayMode;
+
+ if (s & KStatusLockBitError)
+ {
+ // error
+ RDebug::Printf("Erase Failed: addr:0x%x status: 0x%x", p, s);
+ return (TUint32)p-anAddr+1;
+ }
+ }
+ return 0;
+ }
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Write a block of flash
+///////////////////////////////////////////////////////////////////////////////
+TInt spansionWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
+// Assume aSize <= KFlashWriteBufSize
+ {
+ SPANSION_PRINTF(WRITE_PRINTF(RDebug::Printf("spansionWrite anAddr=0x%08x, aSize=0x%08x", anAddr, aSize)));
+
+ volatile TUint8 * base = (TUint8 *)FlashAddress;
+ volatile TUint16 * pDest = (TUint16*)anAddr;
+ volatile TUint16 * pSrc = (TUint16*)aPS;
+ volatile TUint16 * pEnd = (TUint16*)(anAddr+aSize);
+
+ for (; pDest < pEnd; pDest++, pSrc++)
+ {
+ CfiCommand((TUint32)base, (TUint32)base, CfiWrite);
+ *pDest = *pSrc;
+
+ TUint retries = KFlashRetries;
+ while ((*pDest != *pSrc) && (retries != 0))
+ {
+ retries--;
+ }
+
+ if (*pDest != *pSrc)
+ {
+ RDebug::Printf("Write failed 0x%x=0x%x == 0x%x", pDest, *pSrc, *pDest);
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Write a block of flash
+///////////////////////////////////////////////////////////////////////////////
+// Assume aSize <= KFlashWriteBufSize
+TInt tyaxWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
+ {
+ TYAX_PRINTF(WRITE_PRINTF(RDebug::Printf("tyaxWrite anAddr=0x%08x, aSize=0x%08x", anAddr, aSize)));
+
+ volatile TUint16* pF=(volatile TUint16*)anAddr;
+
+ tyaxUnlock(anAddr);
+ tyaxClearStatus(anAddr);
+
+ if (flashInfo[flashId].deviceId == CFI_DEV_SIBLEY)
+ {
+ tyaxWaitUntilReady(anAddr, KCmdWriteStatusSibley);
+ }
+ else
+ {
+ tyaxWaitUntilReady(anAddr, KCmdWriteStatus);
+ }
+
+ // convert to words - 1
+ TInt16 l=(aSize>>1)-1;
+ *pF=l; // Write no of words
+ const TUint16* pS=(const TUint16*)aPS;
+ for (;l>=0;l--)
+ {
+ *pF++=*pS++;
+ }
+ pF=(volatile TUint16*)anAddr;
+ *pF=0xD0; // Confirm
+
+ tyaxWaitUntilReady(anAddr, KCmdReadStatus);
+ tyaxReset(flashId, anAddr);
+
+ return 0;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// WRAPPERS
+//
+// A top level routine to prevent each function checking the flash type
+//
+///////////////////////////////////////////////////////////////////////////////
+TInt flashReset(TUint32 flashId, TUint32 address)
+ {
+ PRINTF(RDebug::Printf("flashReset()"));
+
+ TInt retVal = KErrNotSupported;
+
+ if (flashInfo[flashId].reset != NULL)
+ {
+ retVal = flashInfo[flashId].reset(flashId, address);
+ }
+
+ return retVal;
+ }
+
+TInt flashErase(TUint32 flashId, TUint32 base, TUint32 address, TUint32 size)
+ {
+ PRINTF(RDebug::Printf("flashErase()"));
+
+ TInt retVal = KErrNone;
+
+ if (flashInfo[flashId].erase != NULL)
+ {
+ retVal = flashInfo[flashId].erase(flashId, base, address, size);
+ }
+
+ return retVal;
+ }
+
+TInt flashWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
+ {
+ WRITE_PRINTF(RDebug::Printf("flashWrite()"));
+
+ TInt retVal = KErrNone;
+
+ if (flashInfo[flashId].write != NULL)
+ {
+ retVal = flashInfo[flashId].write(flashId, anAddr, aSize, aPS);
+ }
+
+ return retVal;
+ }
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Flash ID
+//
+// Identify the flash part at the given address
+// returns an index into the flashInfo structure
+///////////////////////////////////////////////////////////////////////////////
+TInt flashId(TUint32 address)
+ {
+ TUint deviceIndex = FLASH_TYPE_UNKNOWN;
+
+ volatile TUint16* p16=(volatile TUint16*)address; // used for 16 bit read/write to the flash
+
+ // Put flash into CFI query mode using 8 bit writes
+ CfiCommand(address, address, CfiQuery);
+
+ // Read ID codes using 16 bit reads
+ // if we ever need to support 8 bit devices, we may need to change this to 2 x 8 bit reads per attribute
+ TUint16 manufacturerId = *(p16 );
+ TUint16 deviceId = *(p16+1);
+
+ for (TUint32 i=0; flashInfo[i].manufacturerId !=0; i++)
+ {
+ PRINTF(RDebug::Printf("Check device: M 0x%04x D 0x%04x", flashInfo[i].manufacturerId, flashInfo[i].deviceId));
+
+ if ( ( flashInfo[i].manufacturerId == manufacturerId)
+ && ( (flashInfo[i].deviceId == CFI_DEV_ANY ) // support generic flash devices
+ ||(flashInfo[i].deviceId == deviceId )
+ )
+ )
+ {
+ PRINTF(RDebug::Print(_L("Found device: %s (Manufacturer=%x Device=%x)"), flashInfo[i].name.Ptr(), flashInfo[i].manufacturerId, flashInfo[i].deviceId));
+ deviceIndex = i;
+ break;
+ }
+ }
+ if (deviceIndex == FLASH_TYPE_UNKNOWN)
+ {
+ RDebug::Printf("Flash type unknown: Manufacturer ID = %04x, Device ID = %04x", manufacturerId, deviceId );
+ }
+ flashReset(deviceIndex, (TUint32)FlashAddress);
+ return deviceIndex;
+ }
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+GLDEF_C TUint32 * GetFlashChunk()
+ {
+ // return if already initialised
+ if (FlashAddress != NULL)
+ return FlashAddress;
+
+ TInt r = User::LoadLogicalDevice(KBootldrLddName);
+
+ r = LddFlash.Open();
+ if (r!=KErrNone)
+ {
+ PrintToScreen(_L("FAULT due to LddFlash open\r\n"));
+ BOOT_FAULT();
+ }
+
+ TUint8* kernelAddress;
+ r=LddFlash.CreateChunk(KNORFlashTargetSize,(TAny**)&kernelAddress);
+ if (r!=KErrNone)
+ {
+ PrintToScreen(_L("FAULT due to chunk create\r\n"));
+ BOOT_FAULT();
+ }
+
+ // If we're running from RAM flash will be in a different place...
+ r = LddFlash.CommitMemory(KNORFlashTargetSize,addr_to_page(KNORFlashTargetAddr));
+ if (r!=KErrNone)
+ {
+ PrintToScreen(_L("FAULT due to commit\r\n"));
+ BOOT_FAULT();
+ }
+
+ r = LddFlash.GetChunkHandle(TheFlashChunk);
+ if (r!=KErrNone)
+ {
+ PrintToScreen(_L("FAULT due to handle\r\n"));
+ BOOT_FAULT();
+ }
+
+ TUint8* Base = TheFlashChunk.Base();
+ FlashAddress = (TUint32*)Base;
+ FlashId = flashId((TUint32)FlashAddress);
+
+ return FlashAddress;
+ }
+
+GLDEF_C void NotifyDataAvailable(TInt aTotalAmount)
+ {
+ Available=(TUint32)aTotalAmount;
+ }
+
+GLDEF_C void NotifyDownloadComplete()
+ {
+ Complete=ETrue;
+ }
+
+GLDEF_C TBool BlankCheck(TUint32 anAddr, TUint32 aSize)
+ {
+ const TUint16* p=(const TUint16*)anAddr;
+ const TUint16* pE=p+(aSize>>1);
+ TBool rv=ETrue;
+
+ while(p<pE)
+ {
+ if (*p!=0xffff)
+ {
+ 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));
+ rv=EFalse;
+ break;
+ }
+ p++;
+ }
+ if (rv)
+ {
+ PRINTF(RDebug::Printf("BlankCheck: %x is blank", anAddr));
+ }
+ return rv;
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Erase
+//
+// This function is used by the variant code. The variant code shouldn't care
+// about the Flash ID, so I've left this function here as a wrapper for the
+// internal flashErase function, passing in a nasty global variable containing
+// the Flash ID.
+//
+///////////////////////////////////////////////////////////////////////////////
+GLDEF_C TInt Erase(TUint32 anAddr, TUint32 aSize)
+ {
+ flashErase(FlashId, (TUint32)FlashAddress, anAddr, aSize);
+ return 0;
+ }
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Write
+//
+// This function is used by the variant code. As well as the Flash ID comment
+// from above (see Erase), the variant shouldn't have to care about internal
+// buffer sizes, etc.
+//
+///////////////////////////////////////////////////////////////////////////////
+GLDEF_C TInt Write(TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
+ {
+ TInt rv=0;
+ do
+ {
+ if ((rv=flashWrite(FlashId, anAddr, KFlashWriteBufSize, aPS))!=0)
+ {
+ break;
+ }
+ anAddr+=KFlashWriteBufSize;
+ aPS+=KFlashWriteBufSize>>2;
+ aSize-=KFlashWriteBufSize;
+ } while(aSize);
+ return rv;
+ }
+
+TInt FlashThread(TAny*)
+ {
+ // If this thread crashes we want it to take the system down
+ User::SetCritical(User::ESystemPermanent);
+
+ GetFlashChunk();
+ if (FlashBootLoader)
+ {
+ PrintToScreen(_L("*** Reflashing bootloader ***\r\n"));
+ FlashImageAddr=(TLinAddr)FlashAddress;
+ // sanity check...
+ if ((TUint32)ImageSize > KNORFlashMaxBootloaderSize)
+ {
+ PrintToScreen(_L("Image is larger than the flash area (%d > %d) bytes.\r\n"), ImageSize, KNORFlashMaxBootloaderSize);
+ return KErrNotSupported;
+ }
+ }
+ else
+ {
+ PrintToScreen(_L("*** Writing to NOR Flash ***\r\n"));
+ FlashImageAddr=(TLinAddr)FlashAddress+KNORFlashMaxBootloaderSize;
+
+ // sanity check...
+ if ((TUint32)ImageSize > KNORFlashMaxImageSize)
+ {
+ PrintToScreen(_L("Image is larger than the flash area (%d > %d) bytes.\r\n"), ImageSize, KNORFlashMaxImageSize);
+ return KErrNotSupported;
+ }
+ }
+
+ FlashImageSize=(TUint32)ImageSize;
+ Complete=EFalse;
+
+ TUint32 imgSzMb=(FlashImageSize+0xfffff)&~0xfffff; // round image size up to 1Mb
+
+ InitProgressBar(1,imgSzMb,_L("ERASE"));
+ TUint32 base=FlashImageAddr;
+ TUint32 end=base+imgSzMb;
+ TInt r=KErrNone;
+ while(base<end)
+ {
+ if (!BlankCheck(base,KFlashEraseBlockSize))
+ {
+ r=Erase(base, KFlashEraseBlockSize);
+ if (r!=KErrNone)
+ {
+ PrintToScreen(_L("Erase failed 0x%x\r\n"), r);
+ RDebug::Printf("Erase failed 0x%x", r);
+ // make this a rdebug
+ BOOT_FAULT();
+ }
+ }
+ if (!BlankCheck(base,KFlashEraseBlockSize))
+ {
+ PrintToScreen(_L("BlankCheck failed 0x%x\r\n"),base);
+ RDebug::Printf("BlankCheck failed at adress 0x%08x with error code 0x%x",base,r);
+ //BOOT_FAULT(); // why crash at this point, retry is better, surely?
+ }
+ else
+ {
+ // only move to next block and update progress if the block erase passed
+ base+=KFlashEraseBlockSize;
+ UpdateProgressBar(1,base-FlashImageAddr);
+ }
+ }
+
+ base=FlashImageAddr;
+ while(base<end)
+ {
+
+ if (!BlankCheck(base,KFlashEraseBlockSize))
+ {
+ PrintToScreen(_L("BlankCheck 2 failed 0x%x\r\n"),base);
+ RDebug::Printf("BlankCheck 2 failed at adress 0x%08x with error code 0x%x",base,r);
+ BOOT_FAULT();
+ }
+ base+=KFlashEraseBlockSize;
+ }
+
+ InitProgressBar(1,FlashImageSize,_L("WRITE"));
+ TUint32 source=DestinationAddress(); // start of image in RAM
+ if (ImageHeaderPresent)
+ source+=256; // skip header if present
+ TUint32 target=FlashImageAddr; // target in flash
+ TBool complete=EFalse;
+ TUint32 used_bytes=0;
+
+ // while the image hasn't been written fully
+ while ((target-FlashImageAddr) < FlashImageSize)
+ {
+ used_bytes=source-DestinationAddress();
+
+ complete=Complete; // must check Complete before Available
+
+ // if there isn't anything ready, go back to the top
+ if (Available<(used_bytes+256) && !complete)
+ {
+ continue; // wait for 256 bytes more data
+ }
+ TUint32 write_block_size=Available-used_bytes; // how much is ready
+ write_block_size &= ~(KFlashWriteBufSize-1); // only write whole buffers
+
+ while (write_block_size)
+ {
+ TUint32 write_size=Min(write_block_size,(TUint32)0x400); // update progress after each 1K
+ r=Write(target,write_size,(const TUint32*)source);
+ if (r!=KErrNone)
+ {
+ PrintToScreen(_L("Write failed 0x%x"),r);
+ BOOT_FAULT();
+ }
+
+ target+=write_size;
+ source+=write_size;
+ write_block_size-=write_size;
+ UpdateProgressBar(1,target-FlashImageAddr);
+ }
+ }
+
+ PrintToScreen(_L("Verifying image...\r\n"));
+
+ source=DestinationAddress(); // start of image in RAM
+ if (ImageHeaderPresent)
+ source+=256; // skip header if present
+ base=FlashImageAddr;
+ volatile TUint16* pRam=(volatile TUint16*)source;
+ volatile TUint16* pFlash=(volatile TUint16*)base;
+ volatile TUint16* pFlashEnd=pFlash+(FlashImageSize>>1);
+
+ InitProgressBar(1, FlashImageSize, _L("VERIFY"));
+ while(pFlash<pFlashEnd)
+ {
+ if (*pFlash++ != *pRam++)
+ {
+ PrintToScreen(_L("Verify error at byte %d (0x%x != 0x%x)\r\n"),
+ ((pFlash-1) - (volatile TUint16*)base) * 2, (*(pFlash-1)), (*(pRam-1)));
+
+ PrintToScreen(_L("VERIFY %d"),(TInt)(pFlash-1));
+ BOOT_FAULT();
+ }
+
+ if (!((TUint32)pFlash % 0x400))
+ UpdateProgressBar(1,(TUint32)pFlash-(TUint32)FlashImageAddr);
+ }
+
+ PrintToScreen(_L("Verify complete\r\n"));
+
+ if (FlashBootLoader)
+ {
+ PrintToScreen(_L("Rebooting in %d Seconds...\r\n"), KRebootDelaySecs);
+
+ InitProgressBar(1, KRebootDelaySecs, _L("DELAY "));
+ for (TUint i=0 ; i<KRebootDelaySecs ; ++i)
+ {
+ User::After(1000000); // Sleep in millisecs
+ UpdateProgressBar(1, i);
+ }
+ UpdateProgressBar(1, KRebootDelaySecs); // let it get to the end
+ PrintToScreen(_L("Rebooting...\r\n"));
+ User::After(10000);
+ Restart(KtRestartReasonHardRestart);
+ }
+
+ PrintToScreen(_L("Booting Image...\r\n"));
+ Restart(KtRestartReasonBootRestart | KtRestartReasonNORImage);
+
+ // NOTREACHED
+ return 0;
+ }
+
+GLDEF_C TInt InitFlashWrite()
+ {
+ // start thread
+ RThread t;
+ TInt r=t.Create(KLitThreadName,FlashThread,0x2000,NULL,NULL);
+ if (r!=KErrNone)
+ {
+ return r;
+ }
+ t.SetPriority(EPriorityLess);
+ t.Resume();
+ return KErrNone;
+ }
+#endif //__SUPPORT_FLASH_REPRO__