brdbootldr/ubootldr/flash_nor.cpp
changeset 0 a41df078684a
child 43 c1f20ce4abcf
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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__