1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/bsptemplate/asspandvariant/template_variant/specific/lffsdev.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,668 @@
1.4 +// Copyright (c) 2004-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 +// template\Template_Variant\Specific\lffsdev.cpp
1.18 +// Implementation of a Logging Flash file system (LFFS) physical device driver
1.19 +// for a standard Common Flash Interface (CFI) based NOR flash chip.
1.20 +// This file is part of the Template Base port
1.21 +// N.B. This sample code assumes that:
1.22 +// (1) the device does not provide an interrupt i.e. it needs to be polled using a timer
1.23 +// to ascertain when an Erase/Write operation has completed.
1.24 +// (2) the flash chip does not have 'read-while-write' support.
1.25 +//
1.26 +//
1.27 +
1.28 +#include "lffsdev.h"
1.29 +#include "variant.h"
1.30 +
1.31 +#ifdef _DEBUG
1.32 +#define CHANGE_ERASE_STATE(x) {TUint32 s=iEraseState; iEraseState=x; __KTRACE_OPT(KLOCDRV,Kern::Printf("ErSt: %d->%d",s,x));}
1.33 +#else
1.34 +#define CHANGE_ERASE_STATE(x) iEraseState=x
1.35 +#endif
1.36 +
1.37 +//
1.38 +// TO DO: (mandatory)
1.39 +//
1.40 +// Define the pyhsical base address of the NOR-Flash
1.41 +// This is only example code... you will need to modify it for your hardware
1.42 +const TPhysAddr KFlashPhysicalBaseAddress = 0x04000000;
1.43 +
1.44 +
1.45 +/********************************************
1.46 + * Common Flash Interface (CFI) query stuff
1.47 + ********************************************/
1.48 +
1.49 +/**
1.50 +Read an 8-bit value from the device at the specified offset
1.51 +
1.52 +@param aOffset the address in device words
1.53 +*/
1.54 +TUint32 DMediaDriverFlashTemplate::ReadQueryData8(TUint32 aOffset)
1.55 + {
1.56 + volatile TUint8* pF=(volatile TUint8*)(iBase+FLASH_ADDRESS_IN_BYTES(aOffset));
1.57 + return pF[0];
1.58 + }
1.59 +
1.60 +/**
1.61 +Read a 16-bit value from the device at the specified offset
1.62 +
1.63 +@param aOffset the address in device words
1.64 +*/
1.65 +TUint32 DMediaDriverFlashTemplate::ReadQueryData16(TUint32 aOffset)
1.66 + {
1.67 + volatile TUint8* pF=(volatile TUint8*)(iBase);
1.68 + return
1.69 + pF[FLASH_ADDRESS_IN_BYTES(aOffset+0)] |
1.70 + (pF[FLASH_ADDRESS_IN_BYTES(aOffset+1)] << 8);
1.71 + }
1.72 +
1.73 +/**
1.74 + Put the device into query mode to read the flash parameters.
1.75 + */
1.76 +void DMediaDriverFlashTemplate::ReadFlashParameters()
1.77 + {
1.78 + volatile TFLASHWORD* pF=(volatile TFLASHWORD*)iBase + KCmdReadQueryOffset;
1.79 + *pF=KCmdReadQuery;
1.80 +
1.81 + TUint32 qd=ReadQueryData16(KQueryOffsetQRY)|(ReadQueryData8(KQueryOffsetQRY+2)<<16);
1.82 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query QRY=%08x",qd));
1.83 + __ASSERT_ALWAYS(qd==0x595251,FLASH_FAULT());
1.84 +
1.85 + qd = FLASH_BUS_DEVICES << ReadQueryData8(KQueryOffsetSizePower);
1.86 +
1.87 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query Size=%08x",qd));
1.88 + iTotalSize=qd;
1.89 +
1.90 + qd = FLASH_BUS_DEVICES << ReadQueryData16(KQueryOffsetWriteBufferSizePower);
1.91 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query WBSize=%08x",qd));
1.92 + iWriteBufferSize=qd;
1.93 +
1.94 + qd = (ReadQueryData16(KQueryOffsetEraseBlockSize)) << (8 + FLASH_BUS_DEVICES-1);
1.95 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query EBSize=%08x",qd));
1.96 + iEraseBlockSize=qd;
1.97 +
1.98 + *pF=KCmdReadArray;
1.99 + }
1.100 +
1.101 +
1.102 +/********************************************
1.103 + * Common Flash Interface (CFI) main code
1.104 + ********************************************/
1.105 +
1.106 +/**
1.107 +NOR flash LFFS constructor.
1.108 +
1.109 +@param aMediaId Media id number from ELOCD
1.110 +*/
1.111 +DMediaDriverFlashTemplate::DMediaDriverFlashTemplate(TInt aMediaId)
1.112 + : DMediaDriverFlash(aMediaId),
1.113 + iHoldOffTimer(HoldOffTimerFn,this),
1.114 + iEventDfc(EventDfc,this,NULL,2)
1.115 + {
1.116 + // iWriteState = EWriteIdle;
1.117 + // iEraseState = EEraseIdle;
1.118 + }
1.119 +
1.120 +/**
1.121 +Device specific implementation of the NOR LFFS initialisation routine.
1.122 +
1.123 +@see DMediaDriverFlash::Initialise
1.124 +@return KErrNone unless the write data buffer couldn't be allocated or the
1.125 + timer interrupt could not be bound.
1.126 + */
1.127 +TInt DMediaDriverFlashTemplate::Initialise()
1.128 + {
1.129 + iEventDfc.SetDfcQ(iPrimaryMedia->iDfcQ);
1.130 + iData=(TUint8*)Kern::Alloc(KDataBufSize);
1.131 + if (!iData)
1.132 + return KErrNoMemory;
1.133 +
1.134 + // Create temporary HW chunk to read FLASH device parameters (especially size)
1.135 + DPlatChunkHw* pC = NULL;
1.136 + TInt r = DPlatChunkHw::New(pC, KFlashPhysicalBaseAddress, 0x1000, EMapAttrSupRw|EMapAttrFullyBlocking);
1.137 + if (r!=KErrNone)
1.138 + return r;
1.139 + iBase = pC->LinearAddress();
1.140 + ReadFlashParameters();
1.141 + // close temporary chunk and open chunk with correct size
1.142 + pC->Close(NULL);
1.143 + r = DPlatChunkHw::New(iFlashChunk, KFlashPhysicalBaseAddress, iTotalSize, EMapAttrSupRw|EMapAttrFullyBlocking);
1.144 + if (r!=KErrNone)
1.145 + return r;
1.146 + iBase = iFlashChunk->LinearAddress();
1.147 +
1.148 + r=Interrupt::Bind(KIntIdTimer1, Isr, this);
1.149 + if (r!=KErrNone)
1.150 + {
1.151 + __KTRACE_OPT(KLOCDRV, Kern::Printf("Flash:Isr Bind failed"));
1.152 + return r;
1.153 + }
1.154 +
1.155 + // TO DO: (mandatory)
1.156 + // Write to the appropriate hardware register(s) to
1.157 + // configure (if necessary) and enable the timer hardware
1.158 + //
1.159 +
1.160 + // Enable the timer interrupt
1.161 + Interrupt::Enable(KIntIdTimer1);
1.162 +
1.163 + return KErrNone;
1.164 + }
1.165 +
1.166 +/**
1.167 +Used by the generic flash media driver code to get the erase block size in
1.168 +bytes.
1.169 + */
1.170 +TUint32 DMediaDriverFlashTemplate::EraseBlockSize()
1.171 + {
1.172 + return iEraseBlockSize;
1.173 + }
1.174 +
1.175 +/**
1.176 +@return Return size of lffs in bytes
1.177 +*/
1.178 +TUint32 DMediaDriverFlashTemplate::TotalSize()
1.179 + {
1.180 + return iTotalSize;
1.181 + }
1.182 +
1.183 +/**
1.184 +Read at the location indicated by DMediaDriverFlash::iReadReq.
1.185 +Where Pos() is the read location
1.186 +
1.187 +@return >0 Defer request to ELOCD. A write is in progress
1.188 +@return KErrNone Erase has been started
1.189 +@return <0 An error has occured.
1.190 +*/
1.191 +TInt DMediaDriverFlashTemplate::DoRead()
1.192 + {
1.193 + if (iWriteReq)
1.194 + return KMediaDriverDeferRequest; // write in progress so defer read
1.195 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoRead"));
1.196 + if (iEraseState==EEraseIdle || iEraseState==ESuspended)
1.197 + {
1.198 + // can do the read now
1.199 + TInt pos=(TInt)iReadReq->Pos();
1.200 + TInt len=(TInt)iReadReq->Length();
1.201 +
1.202 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoRead ibase: %x, pos: %x, len: %x",iBase,pos,len));
1.203 +
1.204 + // Issue a read array command
1.205 + // Porting note: Some devices may work without this step.
1.206 + // Ensure that the write is always dword aligned
1.207 + volatile TFLASHWORD* pF=(volatile TFLASHWORD*)((iBase+pos)&0xFFFFFFF0);
1.208 + *pF=KCmdReadArray;
1.209 +
1.210 + TPtrC8 des((const TUint8*)(iBase+pos),len);
1.211 + TInt r=iReadReq->WriteRemote(&des,0);
1.212 + Complete(EReqRead,r);
1.213 +
1.214 + // resume erase if necessary
1.215 + if (iEraseState==ESuspended)
1.216 + StartErase();
1.217 + }
1.218 + else if (iEraseState==EErase)
1.219 + {
1.220 + // erase in progress - suspend it
1.221 + SuspendErase();
1.222 + }
1.223 + else if (iEraseState==EEraseNoSuspend)
1.224 + CHANGE_ERASE_STATE(ESuspendPending); // wait for suspend to complete
1.225 +
1.226 +
1.227 + return KErrNone;
1.228 + }
1.229 +
1.230 +/**
1.231 +Write at the location indicated by DMediaDriverFlash::iWriteReq
1.232 +
1.233 +@return >0 Defer request to ELOCD. A read is in progress
1.234 +@return KErrNone Erase has been started
1.235 +@return <0 An error has occured.
1.236 + */
1.237 +TInt DMediaDriverFlashTemplate::DoWrite()
1.238 + {
1.239 + if (iReadReq)
1.240 + return KMediaDriverDeferRequest; // read in progress so defer write
1.241 +
1.242 + TInt pos=(TInt)iWriteReq->Pos();
1.243 + TInt len=(TInt)iWriteReq->Length();
1.244 + if (len==0)
1.245 + return KErrCompletion;
1.246 + TUint32 wb_mask=iWriteBufferSize-1;
1.247 + iWritePos=pos & ~wb_mask; // round media position down to write buffer boundary
1.248 + TInt wb_off=pos & wb_mask; // how many bytes of padding at beginning
1.249 + TInt start_len=Min(len,KDataBufSize-(TInt)wb_off);
1.250 + TInt write_len=(start_len+wb_off+wb_mask)&~wb_mask;
1.251 + memset(iData,0xff,iWriteBufferSize);
1.252 + memset(iData+write_len-iWriteBufferSize,0xff,iWriteBufferSize);
1.253 + TPtr8 des(iData+wb_off,0,start_len);
1.254 + TInt r=iWriteReq->ReadRemote(&des,0);
1.255 + if (r!=KErrNone)
1.256 + return r;
1.257 + iWriteReq->RemoteDesOffset()+=start_len;
1.258 + iWriteReq->Length()-=start_len;
1.259 + iDataBufPos=0;
1.260 + iDataBufRemain=write_len;
1.261 + iWriteError=KErrNone;
1.262 +
1.263 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Write iWritePos=%08x iDataBufRemain=%x",iWritePos,iDataBufRemain));
1.264 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Write Pos=%08x Length=%08x RemDesOff=%08x",
1.265 + (TInt)iWriteReq->Pos(),(TInt)iWriteReq->Length(),iWriteReq->RemoteDesOffset()));
1.266 +
1.267 + if (iEraseState==EEraseIdle || iEraseState==ESuspended)
1.268 + {
1.269 + // can start the write now
1.270 + iWriteState=EWriting;
1.271 + WriteStep();
1.272 + }
1.273 + else if (iEraseState==EErase)
1.274 + {
1.275 + // erase in progress - suspend it
1.276 + SuspendErase();
1.277 + }
1.278 + else if (iEraseState==EEraseNoSuspend)
1.279 + CHANGE_ERASE_STATE(ESuspendPending); // wait for suspend to complete
1.280 +
1.281 + return KErrNone;
1.282 + }
1.283 +
1.284 +void DMediaDriverFlashTemplate::WriteStep()
1.285 + {
1.286 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:WriteStep @%08x",iWritePos));
1.287 + if (iDataBufRemain)
1.288 + {
1.289 + // still data left in buffer
1.290 + volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iWritePos);
1.291 + TInt i=KMaxWriteSetupAttempts;
1.292 + *pF=KCmdClearStatusRegister;
1.293 + TUint32 s=0;
1.294 + for (; i>0 && ((s&KStsReady)!=KStsReady); --i)
1.295 + {
1.296 + *pF=KCmdWriteToBuffer; // send write command
1.297 + *pF=KCmdReadStatusRegister; // send read status command
1.298 + s=*pF; // read status reg
1.299 + }
1.300 + __KTRACE_OPT(KLOCDRV,Kern::Printf("i=%d, s=%08x",i,s));
1.301 +
1.302 + // calculate the buffer size in words -1
1.303 + TFLASHWORD l = (FLASH_BYTES_TO_WORDS(iWriteBufferSize)) - 1;
1.304 +
1.305 +#if FLASH_BUS_DEVICES == 2 // 2x16bit or 2x8bit devices
1.306 + l|= l<< BUS_WIDTH_PER_DEVICE;
1.307 +#elif FLASH_BUS_DEVICES == 4 // 4x8bit device
1.308 + l|= (l<<BUS_WIDTH_PER_DEVICE) | (l<<BUS_WIDTH_PER_DEVICE*2) (l<<BUS_WIDTH_PER_DEVICE*3);
1.309 +#endif
1.310 +
1.311 + // write the data length in words to the device(s)
1.312 + *pF=l;
1.313 +
1.314 + const TFLASHWORD* pS=(const TFLASHWORD*)(iData+iDataBufPos);
1.315 +
1.316 + // write the data
1.317 + TInt len;
1.318 + for (len = l; len>=0; len--)
1.319 + {
1.320 + *pF++=*pS++;
1.321 + }
1.322 +
1.323 + *(volatile TFLASHWORD *)(iBase+iWritePos) = KCmdConfirm;
1.324 +
1.325 + // set up timer to poll for completion
1.326 + StartPollTimer(KFlashWriteTimerPeriod,KFlashWriteTimerRetries);
1.327 +
1.328 + iWritePos+=iWriteBufferSize;
1.329 + iDataBufPos+=iWriteBufferSize;
1.330 + iDataBufRemain-=iWriteBufferSize;
1.331 + if (!iDataBufRemain)
1.332 + {
1.333 + // refill buffer
1.334 + TInt len=(TInt)iWriteReq->Length();
1.335 + if (!len)
1.336 + return; // all data has been written, complete request next time
1.337 + TUint32 wb_mask=iWriteBufferSize-1;
1.338 + TInt block_len=Min(len,KDataBufSize);
1.339 + TInt write_len=(block_len+wb_mask)&~wb_mask;
1.340 + memset(iData+write_len-iWriteBufferSize,0xff,iWriteBufferSize);
1.341 + TPtr8 des(iData,0,block_len);
1.342 + TInt r=iWriteReq->ReadRemote(&des,0);
1.343 + if (r!=KErrNone)
1.344 + {
1.345 + iWriteError=r;
1.346 + return; // leave iDataBufRemain=0 so request is terminated when write completes
1.347 + }
1.348 + iWriteReq->RemoteDesOffset()+=block_len;
1.349 + iWriteReq->Length()-=block_len;
1.350 + iDataBufPos=0;
1.351 + iDataBufRemain=write_len;
1.352 + }
1.353 + }
1.354 + else
1.355 + {
1.356 + // write request should have completed, maybe with an error
1.357 + __ASSERT_ALWAYS(iWriteReq->Length()==0 || iWriteError,FLASH_FAULT());
1.358 + iWriteState=EWriteIdle;
1.359 + Complete(EReqWrite,iWriteError);
1.360 + if (iEraseState==ESuspended)
1.361 + StartErase();
1.362 + }
1.363 + }
1.364 +
1.365 +/**
1.366 +Erase at the location indicated by DMediaDriverFlash::iEraseReq
1.367 +
1.368 +@return >0 Defer request to ELOCD. Read or a write is in progress
1.369 +@return KErrNone Erase has been started
1.370 +@return <0 An error has occured.
1.371 + */
1.372 +TInt DMediaDriverFlashTemplate::DoErase()
1.373 + {
1.374 + if (iReadReq || iWriteReq)
1.375 + return KMediaDriverDeferRequest; // read or write in progress so defer this request
1.376 + TUint32 pos=(TUint32)iEraseReq->Pos();
1.377 + TUint32 len=(TUint32)iEraseReq->Length();
1.378 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoErase %d@%08x",len,pos));
1.379 + if (len!=iEraseBlockSize)
1.380 + return KErrArgument; // only allow single-block erase
1.381 + if (pos & (iEraseBlockSize-1))
1.382 + return KErrArgument; // start position must be on erase block boundary
1.383 + iErasePos=pos;
1.384 + __ASSERT_ALWAYS(iEraseState==EEraseIdle,FLASH_FAULT());
1.385 + StartErase();
1.386 + return KErrNone;
1.387 + }
1.388 +
1.389 +void DMediaDriverFlashTemplate::StartHoldOffTimer()
1.390 + {
1.391 + // if this is a retry, don't allow suspends
1.392 + if (iEraseAttempt==0)
1.393 + iHoldOffTimer.OneShot(KEraseSuspendHoldOffTime);
1.394 + }
1.395 +
1.396 +void DMediaDriverFlashTemplate::CancelHoldOffTimer()
1.397 + {
1.398 + iHoldOffTimer.Cancel();
1.399 + ClearEvents(EHoldOffEnd);
1.400 + }
1.401 +
1.402 +void DMediaDriverFlashTemplate::ClearEvents(TUint32 aEvents)
1.403 + {
1.404 + __e32_atomic_and_ord32(&iEvents, ~aEvents);
1.405 + }
1.406 +
1.407 +void DMediaDriverFlashTemplate::HoldOffTimerFn(TAny* aPtr)
1.408 + {
1.409 + DMediaDriverFlashTemplate* p=(DMediaDriverFlashTemplate*)aPtr;
1.410 + p->IPostEvents(EHoldOffEnd);
1.411 + }
1.412 +
1.413 +void DMediaDriverFlashTemplate::StartPollTimer(TUint32 aPeriod, TUint32 aRetries)
1.414 + {
1.415 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Tmr %d * %d",aPeriod,aRetries));
1.416 +
1.417 + ClearEvents(EPollTimer);
1.418 + iPollPeriod=aPeriod;
1.419 + iPollRetries=aRetries;
1.420 + StartPollTimer();
1.421 + }
1.422 +
1.423 +void DMediaDriverFlashTemplate::StartPollTimer()
1.424 + {
1.425 + // TO DO: (mandatory)
1.426 + // Configure the hardware timer to expire after iPollPeriod ticks
1.427 + // and start the timer
1.428 +
1.429 + }
1.430 +
1.431 +void DMediaDriverFlashTemplate::EventDfc(TAny* aPtr)
1.432 + {
1.433 + DMediaDriverFlashTemplate* p=(DMediaDriverFlashTemplate*)aPtr;
1.434 + TUint32 e = __e32_atomic_swp_ord32(&p->iEvents, 0);
1.435 + if (e)
1.436 + p->HandleEvents(e);
1.437 + }
1.438 +
1.439 +void DMediaDriverFlashTemplate::HandleEvents(TUint32 aEvents)
1.440 + {
1.441 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Events %x",aEvents));
1.442 + if (aEvents & EHoldOffEnd)
1.443 + {
1.444 + if (iEraseState==ESuspendPending)
1.445 + {
1.446 + SuspendErase();
1.447 + }
1.448 + else if (iEraseState==EEraseNoSuspend)
1.449 + {
1.450 + CHANGE_ERASE_STATE(EErase); // can now be suspended
1.451 + }
1.452 + else
1.453 + {
1.454 + __KTRACE_OPT(KPANIC,Kern::Printf("iEraseState=%d",iEraseState));
1.455 + FLASH_FAULT();
1.456 + }
1.457 + }
1.458 + if (aEvents & EPollTimer)
1.459 + {
1.460 + volatile TFLASHWORD* pF=(volatile TFLASHWORD*)iBase;
1.461 + *pF=KCmdReadStatusRegister;
1.462 + if ((*pF & KStsReady)!=KStsReady)
1.463 + {
1.464 + // not ready yet
1.465 + if (--iPollRetries)
1.466 + {
1.467 + // try again
1.468 + StartPollTimer();
1.469 + }
1.470 + else
1.471 + // timed out
1.472 + aEvents|=ETimeout;
1.473 + }
1.474 + else
1.475 + {
1.476 + // ready
1.477 + TFLASHWORD s=*pF; // read full status value
1.478 + *pF=KCmdClearStatusRegister;
1.479 + DoFlashReady(s);
1.480 + }
1.481 + }
1.482 + if (aEvents & ETimeout)
1.483 + {
1.484 + DoFlashTimeout();
1.485 + }
1.486 + }
1.487 +
1.488 +void DMediaDriverFlashTemplate::StartErase()
1.489 + {
1.490 + TFLASHWORD s=KStsReady;
1.491 + TInt i;
1.492 + volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iErasePos);
1.493 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:StartErase %08x",pF));
1.494 + switch (iEraseState)
1.495 + {
1.496 + case EEraseIdle: // first attempt to erase
1.497 + iEraseAttempt=-1;
1.498 + // coverity[fallthrough]
1.499 + // fallthrough after attempt
1.500 + case EErase: // retry after verify failed
1.501 + case EEraseNoSuspend:
1.502 + ++iEraseAttempt;
1.503 + *pF=KCmdBlockErase;
1.504 + *pF=KCmdConfirm;
1.505 + CHANGE_ERASE_STATE(EEraseNoSuspend);
1.506 + iEraseError=0;
1.507 + StartHoldOffTimer();
1.508 + break;
1.509 + case ESuspended:
1.510 + *pF=KCmdClearStatusRegister;
1.511 + *pF=KCmdEraseResume;
1.512 + CHANGE_ERASE_STATE(EEraseNoSuspend);
1.513 + i=KMaxEraseResumeAttempts;
1.514 + for (; i>0 && ((s&KStsReady)!=0); --i)
1.515 + {
1.516 + *pF=KCmdReadStatusRegister; // send read status command
1.517 + s=*pF; // read status reg
1.518 + s=*pF; // read status reg
1.519 + }
1.520 + __KTRACE_OPT(KLOCDRV,Kern::Printf("RESUME: i=%d, s=%08x",i,s));
1.521 + StartHoldOffTimer();
1.522 + break;
1.523 + default:
1.524 + __KTRACE_OPT(KPANIC,Kern::Printf("iEraseState=%d",iEraseState));
1.525 + FLASH_FAULT();
1.526 + }
1.527 + StartPollTimer(KFlashEraseTimerPeriod,KFlashEraseTimerRetries);
1.528 + }
1.529 +
1.530 +void DMediaDriverFlashTemplate::SuspendErase()
1.531 + {
1.532 + __ASSERT_ALWAYS(iEraseState==EErase || iEraseState==ESuspendPending,FLASH_FAULT());
1.533 + volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iErasePos);
1.534 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendErase %08x",pF));
1.535 + *pF=KCmdEraseSuspend;
1.536 + CHANGE_ERASE_STATE(ESuspending);
1.537 + StartPollTimer(KFlashSuspendTimerPeriod,KFlashSuspendTimerRetries);
1.538 + }
1.539 +
1.540 +void DMediaDriverFlashTemplate::StartPendingRW()
1.541 + {
1.542 + // start any pending read or write requests
1.543 + if (iReadReq)
1.544 + DoRead();
1.545 + if (iWriteReq)
1.546 + {
1.547 + // can start the write now
1.548 + iWriteState=EWriting;
1.549 + WriteStep();
1.550 + }
1.551 + }
1.552 +
1.553 +void DMediaDriverFlashTemplate::DoFlashReady(TUint32 aStatus)
1.554 + {
1.555 + // could be write completion, erase completion or suspend completion
1.556 + if (iWriteState==EWriting)
1.557 + {
1.558 + // write completion
1.559 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:WriteComplete %08x",aStatus));
1.560 + TUint32 err=aStatus & (KStsWriteError|KStsVppLow|KStsLocked);
1.561 + if (err)
1.562 + {
1.563 + iWriteState=EWriteIdle;
1.564 + Complete(EReqWrite,KErrGeneral);
1.565 + if (iEraseState==ESuspended)
1.566 + StartErase();
1.567 + }
1.568 + else
1.569 + WriteStep();
1.570 + return;
1.571 + }
1.572 +
1.573 + // put the FLASH back into read mode
1.574 + volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iErasePos);
1.575 + *pF=KCmdReadArray;
1.576 +
1.577 + if (iEraseState==ESuspending)
1.578 + {
1.579 + // erase suspend completion
1.580 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendComplete %08x",aStatus));
1.581 +
1.582 + // accumulate errors during erase
1.583 + iEraseError|=(aStatus & (KStsEraseError|KStsVppLow|KStsLocked));
1.584 +
1.585 + if (aStatus & KStsSuspended)
1.586 + {
1.587 + // at least one of the two FLASH devices has suspended
1.588 + CHANGE_ERASE_STATE(ESuspended);
1.589 +
1.590 + // start any pending read or write requests
1.591 + StartPendingRW();
1.592 + return; // in case erase has been resumed by DoRead()
1.593 + }
1.594 +
1.595 + // erase completed before we suspended it
1.596 + CHANGE_ERASE_STATE(EErase);
1.597 + }
1.598 + if (iEraseState==EErase || iEraseState==EEraseNoSuspend)
1.599 + {
1.600 + // erase completion
1.601 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:EraseComplete %08x",aStatus));
1.602 + CancelHoldOffTimer();
1.603 +
1.604 + // accumulate errors during erase
1.605 + iEraseError|=(aStatus & (KStsEraseError|KStsVppLow|KStsLocked));
1.606 +
1.607 + TFLASHWORD x = FLASH_ERASE_WORD_VALUE;
1.608 +
1.609 + // if no device error, verify that erase was successful
1.610 + if (!iEraseError)
1.611 + {
1.612 + volatile TFLASHWORD* p=pF;
1.613 + volatile TFLASHWORD* pE=p + FLASH_BYTES_TO_WORDS(iEraseBlockSize);
1.614 + while(p<pE)
1.615 + x&=*p++;
1.616 + }
1.617 + else
1.618 + {
1.619 + }
1.620 + if (x == FLASH_ERASE_WORD_VALUE)
1.621 + {
1.622 + // erase OK
1.623 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:VerifyErase OK"));
1.624 + CHANGE_ERASE_STATE(EEraseIdle);
1.625 +
1.626 + // complete the erase request
1.627 + TInt r=iEraseError?KErrGeneral:KErrNone;
1.628 + Complete(EReqErase,r);
1.629 +
1.630 + // start any pending read or write requests
1.631 + StartPendingRW();
1.632 + }
1.633 + else
1.634 + {
1.635 + // erase failed, so retry
1.636 + __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:VerifyErase BAD"));
1.637 + StartErase();
1.638 + }
1.639 + }
1.640 + }
1.641 +
1.642 +void DMediaDriverFlashTemplate::DoFlashTimeout()
1.643 + {
1.644 + // TO DO: (optional)
1.645 + // Take appropriate action to handle a timeout.
1.646 + FLASH_FAULT(); // // EXAMPLE ONLY:
1.647 + }
1.648 +
1.649 +DMediaDriverFlash* DMediaDriverFlash::New(TInt aMediaId)
1.650 + {
1.651 + return new DMediaDriverFlashTemplate(aMediaId);
1.652 + }
1.653 +
1.654 +void DMediaDriverFlashTemplate::Isr(TAny* aPtr)
1.655 + {
1.656 + DMediaDriverFlashTemplate& d=*(DMediaDriverFlashTemplate*)aPtr;
1.657 +
1.658 +
1.659 + // TO DO: (mandatory)
1.660 + // Write to the timer hardware register(s) to
1.661 + // clear the timer interrupt
1.662 + //
1.663 +
1.664 + d.IPostEvents(EPollTimer);
1.665 + }
1.666 +
1.667 +void DMediaDriverFlashTemplate::IPostEvents(TUint32 aEvents)
1.668 + {
1.669 + iEvents|=aEvents;
1.670 + iEventDfc.Add();
1.671 + }