fmd.cpp
上传用户:qiulin1960
上传日期:2013-10-16
资源大小:2844k
文件大小:38k
源码类别:

Windows CE

开发平台:

Windows_Unix

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  3. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  4. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  5. PARTICULAR PURPOSE.
  6. Copyright (c) 2002  Microsoft Corporation
  7. Module Name: FMD.CPP
  8. Abstract: FLASH Media Driver Interface Samsung K9F2808UOB NAND Flash Chip
  9.                 on AT-Rise development board.
  10. Notes: Currently, *only* the CE 3.0 (and earlier) power management logic
  11. is implemented (i.e. the PowerUp() and PowerDown() APIs).
  12. Environment: As noted, this media driver works on behalf of the FAL to directly
  13. access the underlying FLASH hardware.  Consquently, this module
  14. needs to be linked with FAL.LIB to produce the device driver
  15. named FLASHDRV.DLL.
  16. -----------------------------------------------------------------------------*/
  17. #include <fmd.h>
  18. //#ifdef CEDAR_ONLY
  19. #ifndef NOSYSCALL
  20. // #include "utldrv.h"
  21. #include <nkintr.h>
  22. #include "oalintr.h"
  23. #endif
  24. //#endif // CEDAR_ONLY
  25. #ifdef NOBINFS
  26. #include "utldrv.h" // Still needed for driver->driver fast method calling in 4.x
  27. #endif
  28. #include <s2440.h>
  29. #include "cfnand.h"
  30. #include "loader.h"
  31. #ifndef NOSYSCALL
  32. #ifndef BOOT_LOADER
  33. // #define USENANDDMA 1
  34. // #define USESETKMODE 1
  35. // #define NAND_BUFFER_LENG 512
  36. #endif
  37. #endif
  38. #ifdef NOBINFS
  39. //#ifdef CEDAR_ONLY // Still needed in 4.x
  40. //  Globals
  41. HANDLE          g_hUTLObject = NULL;
  42. UTL_FASTCALL    g_tblFastCall;
  43. //#endif // CEDAR_ONLY
  44. #endif 
  45. // Globals needed for updatexip
  46. HANDLE g_hMutex = NULL;
  47. // BUGBUG: For now, we always will take the mutex
  48. BOOL g_bTakeMutex = TRUE;
  49. void GRABMUTEX();
  50. void RELEASEMUTEX();
  51. #ifdef NOSYSCALL
  52. #ifndef BOOT_LOADER
  53. // function prototypes for kernel functions
  54. extern "C"
  55. {
  56. HANDLE SC_CreateMutex(LPSECURITY_ATTRIBUTES lpsa, BOOL bInitialOwner, LPCTSTR lpName);
  57. DWORD SC_WaitForMultiple(DWORD cObjects, CONST HANDLE *lphObjects, BOOL fWaitAll, DWORD dwTimeout);
  58. BOOL SC_ReleaseMutex(HANDLE hMutex);
  59. BOOL SC_CloseHandle(HANDLE hObj);
  60. }
  61. #endif
  62. #endif
  63. //  Use Macros here to avoid extra over head for c function calls
  64. #define READ_REGISTER_BYTE(p) (*(volatile PBYTE) (p))
  65. #define WRITE_REGISTER_BYTE(p, v) (*(volatile PBYTE)(p)) = (v)
  66. #define READ_REGISTER_USHORT(p) (*(volatile PUSHORT) (p))
  67. #define WRITE_REGISTER_USHORT(p, v) (*(volatile PUSHORT)(p)) = (v)
  68. #define READ_REGISTER_ULONG(p)  (*(volatile PULONG) (p))
  69. #define WRITE_REGISTER_ULONG(p, v) (*(volatile PULONG)(p)) = (v)
  70. //  Registers
  71. volatile PUSHORT pNFReg;
  72. volatile PUSHORT pNFCONF;
  73. volatile PUSHORT pNFCONT;
  74. volatile PUSHORT pNFCMD;
  75. volatile PUSHORT pNFADDR;
  76. volatile PULONG  pNFDATA;
  77. volatile PUSHORT pNFSTAT;
  78. volatile PULONG  pNFECC;
  79. volatile CLKPWRreg *v_s2440CLKPWR;
  80. volatile DMAreg *v_pDMAregs;
  81. volatile INTreg *v_pINTregs;    
  82. #define NFDATA 0x4E000010
  83. // Event
  84. HANDLE gDMA3IntrEvent;
  85. PBYTE pDMABuffer;
  86. //  Status bit pattern
  87. #define STATUS_READY                0x40
  88. #define STATUS_ERROR                0x01
  89. // HCLK=133Mhz
  90. #define TACLS 0
  91. #define TWRPH0 6
  92. #define TWRPH1 2
  93. //  MACROS
  94. #define NF_CE_L() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) & ~(1<<1)))
  95. #define NF_CE_H() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) | (1<<1)))
  96. #define NF_CMD(cmd) WRITE_REGISTER_USHORT(pNFCMD, (USHORT) (cmd))
  97. #define NF_ADDR(addr) WRITE_REGISTER_USHORT(pNFADDR, (USHORT) (addr))
  98. #define NF_DATA_R() READ_REGISTER_BYTE(pNFDATA)
  99. #define NF_DATA_W(val) WRITE_REGISTER_BYTE(pNFDATA, (BYTE) (val))
  100. #define NF_DATA_R4() READ_REGISTER_ULONG(pNFDATA)
  101. #define NF_DATA_W4(val) WRITE_REGISTER_ULONG(pNFDATA, (ULONG) (val))
  102. #define NF_STAT() READ_REGISTER_USHORT(pNFSTAT)
  103. #define NF_MECC_UnLock() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) & ~(1<<5)))
  104. #define NF_MECC_Lock() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) | (1<<5)))
  105. #define NF_RSTECC() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) | (1<<4)))
  106. #define NF_WAITRB() {while(!(NF_STAT() & (1<<1))) ;}
  107. #define NF_CLEAR_RB() WRITE_REGISTER_USHORT(pNFSTAT, (USHORT) (READ_REGISTER_USHORT(pNFSTAT) | (1<<2)))
  108. #define NF_DETECT_RB() {while(!(NF_STAT() & (1<<2)));}
  109. #define NF_ECC() READ_REGISTER_ULONG(pNFECC)
  110. //  External function
  111. extern "C" {
  112. BOOL ECC_CorrectData(LPBYTE pData, LPBYTE pExistingECC, LPBYTE pNewECC);
  113. }
  114. //  Flags and pointers
  115. #define BADBLOCKMARK                0x00
  116. //  VALIDADDR is 5 << 8
  117. //
  118. //  Explain:    5 means the 6th byte in spare area (517 byte in the sector)
  119. //              Shift 8 bit to the left to form the correct address for 16bit port
  120. //
  121. #define VALIDADDR   0x05
  122. #define OEMADDR 0x04 // 5th byte in spare area
  123. #ifdef CEDAR_ONLY
  124. void PowerOnCallback()
  125. {
  126.     DEBUGMSG(1, (TEXT("FlashDrv::FMD:: Come back form Power Off!n")));
  127. }
  128. #endif // CEDAR_ONLY
  129. //  Reset the chip
  130. //
  131. void NF_Reset()
  132. {
  133. int i;
  134.     GRABMUTEX();
  135.     NF_CE_L();
  136. NF_CLEAR_RB();
  137.     NF_CMD(CMD_RESET);
  138. for(i=0;i<10;i++);  //tWB = 100ns. //??????
  139.     NF_CE_H();
  140.     RELEASEMUTEX();
  141. }
  142. /*
  143.  Here is the statement from SamSung's K9F2808U0B datasheet:
  144.  All device locations are erased (FFh) except location where the invalid block(s)
  145.  information is written prior to shipping. The invalid block(s) status is defined
  146.  by the 6th byte in the spare area. Samsung makes sure that either the 1st or 2nd
  147.  page of every invalid block has non-FFh data at the column address of 517. Since
  148.  the invalid block information is also erasable in most cases, it is impossible to
  149.  recover the information once it has been erased.
  150.  Here is the logic we are taking:
  151.  If the block is invalid, non-FFh value in column address of 517, we don't use that
  152.  block anyway. Otherwise, the whole spare area is subject to use by our program. If
  153.  we found additional bad block later on, we don't necessary have to use column 517
  154.  to represent invalid block. We could use any of the 16 byte spare area.
  155.  But for simplicity, in our current implementation, we avoid to touch column 517. So
  156.  the we allocate SectorInfo as following:
  157.   - - - - - - - - - - - - - - - -
  158.  |R|R|R|R|O|V|R|R|E|E|E|E|E|E|E|E|
  159.   - - - - - - - - - - - - - - - -
  160.  Where  Rs are reserved bytes used by the FAL
  161.         O is a byte for use by the OEM
  162.         V is a byte indicating if the block is valid (a.k.a. bad)
  163.         Es are bytes used for ECC
  164.  */
  165. /*
  166.  *  NAND_ReadSectorInfo
  167.  *
  168.  *  Read SectorInfo out of the spare area. The current implementation only handles
  169.  *  one sector at a time.
  170.  */
  171. void NAND_ReadSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
  172. {
  173. // RETAILMSG(1, (TEXT("FlashDrv!FMD!NAND_ReadSectorInfo:  rn")));
  174.     GRABMUTEX();
  175.     
  176.     //  Chip enable
  177.     NF_CE_L();
  178. NF_CLEAR_RB();
  179.     //  Write the command
  180.     NF_CMD(CMD_READ2);
  181.     //  Write the address
  182.     NF_ADDR(0x00);
  183.     NF_ADDR(sectorAddr & 0xff);
  184.     NF_ADDR((sectorAddr >> 8) & 0xff);
  185.     if (NEED_EXT_ADDR) {
  186.         NF_ADDR((sectorAddr >> 16) & 0xff);
  187.     }
  188. // RETAILMSG(1, (TEXT("sectorAddr : %x rn"), sectorAddr));
  189.     //  Wait for the Ready bit
  190. NF_DETECT_RB();  // Wait tR(max 12us)
  191.     //  Read the SectorInfo data (we only need to read first 8 bytes)
  192.     pInfo->dwReserved1  = NF_DATA_R4();
  193. // RETAILMSG(1, (TEXT("pInfo->dwReserved1 = %xrn"), pInfo->dwReserved1));
  194.     //  OEM byte
  195.     pInfo->bOEMReserved = (BYTE) NF_DATA_R();
  196. // RETAILMSG(1, (TEXT("pInfo->bOEMReserved = %xrn"), pInfo->bOEMReserved));
  197.     //  Read the bad block mark
  198.     pInfo->bBadBlock = (BYTE) NF_DATA_R();
  199. // RETAILMSG(1, (TEXT("pInfo->bBadBlock = %xrn"), pInfo->bBadBlock));
  200.     //  Second reserved field (WORD)
  201.     pInfo->wReserved2 = ((BYTE) NF_DATA_R() << 8);
  202.     pInfo->wReserved2 |= ((BYTE) NF_DATA_R());
  203. // RETAILMSG(1, (TEXT("pInfo->wReserved2 = %xrn"), pInfo->wReserved2));
  204. // RETAILMSG(1, (TEXT("rn")));
  205.     NF_CE_H();
  206.     RELEASEMUTEX();
  207. }
  208. /*
  209.  *  NAND_WriteSectorInfo
  210.  *
  211.  *  Write SectorInfo out to the spare area. The current implementation only handles
  212.  *  one sector at a time.
  213.  */
  214. BOOL NAND_WriteSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
  215. {
  216.     BOOL    bRet = TRUE;
  217. // RETAILMSG(1, (TEXT("FlashDrv!FMD!NAND_WriteSectorInfo:  rn")));
  218.     GRABMUTEX();
  219.     //  Chip enable
  220.     NF_CE_L();
  221. NF_CLEAR_RB();
  222.     //  Write the command
  223.     //  First, let's point to the spare area
  224.     NF_CMD(CMD_READ2);
  225.     NF_CMD(CMD_WRITE);
  226.     //  Write the address
  227.     NF_ADDR(0x00);
  228.     NF_ADDR(sectorAddr & 0xff);
  229.     NF_ADDR((sectorAddr >> 8) & 0xff);
  230.     if (NEED_EXT_ADDR) {
  231.         NF_ADDR((sectorAddr >> 16) & 0xff);
  232.     }
  233.     //  Now let's write the SectorInfo data
  234.     //
  235.     //  Write the first reserved field (DWORD)
  236.     NF_DATA_W4( pInfo->dwReserved1 );
  237.     //  Write OEM reserved flag
  238.     NF_DATA_W( (pInfo->bOEMReserved) );
  239.     //  Write the bad block flag
  240.     NF_DATA_W( (pInfo->bBadBlock) );
  241.     //  Write the second reserved field
  242.     NF_DATA_W( (pInfo->wReserved2 >> 8) & 0xff );
  243.     NF_DATA_W( (pInfo->wReserved2) );
  244.     //  Issue the write complete command
  245.     NF_CMD(CMD_WRITE2);
  246.     //  Check ready bit
  247. NF_DETECT_RB();  // Wait tR(max 12us)
  248.     //  Check the status of program
  249.     NF_CMD(CMD_STATUS);
  250.     if(NF_DATA_R() & STATUS_ERROR) {
  251.         RETAILMSG(1, (TEXT("NAND_WriteSectorInfo() ######## Error Programming page %d!n"), sectorAddr));
  252.         bRet = FALSE;
  253.     }
  254.     NF_CE_H();
  255.     RELEASEMUTEX();
  256.     return bRet;
  257. }
  258. /*-----------------------------------------------------------------------------
  259.  *  FMD Interface functions
  260.  *
  261.  *----------------------------------------------------------------------------*/
  262. //  FMD_Init
  263. //
  264. //  Initialize the flash chip
  265. //
  266. //  Note: Presently, the Flash size characteristics are hardcoded in CFNAND.H
  267. //   and are NOT stored in the registry.  Refer to the StratFlash FMD in
  268. //   %WINCEROOT%PUBLICCOMMONOAKDRIVERSBLOCK... for an example of how
  269. //   to use the registry for storing this information.
  270. //
  271. PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
  272. {
  273. RETAILMSG(1, (TEXT("FMD::FMD_Initrn")));
  274.     //  0. Create the Mutex for shared access between the kernel and MSFLASH
  275. #ifndef BOOT_LOADER
  276.     if (g_hMutex == NULL)
  277.     {
  278. #ifdef NOSYSCALL
  279. #ifndef BOOT_LOADER
  280.         g_hMutex = SC_CreateMutex(NULL, FALSE, TEXT("_FLASH_MUTEX_"));
  281. #endif
  282. #else
  283.         g_hMutex = CreateMutex(NULL, FALSE, TEXT("_FLASH_MUTEX_"));
  284. #endif
  285.         // was mutex creation successful?
  286.         if (g_hMutex == NULL) 
  287.         {
  288.             RETAILMSG(1,(TEXT("FlashDrv!FMD!FMD_Init: Unable to create mutexrn")));
  289.             goto ErrExit;
  290.         }
  291.     }
  292. #endif
  293.     
  294. #ifndef NOSYSCALL
  295. #ifdef NOBINFS
  296.     DWORD dwBytes;
  297.     //  Initialize the FASTCALL structure to 0
  298.     memset(&g_tblFastCall, 0, sizeof(UTL_FASTCALL));
  299.     //  1. CreateFile to get the access to UTLDRV.
  300.     //
  301.     g_hUTLObject = CreateFile(TEXT("UTL0:"), GENERIC_READ|GENERIC_WRITE,
  302.                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
  303.                                 NULL, OPEN_EXISTING, 0, 0);
  304.     if(INVALID_HANDLE_VALUE == g_hUTLObject) {
  305.         RETAILMSG(1, (TEXT("Failed CreateFile -- error = 0x%xn"), GetLastError()));
  306.         goto ErrExit;
  307.     }
  308.     //  2. Call IOCTL to get the FAST CALL function pointer.
  309.     //
  310.     if(!DeviceIoControl(g_hUTLObject,
  311.                         IOCTL_UTL_GET_FASTCALL,
  312.                         NULL, 0,
  313.                         &g_tblFastCall, sizeof(g_tblFastCall),
  314.                         &dwBytes, NULL)) {
  315.         RETAILMSG(1, (TEXT("Failed DeviceIoControl -- error = 0x%xn"), GetLastError()));
  316.         goto ErrExit;
  317.     }
  318.     //  3. Call the fast call to get the PVA for the registers
  319.     //
  320.     //  3.1 Get the register for NAND controller
  321.     if (ERROR_SUCCESS != g_tblFastCall.GetRegisterVA(g_tblFastCall.pContext, NFC_BASE,
  322.                                      32, FALSE, (DWORD *)&pNFReg) ) {
  323.         RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed GetRegisterVA(NFC_BASE) call!n")));
  324.         goto ErrExit;
  325.     }
  326.     //  3.2 Get the register for the CLKPWR register
  327.     if (ERROR_SUCCESS != g_tblFastCall.GetRegisterVA(g_tblFastCall.pContext, CLKPWR_BASE,
  328.                                      32, FALSE, (DWORD *)&v_s2440CLKPWR) ) {
  329.         RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed GetRegisterVA(CLKPWR_BASE) call!n")));
  330.         goto ErrExit;
  331.     }
  332. #ifdef CEDAR_ONLY
  333.     // ++ CE 3.0 Specific Code. Not needed for 4.x +
  334.     //  4. Register the Block driver to the Power On Monitor
  335.     //
  336.     if (ERROR_SUCCESS != g_tblFastCall.RegisterBlockDrv(g_tblFastCall.pContext,
  337.                                                         PowerOnCallback)) {
  338.         RETAILMSG(1, (TEXT("Failed RegisterStorageDrv -- error = 0x%xn"), GetLastError()));
  339.         goto ErrExit;
  340.     }
  341.     // -- CE 3.0 Specific Code. Not needed for 4.x +
  342. #endif // CEDAR_ONLY
  343. #else
  344. // RETAILMSG(1, (TEXT("FMD::FMD_Init:VirtualAlloc rn")));
  345.     pNFReg = (PUSHORT) VirtualAlloc(0, 0x1000, MEM_RESERVE, PAGE_NOACCESS);
  346.     if(!pNFReg) {
  347.         RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed VirtualAlloc ... Bailing out!n")));
  348.         goto ErrExit;
  349.     }
  350.     if(!VirtualCopy(pNFReg, (LPVOID) NFC_BASE, 0x1000, 
  351.                     PAGE_READWRITE|PAGE_NOCACHE)) {
  352.         RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed VirtualCopy for MemCtrl!n")));
  353.         goto ErrExit;
  354.     }
  355.     //  Allocate for the clock control register
  356.     //  Clock control register
  357.     v_s2440CLKPWR = (CLKPWRreg *)VirtualAlloc(NULL, 0x1000, MEM_RESERVE, PAGE_NOACCESS);
  358.     ASSERT(v_s2440CLKPWR);
  359.     if (!VirtualCopy((LPVOID) v_s2440CLKPWR, (LPVOID) CLKPWR_BASE, 0x1000,
  360.                      PAGE_READWRITE | PAGE_NOCACHE)) {
  361.         RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: VirtualCopy (v_s2440CLKPWR) failed!rn")));
  362.         goto ErrExit;
  363.     }
  364. #ifdef USENANDDMA
  365. // From HMSEO
  366. // DMA Virtual alloc
  367. v_pDMAregs = (volatile DMAreg *) VirtualAlloc(0,sizeof(DMAreg),MEM_RESERVE, PAGE_NOACCESS);
  368.     ASSERT(v_pDMAregs);
  369. if(!VirtualCopy((PVOID)v_pDMAregs,(PVOID)(DMA_BASE),sizeof(DMAreg),
  370. PAGE_READWRITE | PAGE_NOCACHE )) {
  371. ERRORMSG(1,(TEXT("For s2440DMA: VirtualCopy failed!rn")));
  372.         goto ErrExit;
  373. }
  374. // Allocate DMA buffer
  375. pDMABuffer = (unsigned char *)VirtualAlloc(0, NAND_BUFFER_LENG, MEM_RESERVE, PAGE_NOACCESS);
  376.     ASSERT(pDMABuffer);
  377.                                   
  378. if(!VirtualCopy(pDMABuffer,
  379. (PVOID)NAND_DMA_BUFFER_BASE,
  380. NAND_BUFFER_LENG,
  381. PAGE_READWRITE | PAGE_NOCACHE) )
  382. {
  383. ERRORMSG(1,(TEXT("For s2440DMA: DMABuffer VirtualCopy failed!rn")));
  384.         goto ErrExit;
  385.     }
  386. #ifndef USESETKMODE
  387. // allocate the interrupt event for DMA
  388. gDMA3IntrEvent = CreateEvent(NULL, FALSE, FALSE,NULL);
  389. if (NULL == gDMA3IntrEvent) {
  390. ERRORMSG(1,(TEXT("For s2440DMA: CreateEvent failed!rn")));
  391.         goto ErrExit;
  392. }
  393.     
  394. if (!InterruptInitialize (SYSINTR_DMA3, gDMA3IntrEvent,NULL,0)) {
  395. ERRORMSG(1,(TEXT("For s2440DMA: InterruptInitialize failed!rn")));
  396.         goto ErrExit;
  397. }
  398. #else
  399.     v_pINTregs = (volatile INTreg *) VirtualAlloc(0,sizeof(INTreg),MEM_RESERVE, PAGE_NOACCESS);
  400.     ASSERT(v_pINTregs);
  401. if(!VirtualCopy((PVOID)v_pINTregs,(PVOID)(INT_BASE),sizeof(INTreg),
  402.     PAGE_READWRITE | PAGE_NOCACHE ))
  403. {
  404. ERRORMSG(1,(TEXT("For INTreg: VirtualCopy failed!rn")));
  405.         goto ErrExit;
  406.     }
  407. #endif USESETKMODE
  408. // End HMSEO
  409. #endif USENANDDMA
  410. #endif // NOBINFS
  411. #else
  412.     pNFReg = (PUSHORT) (NFC_BASE | 0x20000000);
  413.     v_s2440CLKPWR = (CLKPWRreg *) ( CLKPWR_BASE | 0x20000000 );
  414. #endif
  415.     //  Enable the clock to NAND controller
  416.     v_s2440CLKPWR->rCLKCON |= (1<<4);
  417. // RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: pNFReg = %x rn"), pNFReg));
  418.     pNFCONF = pNFReg;
  419.     pNFCONT = (PUSHORT) ((PBYTE) pNFReg + 0x04);
  420.     pNFCMD  = (PUSHORT) ((PBYTE) pNFReg + 0x08);
  421.     pNFADDR = (PUSHORT) ((PBYTE) pNFReg + 0x0C);
  422.     pNFDATA = (PULONG) ((PBYTE) pNFReg + 0x10);
  423.     pNFSTAT = (PUSHORT) ((PBYTE) pNFReg + 0x20);
  424.     pNFECC  = (PULONG)  ((PBYTE) pNFReg + 0x2C);
  425.     //  Now we need enable the NAND Flash controller
  426.     GRABMUTEX();
  427.     WRITE_REGISTER_USHORT(pNFCONF, (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0));
  428.     WRITE_REGISTER_USHORT(pNFCONT, (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(1<<1)|(1<<0));
  429.     WRITE_REGISTER_USHORT(pNFSTAT, 0);
  430.     RELEASEMUTEX();
  431. // NF_Reset();
  432. RETAILMSG(1, (TEXT("FMD::FMD_Init Donern")));
  433.     return (PVOID)pNFCONF;
  434. ErrExit:
  435.     FMD_Deinit((PVOID)pNFCONF);
  436.     return 0;
  437. }
  438. //  FMD_Deinit
  439. //
  440. //  De-initialize the flash chip
  441. //
  442. BOOL    FMD_Deinit(PVOID hFMD)
  443. {
  444. if((DWORD)hFMD != (DWORD)pNFCONF)
  445. {
  446. return FALSE;
  447. }
  448. // destroy the mutex
  449. if (g_hMutex)
  450. {
  451. #ifdef NOSYSCALL
  452. #ifndef BOOT_LOADER
  453.         SC_CloseHandle(g_hMutex);
  454. #endif
  455. #else
  456.         CloseHandle(g_hMutex);
  457. #endif
  458. }
  459. #ifndef NOSYSCALL
  460. #ifdef NOBINFS
  461.     //  We don't have to free pNFReg and clock register.
  462. #ifdef CEDAR_ONLY
  463.     // ++ CE 3.0 Specific Code. Not needed for 4.x +
  464.     if (g_tblFastCall.UnRegisterBlockDrv) {
  465.         g_tblFastCall.UnRegisterBlockDrv(g_tblFastCall.pContext, PowerOnCallback);
  466.     }
  467.     // -- CE 3.0 Specific Code. Not needed for 4.x +
  468. #endif // CEDAR_ONLY
  469.     //  Close the handle
  470.     if (g_hUTLObject) {
  471.         CloseHandle(g_hUTLObject);
  472.     }
  473. #else
  474.     if(pNFReg) {
  475.         VirtualFree(pNFReg, 0, MEM_RELEASE);
  476.     }
  477.     if(v_s2440CLKPWR) {
  478.         VirtualFree((LPVOID)v_s2440CLKPWR, 0, MEM_RELEASE);
  479.     }
  480. #endif // NOBINFS
  481. #endif
  482.     return TRUE;
  483. }
  484. //  FMD_GetInfo
  485. //
  486. //  Return the Flash information
  487. //
  488. BOOL    FMD_GetInfo(PFlashInfo pFlashInfo)
  489. {
  490.     pFlashInfo->flashType = NAND;
  491.     //  OK, instead of reading it from the chip, we use the hardcoded
  492.     //  numbers here.
  493.     pFlashInfo->dwNumBlocks = NUM_BLOCKS;
  494.     pFlashInfo->wSectorsPerBlock = PAGES_PER_BLOCK;
  495.     pFlashInfo->wDataBytesPerSector = SECTOR_SIZE;
  496.     return TRUE;
  497. }
  498. //  FMD_ReadSector
  499. //
  500. //  Read the content of the sector.
  501. //
  502. //  startSectorAddr: Starting page address
  503. //  pSectorBuff  : Buffer for the data portion
  504. //  pSectorInfoBuff: Buffer for Sector Info structure
  505. //  dwNumSectors : Number of sectors
  506. //
  507. typedef union _ECCRegVal
  508. {
  509.     DWORD   dwECCVal;
  510.     BYTE    bECCBuf[4];
  511. } ECCRegVal;
  512. BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff,
  513.                         PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
  514. {
  515.     DWORD       i;
  516.     BYTE        eccBuf[8];
  517.     ECCRegVal   eccRegVal;
  518. // RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_ReadSector:  startSectorAddr = %x rn"), startSectorAddr));
  519.     //  Sanity check
  520.     if (!pSectorBuff && !pSectorInfoBuff || dwNumSectors > 1) {
  521. #ifdef BOOT_LOADER
  522.         EdbgOutputDebugString("Invalid parameters!rn");
  523. #else
  524.         RETAILMSG(1, (TEXT("Invalid parameters!n")));
  525. #endif
  526. #ifndef NOSYSCALL
  527.         SetLastError(ERROR_INVALID_PARAMETER);
  528. #endif
  529.         return FALSE;
  530.     }
  531. NF_Reset();
  532.     if(!pSectorBuff) {
  533.         //  We are reading spare only
  534.         NAND_ReadSectorInfo(startSectorAddr, pSectorInfoBuff);
  535.         //  There is no ECC for the sector info, so the read always succeed.
  536.         return TRUE;
  537.     }
  538. // RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_ReadSector:  startSectorAddr = %x rn"), startSectorAddr));
  539. GRABMUTEX();
  540. //  Initialize ECC register
  541. NF_RSTECC();
  542. NF_MECC_UnLock();
  543. //  Enable the chip
  544. NF_CE_L();
  545. NF_CLEAR_RB();
  546. //  Issue command
  547. NF_CMD(CMD_READ);
  548. //  Set up address
  549. NF_ADDR(0x00);
  550. NF_ADDR((startSectorAddr) & 0xff);
  551. NF_ADDR((startSectorAddr >> 8) & 0xff);
  552. if (NEED_EXT_ADDR) {
  553. NF_ADDR((startSectorAddr >> 16) & 0xff);
  554. }
  555. NF_DETECT_RB();  // Wait tR(max 12us)
  556. //  BUGBUG, because Media Player for Pocket PC sometimes pass us un-aligned buffer
  557. //  we have to waste cycle here to work around this problem
  558. if( ((DWORD) pSectorBuff) & 0x3) {
  559. for(i=0; i<SECTOR_SIZE; i++) {
  560. pSectorBuff[i] = (BYTE) NF_DATA_R();
  561. }
  562. }
  563. else {
  564. //  The right way.
  565. #ifndef USENANDDMA
  566. ReadPage512(pSectorBuff, pNFDATA);
  567. #else // USENANDDMA
  568. #ifdef USESETKMODE
  569. SetKMode(TRUE);
  570. v_pINTregs->rSRCPND=BIT_DMA3; // Init DMA src pending.
  571. #endif // USESETKMODE
  572. // Nand to memory dma setting
  573. v_pDMAregs->rDISRC3  = (unsigned int)NFDATA;  // Nand flash data register
  574. v_pDMAregs->rDISRCC3 = (0<<1) | (1<<0); //arc=AHB,src_addr=fix
  575. v_pDMAregs->rDIDST3  = (int)NAND_DMA_BUFFER_PHYS;
  576. v_pDMAregs->rDIDSTC3 = (0<<1) | (0<<0); //dst=AHB,dst_addr=inc;
  577. v_pDMAregs->rDCON3   = (1<<31)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(0<<23)|(1<<22)|(2<<20)|(512/4/4);
  578. //Handshake,AHB,interrupt,(4-burst),whole,S/W,no_autoreload,word,count=128;
  579. // DMA on and start.
  580. v_pDMAregs->rDMASKTRIG3 = (1<<1)|(1<<0);
  581. #ifndef USESETKMODE
  582. WaitForSingleObject(gDMA3IntrEvent, INFINITE);
  583. InterruptDone(SYSINTR_DMA3);
  584. #else // USESETKMODE
  585. while(!(v_pINTregs->rSRCPND & BIT_DMA3)); // Wait until Dma transfer is done.
  586. v_pINTregs->rSRCPND=BIT_DMA3;
  587. SetKMode(FALSE);
  588. #endif // USESETKMODE
  589. memcpy(pSectorBuff, pDMABuffer, 512);
  590. #endif // USENANDDMA
  591.     }
  592. /*
  593. for ( i = 0 ; i < 512; i++ )
  594. #ifdef BOOT_LOADER
  595.         EdbgOutputDebugString("%x ", *(pSectorBuff+i));
  596. #else
  597.         RETAILMSG(1, (TEXT("%x "), *(pSectorBuff+i)));
  598. #endif
  599. */
  600.     //  Do the ECC thing here
  601.     //  We read the ECC value from the ECC register pFNECC
  602. NF_MECC_Lock();
  603.     eccRegVal.dwECCVal = NF_ECC();
  604.     //  Read the SectorInfo data
  605.     if(pSectorInfoBuff) {
  606.         //  Read the SectorInfo data (we only need to read first 8 bytes)
  607.         pSectorInfoBuff->dwReserved1  = NF_DATA_R4();
  608.         //  OEM byte
  609.         pSectorInfoBuff->bOEMReserved = (BYTE) NF_DATA_R();
  610.         //  Read the bad block mark
  611.         pSectorInfoBuff->bBadBlock = (BYTE) NF_DATA_R();
  612.         //  Second reserved field (WORD)
  613.         pSectorInfoBuff->wReserved2 = ((BYTE) NF_DATA_R() << 8);
  614.         pSectorInfoBuff->wReserved2 |= ((BYTE) NF_DATA_R());
  615.     }
  616.     else {
  617.         //  Advance the read pointer
  618.         for(i=0; i<sizeof(SectorInfo); i++) {
  619.             eccBuf[i] = (BYTE) NF_DATA_R();
  620.         }
  621.     }
  622.     //  Verify the ECC values
  623.     //
  624.     //  Read the ECC buffer
  625.     for(i=0; i<3; i++) {
  626.         eccBuf[i] = (BYTE) NF_DATA_R();
  627.     }
  628.     NF_CE_H();
  629.     //  Copmare with the ECC generated from the HW
  630.     if(eccBuf[0] != eccRegVal.bECCBuf[0] ||
  631.        eccBuf[1] != eccRegVal.bECCBuf[1]  ||
  632.        eccBuf[2] != eccRegVal.bECCBuf[2] ) {
  633. #ifdef BOOT_LOADER
  634.         EdbgOutputDebugString("FMD: ECC ERROR - Page #: %drn", startSectorAddr);
  635.         EdbgOutputDebugString("(%x:%x %x:%x %x:%x)rn", eccBuf[0], eccRegVal.bECCBuf[0], eccBuf[1], eccRegVal.bECCBuf[1], eccBuf[2], eccRegVal.bECCBuf[2]);
  636. #else
  637.         RETAILMSG(1, (TEXT("FMD: ECC ERROR - Page #: %drn"), startSectorAddr));
  638. #endif
  639.         //  Now try to correct them
  640.         if(!ECC_CorrectData(pSectorBuff, eccBuf, eccRegVal.bECCBuf)) {
  641.             RETAILMSG(1, (TEXT("FMD: Unable to correct the ECC error - Page #: %drn"),
  642.                           startSectorAddr));
  643.             RELEASEMUTEX();
  644. return FALSE;
  645.         }
  646.     }
  647.     RELEASEMUTEX();
  648.     return TRUE;
  649. }
  650. //
  651. //  IsBlockBad
  652. //
  653. //  Check to see if the given block is bad. A block is bad if the 517th byte on
  654. //  the first or second page is not 0xff.
  655. //
  656. //  blockID:    The block address. We need to convert this to page address
  657. //
  658. //
  659. BOOL IsBlockBad(BLOCK_ID blockID)
  660. {
  661.     DWORD   dwPageID = blockID << 5;
  662.     BOOL    bRet = FALSE;
  663.     BYTE    wFlag;
  664.     GRABMUTEX();
  665.     //  Enable the chip
  666.     NF_CE_L();
  667. NF_CLEAR_RB();
  668.     //  Issue the command
  669.     NF_CMD(CMD_READ2);
  670.     //  Set up address
  671.     NF_ADDR(VALIDADDR);
  672.     NF_ADDR((dwPageID) & 0xff);
  673.     NF_ADDR((dwPageID >> 8) & 0xff);
  674.     if (NEED_EXT_ADDR) {
  675.         NF_ADDR((dwPageID >> 16) & 0xff);
  676.     }
  677.     //  Wait for Ready bit
  678. NF_DETECT_RB();  // Wait tR(max 12us)
  679.     //  Now get the byte we want
  680.     wFlag = (BYTE) NF_DATA_R();
  681.     if(wFlag != 0xff) {
  682.         bRet = TRUE;
  683.     }
  684.     //  Disable the chip
  685.     NF_CE_H();
  686.     RELEASEMUTEX();
  687.     return bRet;
  688. }
  689. //
  690. //  FMD_GetBlockStatus
  691. //
  692. //  Returns the status of a block.  The status information is stored in the spare area of the first sector for
  693. //  the respective block.
  694. //
  695. //  A block is BAD if the bBadBlock byte on the first page is not equal to 0xff.
  696. //
  697. DWORD FMD_GetBlockStatus(BLOCK_ID blockID)
  698. {
  699.     SECTOR_ADDR sectorAddr = blockID << LOG_2_PAGES_PER_BLOCK;
  700.     SectorInfo SI;
  701.     DWORD dwResult = 0;
  702. if(!FMD_ReadSector(sectorAddr, NULL, &SI, 1))
  703. {
  704.         return BLOCK_STATUS_UNKNOWN;
  705. }
  706.     if(!(SI.bOEMReserved & OEM_BLOCK_READONLY))
  707. {
  708.         dwResult |= BLOCK_STATUS_READONLY;
  709. }
  710.     if(SI.bBadBlock != 0xFF)
  711. {
  712.         dwResult |= BLOCK_STATUS_BAD;
  713. }
  714.     return dwResult;
  715. }
  716. //  FMD_EraseBlock
  717. //
  718. //  Erase the given block
  719. //
  720. BOOL FMD_EraseBlock(BLOCK_ID blockID)
  721. {
  722.     BOOL    bRet = TRUE;
  723.     DWORD   dwPageID = blockID << 5;
  724.     GRABMUTEX();
  725. #ifndef NOSYSCALL
  726. if(blockID < IMAGE_START_BLOCK)
  727. {
  728. bRet = FALSE;
  729. RELEASEMUTEX();
  730. return bRet;
  731. }
  732. #endif
  733.     //  Enable the chip
  734.     NF_CE_L();
  735. NF_CLEAR_RB();
  736.     //  Issue command
  737.     NF_CMD(CMD_ERASE);
  738.     //  Set up address
  739.     NF_ADDR((dwPageID) & 0xff);
  740.     NF_ADDR((dwPageID >> 8) & 0xff);
  741.     if (NEED_EXT_ADDR) {
  742.         NF_ADDR((dwPageID >> 16) & 0xff);
  743.     }
  744.     //  Complete erase operation
  745.     NF_CMD(CMD_ERASE2);
  746.     //  Wait for ready bit
  747. NF_DETECT_RB();  // Wait tR(max 12us)
  748.     //  Check the status
  749.     NF_CMD(CMD_STATUS);
  750.     if(NF_DATA_R() & STATUS_ERROR) {
  751.         RETAILMSG(1, (TEXT("######## Error Erasing block %d!n"), blockID));
  752.         bRet = FALSE;
  753.     }
  754.     NF_CE_H();
  755.     RELEASEMUTEX();
  756.     return bRet;
  757. }
  758. //  FMD_WriteSector
  759. //
  760. //  Write dwNumPages pages to the startSectorAddr
  761. //
  762. BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff,
  763.                         DWORD dwNumSectors)
  764. {
  765.     DWORD   i;
  766.     BOOL    bRet = TRUE;
  767.     DWORD   dwECCVal;
  768.     BYTE    eccBuf[4];
  769. // RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_WriteSector:  rn")));
  770.     //  Sanity check
  771.     //  BUGBUGBUG: I need to come back to support dwNumSectors > 1
  772.     //
  773.     if((!pSectorBuff && !pSectorInfoBuff) || dwNumSectors != 1) {
  774. #ifdef BOOT_LOADER
  775.         EdbgOutputDebugString("Invalid parameters!rn");
  776. #else
  777.         RETAILMSG(1, (TEXT("Invalid parameters!n")));
  778. #endif
  779. #ifndef NOSYSCALL
  780.         SetLastError(ERROR_INVALID_PARAMETER);
  781. #endif
  782.         return FALSE;
  783.     }
  784. NF_Reset();
  785.     if(!pSectorBuff) {
  786.         //  If we are asked just to write the SectorInfo, we will do that separately
  787.         bRet = NAND_WriteSectorInfo(startSectorAddr, pSectorInfoBuff);
  788. return bRet; // Do not write the actual sector information...
  789.     }
  790.     GRABMUTEX();
  791.     //  Initialize ECC register
  792.     NF_RSTECC();
  793. NF_MECC_UnLock();
  794.     //  Enable Chip
  795.     NF_CE_L();
  796.     //  Issue command
  797.     NF_CMD(CMD_READ);
  798.     NF_CMD(CMD_WRITE);
  799.     //  Setup address
  800.     NF_ADDR(0x00);
  801.     NF_ADDR((startSectorAddr) & 0xff);
  802.     NF_ADDR((startSectorAddr >> 8) & 0xff);
  803.     if (NEED_EXT_ADDR) {
  804.         NF_ADDR((startSectorAddr >> 16) & 0xff);
  805.     }
  806.     //  Special case to handle un-aligned buffer pointer.
  807.     //
  808.     if( ((DWORD) pSectorBuff) & 0x3) {
  809.         //  Write the data
  810.         for(i=0; i<SECTOR_SIZE; i++) {
  811.             NF_DATA_W(pSectorBuff[i]);
  812.         }
  813.     }
  814.     else {
  815. #ifndef USENANDDMA
  816.         WritePage512(pSectorBuff, pNFDATA);
  817. #else // USENANDDMA
  818. #ifdef USESETKMODE
  819. SetKMode(TRUE);
  820. v_pINTregs->rSRCPND=BIT_DMA3; // Init DMA src pending.
  821. #endif // USESETKMODE
  822. memcpy(pDMABuffer, pSectorBuff, 512);
  823. // Nand to memory dma setting
  824.     v_pDMAregs->rDISRC3  = (int)SDI_DMA_BUFFER_PHYS;  // Nand flash data register
  825.     v_pDMAregs->rDISRCC3 = (0<<1) | (0<<0); //arc=AHB,src_addr=inc
  826.     v_pDMAregs->rDIDST3  = (int)NFDATA;
  827.     v_pDMAregs->rDIDSTC3 = (0<<1) | (1<<0); //dst=AHB,dst_addr=fix;
  828.     v_pDMAregs->rDCON3   = (1<<31)|(1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(1<<22)|(2<<20)|(512/4);
  829. //  only unit transfer in writing!!!!
  830. //Handshake,AHB,interrupt,(unit),whole,S/W,no_autoreload,word,count=128;
  831. // DMA on and start.
  832.     v_pDMAregs->rDMASKTRIG3 = (1<<1)|(1<<0);
  833. #ifndef USESETKMODE
  834. WaitForSingleObject(gDMA3IntrEvent, INFINITE);
  835. InterruptDone(SYSINTR_DMA3);
  836. #else // USESETKMODE
  837. while(!(v_pINTregs->rSRCPND & BIT_DMA3)); // Wait until Dma transfer is done.
  838. v_pINTregs->rSRCPND=BIT_DMA3;
  839. SetKMode(FALSE);
  840. #endif // USESETKMODE
  841. #endif // USENANDDMA
  842.     }
  843.     //  Read out the ECC value generated by HW
  844. NF_MECC_Lock();
  845.     dwECCVal = NF_ECC();
  846. // Write the SectorInfo data to the media
  847. // NOTE: This hardware is odd: only a byte can be written at a time and it must reside in the
  848. //       upper byte of a USHORT.
  849. if(pSectorInfoBuff)
  850. {
  851.         //  Write the first reserved field (DWORD)
  852.         NF_DATA_W4(pSectorInfoBuff->dwReserved1);
  853.         //  Write OEM reserved flag
  854.         NF_DATA_W( (pSectorInfoBuff->bOEMReserved) );
  855.         //  Write the bad block flag
  856.         NF_DATA_W( (pSectorInfoBuff->bBadBlock) );
  857.         //  Write the second reserved field
  858.         NF_DATA_W( (pSectorInfoBuff->wReserved2 >> 8) & 0xff );
  859.         NF_DATA_W( (pSectorInfoBuff->wReserved2) & 0xff );
  860. }else
  861. {
  862. // Make sure we advance the Flash's write pointer (even though we aren't writing the SectorInfo data)
  863. for(i=0; i<sizeof(SectorInfo); i++)
  864. {
  865.             NF_DATA_W(0xff);
  866. }
  867. }
  868.     //  ECC stuff should be here
  869.     eccBuf[0] = (BYTE) ((dwECCVal) & 0xff);
  870.     eccBuf[1] = (BYTE) ((dwECCVal >> 8) & 0xff);
  871.     eccBuf[2] = (BYTE) ((dwECCVal >> 16) & 0xff);
  872.     //  Write the ECC value to the flash
  873.     for(i=0; i<3; i++) {
  874.         NF_DATA_W(eccBuf[i]);
  875.     }
  876.     for(i=0; i<5; i++) {
  877.         NF_DATA_W(0xff);
  878.     }
  879. NF_CLEAR_RB();
  880.     //  Finish up the write operation
  881.     NF_CMD(CMD_WRITE2);
  882.     //  Wait for RB
  883. NF_DETECT_RB();  // Wait tR(max 12us)
  884.     //  Check the status
  885.     NF_CMD(CMD_STATUS);
  886.     if(NF_DATA_R() & STATUS_ERROR) {
  887. #ifdef BOOT_LOADER
  888.         EdbgOutputDebugString("FMD_WriteSector() ######## Error Programming page %d!rn", startSectorAddr);
  889. #else
  890.         RETAILMSG(1, (TEXT("FMD_WriteSector() ######## Error Programming page %d!n"), startSectorAddr));
  891. #endif
  892.         bRet = FALSE;
  893.     }
  894.     //  Disable the chip
  895.     NF_CE_H();
  896.     RELEASEMUTEX();
  897.     return bRet;
  898. }
  899. /*
  900.  *  MarkBlockBad
  901.  *
  902.  *  Mark the block as a bad block. We need to write a 00 to the 517th byte
  903.  */
  904. BOOL MarkBlockBad(BLOCK_ID blockID)
  905. {
  906.     DWORD   dwStartPage = blockID << 5;
  907.     BOOL    bRet = TRUE;
  908.     GRABMUTEX();
  909.     //  Enable chip
  910.     NF_CE_L();
  911. NF_CLEAR_RB();
  912.     //  Issue command
  913.     //  We are dealing with spare area
  914.     NF_CMD(CMD_READ2);
  915.     NF_CMD(CMD_WRITE);
  916.     //  Set up address
  917.     NF_ADDR(VALIDADDR);
  918.     NF_ADDR((dwStartPage) & 0xff);
  919.     NF_ADDR((dwStartPage >> 8) & 0xff);
  920.     if (NEED_EXT_ADDR) {
  921.         NF_ADDR((dwStartPage >> 16) & 0xff);
  922.     }
  923.     NF_DATA_W(BADBLOCKMARK);
  924.     //  Copmlete the write
  925.     NF_CMD(CMD_WRITE2);
  926.     //  Wait for RB
  927. NF_DETECT_RB();  // Wait tR(max 12us)
  928.     //  Get the status
  929.     NF_CMD(CMD_STATUS);
  930.     if(NF_DATA_R() &  STATUS_ERROR) {
  931.         RETAILMSG(1, (TEXT("######## Failed to mark the block bad!n")));
  932.         bRet = FALSE;
  933.     }
  934.     //  Disable chip select
  935.     NF_CE_H();
  936.     RELEASEMUTEX();
  937.     return bRet;
  938. }
  939. //
  940. //  FMD_SetBlockStatus
  941. //
  942. //  Sets the status of a block.  Only implement for bad blocks for now.
  943. //  Returns TRUE if no errors in setting.
  944. //
  945. BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)
  946. {
  947.     SECTOR_ADDR sectorAddr = blockID << LOG_2_PAGES_PER_BLOCK;
  948. BYTE bStatus = 0;
  949.     if(dwStatus & BLOCK_STATUS_BAD)
  950. {
  951.         if(!MarkBlockBad (blockID))
  952.         {
  953.             return FALSE;
  954.         }
  955.     }
  956.     // We don't currently support setting a block to read-only, so fail if request is
  957.     // for read-only and block is not currently read-only.
  958.     if(dwStatus & BLOCK_STATUS_READONLY)
  959. {
  960.         if(!(FMD_GetBlockStatus(blockID) & BLOCK_STATUS_READONLY))
  961.         {
  962.             return FALSE;
  963.         }
  964.     }
  965.     return TRUE;
  966. }
  967. #ifndef NOSYSCALL
  968. //  We don't have to build the following interface functions for the
  969. //  bootloader.
  970. //
  971. //  FMD_PowerUp
  972. //
  973. //  Performs any necessary powerup procedures...
  974. //
  975. VOID FMD_PowerUp(VOID)
  976. {
  977.     if (v_s2440CLKPWR && pNFCONF) {
  978.         //  Enable the clock to NAND controller
  979.         v_s2440CLKPWR->rCLKCON |= (1<<4);
  980.         //  Reinit the NAND controller
  981.         GRABMUTEX();
  982. WRITE_REGISTER_USHORT(pNFCONF, (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0));
  983. WRITE_REGISTER_USHORT(pNFCONT, (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(1<<1)|(1<<0));
  984. WRITE_REGISTER_USHORT(pNFSTAT, 0);
  985.         RELEASEMUTEX();
  986.         
  987.         //  Reset the controller
  988.         NF_Reset();
  989. #ifdef CEDAR_ONLY
  990.         // ++ CE 3.0 Specific Code. Not needed for 4.x +
  991.         SetInterruptEvent(SYSINTR_POWERON);
  992.         // -- CE 3.0 Specific Code. Not needed for 4.x +
  993. #endif // CEDAR_ONLY
  994.     }
  995. }
  996. //  FMD_PowerDown
  997. //
  998. //  Performs any necessary powerdown procedures...
  999. //
  1000. VOID FMD_PowerDown(VOID)
  1001. {
  1002.     if (v_s2440CLKPWR) {
  1003.         //  Disable the clock to NAND controller
  1004.         v_s2440CLKPWR->rCLKCON &= ~(1<<4);
  1005.     }
  1006. }
  1007. //  FMD_OEMIoControl
  1008. //
  1009. //  Used for any OEM defined IOCTL operations
  1010. //
  1011. BOOL  FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize,
  1012.                        PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
  1013. {
  1014.     switch(dwIoControlCode)
  1015.     {
  1016.         case IOCTL_FMD_UPDATEXIP_BEGIN:
  1017.             g_bTakeMutex = TRUE;
  1018.             break;
  1019.             
  1020.         case IOCTL_FMD_UPDATEXIP_END:
  1021.             g_bTakeMutex = FALSE;
  1022.             break;
  1023.             
  1024.         default:
  1025.         RETAILMSG(1, (TEXT("FMD::FMD_OEMIoControl = 0x%xn"), dwIoControlCode));
  1026.             return FALSE;
  1027.     }
  1028. return TRUE;
  1029. }
  1030. #endif // NOSYSCALL
  1031. //------------------------------- Private Interface (NOT used by the FAL) --------------------------
  1032. //  FMD_GetOEMReservedByte
  1033. //
  1034. //  Retrieves the OEM reserved byte (for metadata) for the specified physical sector.
  1035. //
  1036. //
  1037. BOOL FMD_GetOEMReservedByte(SECTOR_ADDR physicalSectorAddr, PBYTE pOEMReserved)
  1038. {
  1039.     GRABMUTEX();
  1040.     
  1041.     //  Enable chip select
  1042.     NF_CE_L();
  1043. NF_CLEAR_RB();
  1044.     //  Issue command
  1045.     NF_CMD(CMD_READ2);
  1046.     //  Set up address
  1047.     NF_ADDR(OEMADDR);
  1048.     NF_ADDR((physicalSectorAddr) & 0xff);
  1049.     NF_ADDR((physicalSectorAddr >> 8) & 0xff);
  1050.     if (NEED_EXT_ADDR) {
  1051.         NF_ADDR((physicalSectorAddr >> 16) & 0xff);
  1052.     }
  1053.     //  Wait for the ready bit
  1054. NF_DETECT_RB();  // Wait tR(max 12us)
  1055.     //  Read the data
  1056.     *pOEMReserved = (BYTE) NF_DATA_R();
  1057.     //  Disable chip select
  1058.     NF_CE_H();
  1059.     RELEASEMUTEX();
  1060. return TRUE;
  1061. }
  1062. //  FMD_SetOEMReservedByte
  1063. //
  1064. //  Sets the OEM reserved byte (for metadata) for the specified physical sector.
  1065. //
  1066. BOOL FMD_SetOEMReservedByte(SECTOR_ADDR physicalSectorAddr, BYTE bOEMReserved)
  1067. {
  1068.     BOOL    bRet = TRUE;
  1069.     GRABMUTEX();
  1070.     //  Enable chip select
  1071.     NF_CE_L();
  1072. NF_CLEAR_RB();
  1073.     //  Issue command
  1074.     NF_CMD(CMD_READ2);
  1075.     NF_CMD(CMD_WRITE);
  1076.     //  Set up address
  1077.     NF_ADDR(OEMADDR);
  1078.     NF_ADDR((physicalSectorAddr) & 0xff);
  1079.     NF_ADDR((physicalSectorAddr >> 8) & 0xff);
  1080.     if (NEED_EXT_ADDR) {
  1081.         NF_ADDR((physicalSectorAddr >> 16) & 0xff);
  1082.     }
  1083.     //  Write the data
  1084.     NF_DATA_W(bOEMReserved);
  1085.     //  Complete the write
  1086.     NF_CMD(CMD_WRITE2);
  1087.     //  Wait for the ready bit
  1088. NF_DETECT_RB();  // Wait tR(max 12us)
  1089.     //  Read the status
  1090.     NF_CMD(CMD_STATUS);
  1091.     //  Check the status
  1092.     if(NF_DATA_R() & STATUS_ERROR) {
  1093.         RETAILMSG(1, (TEXT("######## Failed to set OEM Reserved byte!n")));
  1094.         bRet = FALSE;
  1095.     }
  1096.     //  Disable chip select
  1097.     NF_CE_H();
  1098.     RELEASEMUTEX();
  1099.     return bRet;
  1100. }
  1101. //---------------------------------------- Helper Functions ----------------------------------------
  1102. //  Interface function for testing purpose.
  1103. //
  1104. BOOL FMD_ReadSpare(DWORD dwStartPage, LPBYTE pBuff, DWORD dwNumPages)
  1105. {
  1106.     DWORD   i, n;
  1107.     GRABMUTEX();
  1108.     //  Enable chip select
  1109.     NF_CE_L();
  1110. NF_CLEAR_RB();
  1111.     //  Issue command
  1112.     NF_CMD(CMD_READ2);
  1113.     //  Set up address
  1114.     NF_ADDR(0x00);
  1115.     NF_ADDR((dwStartPage) & 0xff);
  1116.     NF_ADDR((dwStartPage >> 8) & 0xff);
  1117.     if (NEED_EXT_ADDR) {
  1118.         NF_ADDR((dwStartPage >> 16) & 0xff);
  1119.     }
  1120.     //  Wait for Ready bit
  1121. NF_DETECT_RB();  // Wait tR(max 12us)
  1122.     //  Now read out the data
  1123.     for(n=0; n<dwNumPages; n++) {
  1124.         //  Read the spare area
  1125.         for(i=0; i<16; i++) {
  1126.             pBuff[n*16+i] = (BYTE) NF_DATA_R();
  1127.         }
  1128. NF_DETECT_RB();  // Wait tR(max 12us)
  1129.     }
  1130.     NF_CE_H();
  1131.     RELEASEMUTEX();
  1132.     return TRUE;
  1133. }
  1134. void GRABMUTEX()
  1135. {
  1136. #ifdef NOSYSCALL
  1137. #ifndef BOOT_LOADER
  1138.     // we're in the kernel - always SC_WaitForMultiple
  1139.     SC_WaitForMultiple(1, &g_hMutex, TRUE, INFINITE);
  1140. #endif
  1141. #else
  1142.     if (g_bTakeMutex) {
  1143.         // we can do a normal WaitForSingleObject
  1144.         WaitForSingleObject(g_hMutex, INFINITE);
  1145.     }
  1146. #endif
  1147. }
  1148. void RELEASEMUTEX()
  1149. {
  1150. #ifdef NOSYSCALL
  1151. #ifndef BOOT_LOADER
  1152.     SC_ReleaseMutex(g_hMutex);
  1153. #endif
  1154. #else
  1155.     if (g_bTakeMutex) {
  1156.         ReleaseMutex(g_hMutex);
  1157.     }
  1158. #endif
  1159. }