1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/brdbootldr/ubootldr/flash_nor.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,850 @@
1.4 +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// ubootldr\flash_nor.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#define FILE_ID 0x464C5348
1.22 +
1.23 +#include "bootldr.h"
1.24 +#include "ubootldrldd.h"
1.25 +#include <e32std.h>
1.26 +#include <e32std_private.h>
1.27 +#include <e32svr.h>
1.28 +#include <e32cons.h>
1.29 +#include <f32file.h>
1.30 +#include <hal.h>
1.31 +#include <u32hal.h>
1.32 +#include "flash_nor.h"
1.33 +
1.34 +const TUint KFlashRetries = 1000000;
1.35 +
1.36 +#ifdef __SUPPORT_FLASH_REPRO__
1.37 +_LIT(KLitThreadName,"Flash");
1.38 +
1.39 +TLinAddr FlashImageAddr;
1.40 +TUint32 FlashImageSize;
1.41 +TUint32 * FlashAddress;
1.42 +
1.43 +volatile TUint32 Available;
1.44 +volatile TBool Complete;
1.45 +
1.46 +#define addr_to_page(a) (a&~(0x1000-1))
1.47 +#define addr_pageoff(a) (a&(0x1000-1))
1.48 +
1.49 +// Memory
1.50 +RUBootldrLdd LddFlash;
1.51 +RChunk TheFlashChunk;
1.52 +
1.53 +TUint FlashId = FLASH_TYPE_UNKNOWN;
1.54 +
1.55 +
1.56 +#define PRINTF(x)
1.57 +#define SPANSION_PRINTF(x)
1.58 +#define TYAX_PRINTF(x)
1.59 +#define WRITE_PRINTF(x)
1.60 +
1.61 +// Reset prototypes
1.62 +TInt cfiReset (TUint32 flashId, TUint32 address);
1.63 +TInt tyaxReset(TUint32 flashId, TUint32 address);
1.64 +
1.65 +// Erase prototypes
1.66 +TInt spansionErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize);
1.67 +TInt tyaxErase (TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize);
1.68 +
1.69 +// Write prototypes
1.70 +TInt spansionWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS);
1.71 +TInt tyaxWrite (TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS);
1.72 +
1.73 +///////////////////////////////////////////////////////////////////////////////
1.74 +//
1.75 +// FLASH INFO
1.76 +//
1.77 +// This table holds all the information we have about supported flash devices
1.78 +//
1.79 +///////////////////////////////////////////////////////////////////////////////
1.80 +const TFlashInfo flashInfo [] =
1.81 + {
1.82 +// Description Manufacturer ID Device ID Reset fn Erase fn Write fn Comments
1.83 + {_L(""), CFI_MANUF_ANY, CFI_DEV_ANY, cfiReset, NULL, NULL, }, // This is the catch-all entry in case we aren't initialised
1.84 +
1.85 +// {_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
1.86 + {_L("Spansion S29GL512N"), CFI_MANUF_SPANSION, CFI_DEV_S29GL512N, cfiReset, spansionErase, spansionWrite, }, // NaviEngine Rev B & C
1.87 + {_L("Spansion Generic"), CFI_MANUF_SPANSION, CFI_DEV_ANY, cfiReset, spansionErase, spansionWrite, }, // Generic Spansion flash types
1.88 +
1.89 +// {_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
1.90 + {_L("Intel Sibley"), CFI_MANUF_INTEL, CFI_DEV_SIBLEY, tyaxReset, tyaxErase, tyaxWrite, }, // H4 with Intel Tyax flash parts
1.91 + {_L("Intel 28F256L18T"), CFI_MANUF_INTEL, CFI_DEV_28F256L18T, tyaxReset, tyaxErase, tyaxWrite, }, // H4 with Intel Tyax flash parts
1.92 + {_L("Intel Tyax"), CFI_MANUF_INTEL, CFI_DEV_ANY, tyaxReset, tyaxErase, tyaxWrite, }, // Generic Intel Tyax flash support
1.93 +
1.94 + // End Of Table - no more entries after here
1.95 + {_L(""), 0, 0, NULL, NULL, NULL } // NULL entry used to mark end of table
1.96 + };
1.97 +
1.98 +
1.99 +
1.100 +
1.101 +
1.102 +///////////////////////////////////////////////////////////////////////////////
1.103 +// CFI Commands
1.104 +///////////////////////////////////////////////////////////////////////////////
1.105 +// Query
1.106 +const TCfiCommands CfiQuery [] =
1.107 + {
1.108 + {CFI_BASE8, 0xAAA, 0xAA},
1.109 + {CFI_BASE8, 0x555, 0x55},
1.110 + {CFI_BASE8, 0xAAA, 0x90},
1.111 +
1.112 + {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command
1.113 + };
1.114 +
1.115 +// Erase
1.116 +const TCfiCommands CfiErase [] =
1.117 + {
1.118 + {CFI_BASE8, 0xAAA, 0xAA},
1.119 + {CFI_BASE8, 0x555, 0x55},
1.120 + {CFI_BASE8, 0xAAA, 0x80},
1.121 + {CFI_BASE8, 0xAAA, 0xAA},
1.122 + {CFI_BASE8, 0x555, 0x55},
1.123 + {CFI_SECTOR8, 0x000, 0x30},
1.124 +
1.125 + {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command
1.126 + };
1.127 +
1.128 +// Write
1.129 +const TCfiCommands CfiWrite [] =
1.130 + {
1.131 + {CFI_BASE8, 0xAAA, 0xAA},
1.132 + {CFI_BASE8, 0x555, 0x55},
1.133 + {CFI_BASE8, 0xAAA, 0xA0},
1.134 +
1.135 + {CFI_END, CFI_END, CFI_END} // Termination of command sequence - this entry is not a command
1.136 + };
1.137 +
1.138 +
1.139 +
1.140 +
1.141 +
1.142 +
1.143 +///////////////////////////////////////////////////////////////////////////////
1.144 +//
1.145 +// CFI Command execution
1.146 +//
1.147 +// CFI implements a generic set of commands that can be used on all CFI flash
1.148 +// parts.
1.149 +//
1.150 +// The commands usually write to the base address of the device + an offset,
1.151 +// or to the sector/block address for some commands.
1.152 +//
1.153 +///////////////////////////////////////////////////////////////////////////////
1.154 +TInt CfiCommand(TUint32 base, TUint32 sector, const TCfiCommands * commands)
1.155 + {
1.156 + if (commands != NULL)
1.157 + {
1.158 + const TCfiCommands * pCmd = commands;
1.159 + while (pCmd->location != CFI_END)
1.160 + {
1.161 + switch (pCmd->location)
1.162 + {
1.163 + case CFI_BASE8:
1.164 + {
1.165 + *(volatile TUint8*)(base + pCmd->offset) = pCmd->command;
1.166 + }
1.167 + break;
1.168 + case CFI_SECTOR8:
1.169 + {
1.170 + *(volatile TUint8*)(sector + pCmd->offset) = pCmd->command;
1.171 + }
1.172 + break;
1.173 + default:
1.174 + return KErrNotSupported;
1.175 + }
1.176 + pCmd++;
1.177 + }
1.178 + }
1.179 + return KErrNone;
1.180 + }
1.181 +
1.182 +
1.183 +
1.184 +
1.185 +///////////////////////////////////////////////////////////////////////////////
1.186 +//
1.187 +// TYAX specific routines
1.188 +//
1.189 +///////////////////////////////////////////////////////////////////////////////
1.190 +// Clear the status register
1.191 +///////////////////////////////////////////////////////////////////////////////
1.192 +void tyaxClearStatus(TUint32 address)
1.193 + {
1.194 + volatile TUint16 *p = (TUint16 *)address;
1.195 + *p=KCmdClearStatus; // clear status reg
1.196 + }
1.197 +
1.198 +///////////////////////////////////////////////////////////////////////////////
1.199 +// Wait until cmd completes
1.200 +///////////////////////////////////////////////////////////////////////////////
1.201 +void tyaxWaitUntilReady(TUint32 address, TUint16 cmd)
1.202 + {
1.203 + volatile TUint16 *pF = (TUint16 *)address;
1.204 + TUint16 s=0;
1.205 + TInt i=KFlashRetries;
1.206 +
1.207 + for (; i>0 && ((s&KStatusBusy)!=KStatusBusy); --i) // check ready bit
1.208 + {
1.209 + *pF=cmd;
1.210 + s=*pF;
1.211 + }
1.212 + if (i==0)
1.213 + {
1.214 + PrintToScreen(_L("Write timed out"));
1.215 + BOOT_FAULT();
1.216 + }
1.217 + if (s&KStatusCmdSeqError)
1.218 + {
1.219 + PrintToScreen(_L("Write error s=%x pF=0x%x\n"), s, pF);
1.220 + }
1.221 + }
1.222 +
1.223 +///////////////////////////////////////////////////////////////////////////////
1.224 +// Unlock Flash
1.225 +///////////////////////////////////////////////////////////////////////////////
1.226 +void tyaxUnlock(TUint32 address)
1.227 + {
1.228 + TYAX_PRINTF(RDebug::Printf("tyaxUnlock(0x%08x)", address));
1.229 + TUint16 * pF = (TUint16*)address;
1.230 + // Unlock
1.231 + *pF=KCmdClearBlockLockBit1;
1.232 + *pF=KCmdClearBlockLockBit2;
1.233 + }
1.234 +
1.235 +
1.236 +
1.237 +
1.238 +
1.239 +
1.240 +
1.241 +
1.242 +
1.243 +
1.244 +
1.245 +
1.246 +
1.247 +///////////////////////////////////////////////////////////////////////////////
1.248 +//
1.249 +// GENERIC - implementations of the generic routines
1.250 +//
1.251 +// - reset
1.252 +// - erase
1.253 +// - write
1.254 +//
1.255 +///////////////////////////////////////////////////////////////////////////////
1.256 +// Reset Flash
1.257 +///////////////////////////////////////////////////////////////////////////////
1.258 +TInt cfiReset(TUint32 flashId, TUint32 address)
1.259 + {
1.260 + SPANSION_PRINTF(RDebug::Printf("cfiReset(0x%08x)", address));
1.261 +
1.262 + volatile TUint8 * p = (TUint8*)address;
1.263 + *(p)=0xF0; // reset spansion flash
1.264 + return KErrNone;
1.265 + }
1.266 +
1.267 +///////////////////////////////////////////////////////////////////////////////
1.268 +// Reset Flash
1.269 +///////////////////////////////////////////////////////////////////////////////
1.270 +TInt tyaxReset(TUint32 flashId, TUint32 address)
1.271 + {
1.272 + TYAX_PRINTF(RDebug::Printf("tyaxReset(0x%08x)", address));
1.273 +
1.274 + TUint16 * p = (TUint16*)address;
1.275 +
1.276 + // clear the status register
1.277 + tyaxClearStatus((TUint32)address);
1.278 +
1.279 + // write to linear base and set strataflash into readarray mode
1.280 + *p=KCmdReadArrayMode;
1.281 + return KErrNone;
1.282 + }
1.283 +
1.284 +
1.285 +
1.286 +
1.287 +///////////////////////////////////////////////////////////////////////////////
1.288 +// Erase a block of flash
1.289 +///////////////////////////////////////////////////////////////////////////////
1.290 +TInt spansionErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize)
1.291 + {
1.292 + SPANSION_PRINTF(RDebug::Printf("spansionErase 0x%08x", anAddr));
1.293 +
1.294 + volatile TUint32 base=anAddr&~(KFlashEraseBlockSize-1); // round base address down to block
1.295 + volatile TUint32 end=anAddr+aSize;
1.296 + end=(end+KFlashEraseBlockSize-1)&~(KFlashEraseBlockSize-1); // round end address up to block
1.297 + TUint32 size=end-base;
1.298 + volatile TUint8* p=(volatile TUint8*)base;
1.299 +
1.300 + 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));
1.301 +
1.302 + cfiReset(flashId, aBase);
1.303 + for (; size; size-=KFlashEraseBlockSize, p+=(KFlashEraseBlockSize>>1))
1.304 + {
1.305 + CfiCommand(aBase, base, CfiErase);
1.306 +
1.307 + TUint retries = KFlashRetries;
1.308 + while ((*(volatile TUint8*)anAddr != 0xFF) && (retries != 0))
1.309 + {
1.310 + retries--;
1.311 + }
1.312 + if (retries==0)
1.313 + {
1.314 + 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);
1.315 + }
1.316 + cfiReset(flashId, aBase);
1.317 + }
1.318 + return 0;
1.319 + }
1.320 +
1.321 +
1.322 +///////////////////////////////////////////////////////////////////////////////
1.323 +// Erase a block of flash
1.324 +///////////////////////////////////////////////////////////////////////////////
1.325 +TInt tyaxErase(TUint32 flashId, TUint32 aBase, TUint32 anAddr, TUint32 aSize)
1.326 + {
1.327 + TUint32 base=anAddr&~(KFlashEraseBlockSize-1); // round base address down to block
1.328 + TUint32 end=anAddr+aSize;
1.329 + end=(end+KFlashEraseBlockSize-1)&~(KFlashEraseBlockSize-1); // round end address up to block
1.330 + TUint32 size=end-base;
1.331 + volatile TUint16* p=(volatile TUint16*)base;
1.332 +
1.333 + // write to linear base and set strataflash into readarray mode
1.334 + *p=KCmdReadArrayMode;
1.335 + // clear the status register
1.336 + *p=KCmdClearStatus;
1.337 + for (; size; size-=KFlashEraseBlockSize, p+=(KFlashEraseBlockSize>>1))
1.338 + {
1.339 + // Unlock
1.340 + *p=KCmdClearBlockLockBit1;
1.341 + *p=KCmdClearBlockLockBit2;
1.342 + // Erase
1.343 + *p=KCmdBlockErase1; // block erase
1.344 + *p=KCmdBlockErase2; // block erase confirm
1.345 +
1.346 + // wait for the erase to finish
1.347 + while ((*p & KStatusBusy)!=KStatusBusy);
1.348 +
1.349 + // put the flash block back to normal
1.350 + TUint32 s=*p;
1.351 + *p=KCmdClearStatus; // clear status reg
1.352 + *p=KCmdReadArrayMode;
1.353 +
1.354 + if (s & KStatusLockBitError)
1.355 + {
1.356 + // error
1.357 + RDebug::Printf("Erase Failed: addr:0x%x status: 0x%x", p, s);
1.358 + return (TUint32)p-anAddr+1;
1.359 + }
1.360 + }
1.361 + return 0;
1.362 + }
1.363 +
1.364 +
1.365 +///////////////////////////////////////////////////////////////////////////////
1.366 +// Write a block of flash
1.367 +///////////////////////////////////////////////////////////////////////////////
1.368 +TInt spansionWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
1.369 +// Assume aSize <= KFlashWriteBufSize
1.370 + {
1.371 + SPANSION_PRINTF(WRITE_PRINTF(RDebug::Printf("spansionWrite anAddr=0x%08x, aSize=0x%08x", anAddr, aSize)));
1.372 +
1.373 + volatile TUint8 * base = (TUint8 *)FlashAddress;
1.374 + volatile TUint16 * pDest = (TUint16*)anAddr;
1.375 + volatile TUint16 * pSrc = (TUint16*)aPS;
1.376 + volatile TUint16 * pEnd = (TUint16*)(anAddr+aSize);
1.377 +
1.378 + for (; pDest < pEnd; pDest++, pSrc++)
1.379 + {
1.380 + CfiCommand((TUint32)base, (TUint32)base, CfiWrite);
1.381 + *pDest = *pSrc;
1.382 +
1.383 + TUint retries = KFlashRetries;
1.384 + while ((*pDest != *pSrc) && (retries != 0))
1.385 + {
1.386 + retries--;
1.387 + }
1.388 +
1.389 + if (*pDest != *pSrc)
1.390 + {
1.391 + RDebug::Printf("Write failed 0x%x=0x%x == 0x%x", pDest, *pSrc, *pDest);
1.392 + return 1;
1.393 + }
1.394 + }
1.395 + return 0;
1.396 + }
1.397 +
1.398 +///////////////////////////////////////////////////////////////////////////////
1.399 +// Write a block of flash
1.400 +///////////////////////////////////////////////////////////////////////////////
1.401 +// Assume aSize <= KFlashWriteBufSize
1.402 +TInt tyaxWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
1.403 + {
1.404 + TYAX_PRINTF(WRITE_PRINTF(RDebug::Printf("tyaxWrite anAddr=0x%08x, aSize=0x%08x", anAddr, aSize)));
1.405 +
1.406 + volatile TUint16* pF=(volatile TUint16*)anAddr;
1.407 +
1.408 + tyaxUnlock(anAddr);
1.409 + tyaxClearStatus(anAddr);
1.410 +
1.411 + if (flashInfo[flashId].deviceId == CFI_DEV_SIBLEY)
1.412 + {
1.413 + tyaxWaitUntilReady(anAddr, KCmdWriteStatusSibley);
1.414 + }
1.415 + else
1.416 + {
1.417 + tyaxWaitUntilReady(anAddr, KCmdWriteStatus);
1.418 + }
1.419 +
1.420 + // convert to words - 1
1.421 + TInt16 l=(aSize>>1)-1;
1.422 + *pF=l; // Write no of words
1.423 + const TUint16* pS=(const TUint16*)aPS;
1.424 + for (;l>=0;l--)
1.425 + {
1.426 + *pF++=*pS++;
1.427 + }
1.428 + pF=(volatile TUint16*)anAddr;
1.429 + *pF=0xD0; // Confirm
1.430 +
1.431 + tyaxWaitUntilReady(anAddr, KCmdReadStatus);
1.432 + tyaxReset(flashId, anAddr);
1.433 +
1.434 + return 0;
1.435 + }
1.436 +
1.437 +
1.438 +
1.439 +
1.440 +
1.441 +
1.442 +
1.443 +
1.444 +
1.445 +
1.446 +
1.447 +
1.448 +///////////////////////////////////////////////////////////////////////////////
1.449 +//
1.450 +// WRAPPERS
1.451 +//
1.452 +// A top level routine to prevent each function checking the flash type
1.453 +//
1.454 +///////////////////////////////////////////////////////////////////////////////
1.455 +TInt flashReset(TUint32 flashId, TUint32 address)
1.456 + {
1.457 + PRINTF(RDebug::Printf("flashReset()"));
1.458 +
1.459 + TInt retVal = KErrNotSupported;
1.460 +
1.461 + if (flashInfo[flashId].reset != NULL)
1.462 + {
1.463 + retVal = flashInfo[flashId].reset(flashId, address);
1.464 + }
1.465 +
1.466 + return retVal;
1.467 + }
1.468 +
1.469 +TInt flashErase(TUint32 flashId, TUint32 base, TUint32 address, TUint32 size)
1.470 + {
1.471 + PRINTF(RDebug::Printf("flashErase()"));
1.472 +
1.473 + TInt retVal = KErrNone;
1.474 +
1.475 + if (flashInfo[flashId].erase != NULL)
1.476 + {
1.477 + retVal = flashInfo[flashId].erase(flashId, base, address, size);
1.478 + }
1.479 +
1.480 + return retVal;
1.481 + }
1.482 +
1.483 +TInt flashWrite(TUint32 flashId, TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
1.484 + {
1.485 + WRITE_PRINTF(RDebug::Printf("flashWrite()"));
1.486 +
1.487 + TInt retVal = KErrNone;
1.488 +
1.489 + if (flashInfo[flashId].write != NULL)
1.490 + {
1.491 + retVal = flashInfo[flashId].write(flashId, anAddr, aSize, aPS);
1.492 + }
1.493 +
1.494 + return retVal;
1.495 + }
1.496 +
1.497 +
1.498 +///////////////////////////////////////////////////////////////////////////////
1.499 +//
1.500 +// Flash ID
1.501 +//
1.502 +// Identify the flash part at the given address
1.503 +// returns an index into the flashInfo structure
1.504 +///////////////////////////////////////////////////////////////////////////////
1.505 +TInt flashId(TUint32 address)
1.506 + {
1.507 + TUint deviceIndex = FLASH_TYPE_UNKNOWN;
1.508 +
1.509 + volatile TUint16* p16=(volatile TUint16*)address; // used for 16 bit read/write to the flash
1.510 +
1.511 + // Put flash into CFI query mode using 8 bit writes
1.512 + CfiCommand(address, address, CfiQuery);
1.513 +
1.514 + // Read ID codes using 16 bit reads
1.515 + // if we ever need to support 8 bit devices, we may need to change this to 2 x 8 bit reads per attribute
1.516 + TUint16 manufacturerId = *(p16 );
1.517 + TUint16 deviceId = *(p16+1);
1.518 +
1.519 + for (TUint32 i=0; flashInfo[i].manufacturerId !=0; i++)
1.520 + {
1.521 + PRINTF(RDebug::Printf("Check device: M 0x%04x D 0x%04x", flashInfo[i].manufacturerId, flashInfo[i].deviceId));
1.522 +
1.523 + if ( ( flashInfo[i].manufacturerId == manufacturerId)
1.524 + && ( (flashInfo[i].deviceId == CFI_DEV_ANY ) // support generic flash devices
1.525 + ||(flashInfo[i].deviceId == deviceId )
1.526 + )
1.527 + )
1.528 + {
1.529 + PRINTF(RDebug::Print(_L("Found device: %s (Manufacturer=%x Device=%x)"), flashInfo[i].name.Ptr(), flashInfo[i].manufacturerId, flashInfo[i].deviceId));
1.530 + deviceIndex = i;
1.531 + break;
1.532 + }
1.533 + }
1.534 + if (deviceIndex == FLASH_TYPE_UNKNOWN)
1.535 + {
1.536 + RDebug::Printf("Flash type unknown: Manufacturer ID = %04x, Device ID = %04x", manufacturerId, deviceId );
1.537 + }
1.538 + flashReset(deviceIndex, (TUint32)FlashAddress);
1.539 + return deviceIndex;
1.540 + }
1.541 +
1.542 +
1.543 +///////////////////////////////////////////////////////////////////////////////
1.544 +///////////////////////////////////////////////////////////////////////////////
1.545 +
1.546 +
1.547 +
1.548 +
1.549 +
1.550 +GLDEF_C TUint32 * GetFlashChunk()
1.551 + {
1.552 + // return if already initialised
1.553 + if (FlashAddress != NULL)
1.554 + return FlashAddress;
1.555 +
1.556 + TInt r = User::LoadLogicalDevice(KBootldrLddName);
1.557 +
1.558 + r = LddFlash.Open();
1.559 + if (r!=KErrNone)
1.560 + {
1.561 + PrintToScreen(_L("FAULT due to LddFlash open\r\n"));
1.562 + BOOT_FAULT();
1.563 + }
1.564 +
1.565 + TUint8* kernelAddress;
1.566 + r=LddFlash.CreateChunk(KNORFlashTargetSize,(TAny**)&kernelAddress);
1.567 + if (r!=KErrNone)
1.568 + {
1.569 + PrintToScreen(_L("FAULT due to chunk create\r\n"));
1.570 + BOOT_FAULT();
1.571 + }
1.572 +
1.573 + // If we're running from RAM flash will be in a different place...
1.574 + r = LddFlash.CommitMemory(KNORFlashTargetSize,addr_to_page(KNORFlashTargetAddr));
1.575 + if (r!=KErrNone)
1.576 + {
1.577 + PrintToScreen(_L("FAULT due to commit\r\n"));
1.578 + BOOT_FAULT();
1.579 + }
1.580 +
1.581 + r = LddFlash.GetChunkHandle(TheFlashChunk);
1.582 + if (r!=KErrNone)
1.583 + {
1.584 + PrintToScreen(_L("FAULT due to handle\r\n"));
1.585 + BOOT_FAULT();
1.586 + }
1.587 +
1.588 + TUint8* Base = TheFlashChunk.Base();
1.589 + FlashAddress = (TUint32*)Base;
1.590 + FlashId = flashId((TUint32)FlashAddress);
1.591 +
1.592 + return FlashAddress;
1.593 + }
1.594 +
1.595 +GLDEF_C void NotifyDataAvailable(TInt aTotalAmount)
1.596 + {
1.597 + Available=(TUint32)aTotalAmount;
1.598 + }
1.599 +
1.600 +GLDEF_C void NotifyDownloadComplete()
1.601 + {
1.602 + Complete=ETrue;
1.603 + }
1.604 +
1.605 +GLDEF_C TBool BlankCheck(TUint32 anAddr, TUint32 aSize)
1.606 + {
1.607 + const TUint16* p=(const TUint16*)anAddr;
1.608 + const TUint16* pE=p+(aSize>>1);
1.609 + TBool rv=ETrue;
1.610 +
1.611 + while(p<pE)
1.612 + {
1.613 + if (*p!=0xffff)
1.614 + {
1.615 + 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));
1.616 + rv=EFalse;
1.617 + break;
1.618 + }
1.619 + p++;
1.620 + }
1.621 + if (rv)
1.622 + {
1.623 + PRINTF(RDebug::Printf("BlankCheck: %x is blank", anAddr));
1.624 + }
1.625 + return rv;
1.626 + }
1.627 +
1.628 +///////////////////////////////////////////////////////////////////////////////
1.629 +//
1.630 +// Erase
1.631 +//
1.632 +// This function is used by the variant code. The variant code shouldn't care
1.633 +// about the Flash ID, so I've left this function here as a wrapper for the
1.634 +// internal flashErase function, passing in a nasty global variable containing
1.635 +// the Flash ID.
1.636 +//
1.637 +///////////////////////////////////////////////////////////////////////////////
1.638 +GLDEF_C TInt Erase(TUint32 anAddr, TUint32 aSize)
1.639 + {
1.640 + flashErase(FlashId, (TUint32)FlashAddress, anAddr, aSize);
1.641 + return 0;
1.642 + }
1.643 +
1.644 +
1.645 +///////////////////////////////////////////////////////////////////////////////
1.646 +//
1.647 +// Write
1.648 +//
1.649 +// This function is used by the variant code. As well as the Flash ID comment
1.650 +// from above (see Erase), the variant shouldn't have to care about internal
1.651 +// buffer sizes, etc.
1.652 +//
1.653 +///////////////////////////////////////////////////////////////////////////////
1.654 +GLDEF_C TInt Write(TUint32 anAddr, TUint32 aSize, const TUint32* aPS)
1.655 + {
1.656 + TInt rv=0;
1.657 + do
1.658 + {
1.659 + if ((rv=flashWrite(FlashId, anAddr, KFlashWriteBufSize, aPS))!=0)
1.660 + {
1.661 + break;
1.662 + }
1.663 + anAddr+=KFlashWriteBufSize;
1.664 + aPS+=KFlashWriteBufSize>>2;
1.665 + aSize-=KFlashWriteBufSize;
1.666 + } while(aSize);
1.667 + return rv;
1.668 + }
1.669 +
1.670 +TInt FlashThread(TAny*)
1.671 + {
1.672 + // If this thread crashes we want it to take the system down
1.673 + User::SetCritical(User::ESystemPermanent);
1.674 +
1.675 + GetFlashChunk();
1.676 + if (FlashBootLoader)
1.677 + {
1.678 + PrintToScreen(_L("*** Reflashing bootloader ***\r\n"));
1.679 + FlashImageAddr=(TLinAddr)FlashAddress;
1.680 + // sanity check...
1.681 + if ((TUint32)ImageSize > KNORFlashMaxBootloaderSize)
1.682 + {
1.683 + PrintToScreen(_L("Image is larger than the flash area (%d > %d) bytes.\r\n"), ImageSize, KNORFlashMaxBootloaderSize);
1.684 + return KErrNotSupported;
1.685 + }
1.686 + }
1.687 + else
1.688 + {
1.689 + PrintToScreen(_L("*** Writing to NOR Flash ***\r\n"));
1.690 + FlashImageAddr=(TLinAddr)FlashAddress+KNORFlashMaxBootloaderSize;
1.691 +
1.692 + // sanity check...
1.693 + if ((TUint32)ImageSize > KNORFlashMaxImageSize)
1.694 + {
1.695 + PrintToScreen(_L("Image is larger than the flash area (%d > %d) bytes.\r\n"), ImageSize, KNORFlashMaxImageSize);
1.696 + return KErrNotSupported;
1.697 + }
1.698 + }
1.699 +
1.700 + FlashImageSize=(TUint32)ImageSize;
1.701 + Complete=EFalse;
1.702 +
1.703 + TUint32 imgSzMb=(FlashImageSize+0xfffff)&~0xfffff; // round image size up to 1Mb
1.704 +
1.705 + InitProgressBar(1,imgSzMb,_L("ERASE"));
1.706 + TUint32 base=FlashImageAddr;
1.707 + TUint32 end=base+imgSzMb;
1.708 + TInt r=KErrNone;
1.709 + while(base<end)
1.710 + {
1.711 + if (!BlankCheck(base,KFlashEraseBlockSize))
1.712 + {
1.713 + r=Erase(base, KFlashEraseBlockSize);
1.714 + if (r!=KErrNone)
1.715 + {
1.716 + PrintToScreen(_L("Erase failed 0x%x\r\n"), r);
1.717 + RDebug::Printf("Erase failed 0x%x", r);
1.718 + // make this a rdebug
1.719 + BOOT_FAULT();
1.720 + }
1.721 + }
1.722 + if (!BlankCheck(base,KFlashEraseBlockSize))
1.723 + {
1.724 + PrintToScreen(_L("BlankCheck failed 0x%x\r\n"),base);
1.725 + RDebug::Printf("BlankCheck failed at adress 0x%08x with error code 0x%x",base,r);
1.726 + //BOOT_FAULT(); // why crash at this point, retry is better, surely?
1.727 + }
1.728 + else
1.729 + {
1.730 + // only move to next block and update progress if the block erase passed
1.731 + base+=KFlashEraseBlockSize;
1.732 + UpdateProgressBar(1,base-FlashImageAddr);
1.733 + }
1.734 + }
1.735 +
1.736 + base=FlashImageAddr;
1.737 + while(base<end)
1.738 + {
1.739 +
1.740 + if (!BlankCheck(base,KFlashEraseBlockSize))
1.741 + {
1.742 + PrintToScreen(_L("BlankCheck 2 failed 0x%x\r\n"),base);
1.743 + RDebug::Printf("BlankCheck 2 failed at adress 0x%08x with error code 0x%x",base,r);
1.744 + BOOT_FAULT();
1.745 + }
1.746 + base+=KFlashEraseBlockSize;
1.747 + }
1.748 +
1.749 + InitProgressBar(1,FlashImageSize,_L("WRITE"));
1.750 + TUint32 source=DestinationAddress(); // start of image in RAM
1.751 + if (ImageHeaderPresent)
1.752 + source+=256; // skip header if present
1.753 + TUint32 target=FlashImageAddr; // target in flash
1.754 + TBool complete=EFalse;
1.755 + TUint32 used_bytes=0;
1.756 +
1.757 + // while the image hasn't been written fully
1.758 + while ((target-FlashImageAddr) < FlashImageSize)
1.759 + {
1.760 + used_bytes=source-DestinationAddress();
1.761 +
1.762 + complete=Complete; // must check Complete before Available
1.763 +
1.764 + // if there isn't anything ready, go back to the top
1.765 + if (Available<(used_bytes+256) && !complete)
1.766 + {
1.767 + continue; // wait for 256 bytes more data
1.768 + }
1.769 + TUint32 write_block_size=Available-used_bytes; // how much is ready
1.770 + write_block_size &= ~(KFlashWriteBufSize-1); // only write whole buffers
1.771 +
1.772 + while (write_block_size)
1.773 + {
1.774 + TUint32 write_size=Min(write_block_size,(TUint32)0x400); // update progress after each 1K
1.775 + r=Write(target,write_size,(const TUint32*)source);
1.776 + if (r!=KErrNone)
1.777 + {
1.778 + PrintToScreen(_L("Write failed 0x%x"),r);
1.779 + BOOT_FAULT();
1.780 + }
1.781 +
1.782 + target+=write_size;
1.783 + source+=write_size;
1.784 + write_block_size-=write_size;
1.785 + UpdateProgressBar(1,target-FlashImageAddr);
1.786 + }
1.787 + }
1.788 +
1.789 + PrintToScreen(_L("Verifying image...\r\n"));
1.790 +
1.791 + source=DestinationAddress(); // start of image in RAM
1.792 + if (ImageHeaderPresent)
1.793 + source+=256; // skip header if present
1.794 + base=FlashImageAddr;
1.795 + volatile TUint16* pRam=(volatile TUint16*)source;
1.796 + volatile TUint16* pFlash=(volatile TUint16*)base;
1.797 + volatile TUint16* pFlashEnd=pFlash+(FlashImageSize>>1);
1.798 +
1.799 + InitProgressBar(1, FlashImageSize, _L("VERIFY"));
1.800 + while(pFlash<pFlashEnd)
1.801 + {
1.802 + if (*pFlash++ != *pRam++)
1.803 + {
1.804 + PrintToScreen(_L("Verify error at byte %d (0x%x != 0x%x)\r\n"),
1.805 + ((pFlash-1) - (volatile TUint16*)base) * 2, (*(pFlash-1)), (*(pRam-1)));
1.806 +
1.807 + PrintToScreen(_L("VERIFY %d"),(TInt)(pFlash-1));
1.808 + BOOT_FAULT();
1.809 + }
1.810 +
1.811 + if (!((TUint32)pFlash % 0x400))
1.812 + UpdateProgressBar(1,(TUint32)pFlash-(TUint32)FlashImageAddr);
1.813 + }
1.814 +
1.815 + PrintToScreen(_L("Verify complete\r\n"));
1.816 +
1.817 + if (FlashBootLoader)
1.818 + {
1.819 + PrintToScreen(_L("Rebooting in %d Seconds...\r\n"), KRebootDelaySecs);
1.820 +
1.821 + InitProgressBar(1, KRebootDelaySecs, _L("DELAY "));
1.822 + for (TUint i=0 ; i<KRebootDelaySecs ; ++i)
1.823 + {
1.824 + User::After(1000000); // Sleep in millisecs
1.825 + UpdateProgressBar(1, i);
1.826 + }
1.827 + UpdateProgressBar(1, KRebootDelaySecs); // let it get to the end
1.828 + PrintToScreen(_L("Rebooting...\r\n"));
1.829 + User::After(10000);
1.830 + Restart(KtRestartReasonHardRestart);
1.831 + }
1.832 +
1.833 + PrintToScreen(_L("Booting Image...\r\n"));
1.834 + Restart(KtRestartReasonBootRestart | KtRestartReasonNORImage);
1.835 +
1.836 + // NOTREACHED
1.837 + return 0;
1.838 + }
1.839 +
1.840 +GLDEF_C TInt InitFlashWrite()
1.841 + {
1.842 + // start thread
1.843 + RThread t;
1.844 + TInt r=t.Create(KLitThreadName,FlashThread,0x2000,NULL,NULL);
1.845 + if (r!=KErrNone)
1.846 + {
1.847 + return r;
1.848 + }
1.849 + t.SetPriority(EPriorityLess);
1.850 + t.Resume();
1.851 + return KErrNone;
1.852 + }
1.853 +#endif //__SUPPORT_FLASH_REPRO__