os/kernelhwsrv/brdbootldr/ubootldr/flash_nor.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
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".
     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__