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