www.pudn.com > iMx31_WCE600.rar > nand.c
//----------------------------------------------------------------------------- // // Use of this source code is subject to the terms of the Microsoft end-user // license agreement (EULA) under which you licensed this SOFTWARE PRODUCT. // If you did not accept the terms of the EULA, you are not authorized to use // this source code. For a copy of the EULA, please see the LICENSE.RTF on // your install media. // //----------------------------------------------------------------------------- // // Copyright (C) 2004-2007, Freescale Semiconductor, Inc. All Rights Reserved. // THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS // AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT // //----------------------------------------------------------------------------- // // File: nand.c // // Contains BOOT NAND flash support functions. // //----------------------------------------------------------------------------- #include "bsp.h" #include "loader.h" #pragma warning(push) #pragma warning(disable: 4115) #include#pragma warning(pop) //----------------------------------------------------------------------------- // External Functions //----------------------------------------------------------------------------- // External Variables extern BOOL g_bNandExist; //----------------------------------------------------------------------------- // Defines #define NANDFC_BOOT_SIZE (2*1024) //----------------------------------------------------------------------------- // Types //----------------------------------------------------------------------------- // Global Variables BYTE sectorBuf[NANDFC_BOOT_SIZE]; static FlashInfo g_flashInfo; //----------------------------------------------------------------------------- // Local Variables //----------------------------------------------------------------------------- // Local Functions //----------------------------------------------------------------------------- // // Function: NANDWriteXldr // // This function writes to NAND flash memory the XLDR image stored // in the RAM file cache area. // // Parameters: // dwStartAddr // [in] Address in flash memory where the start of the downloaded // XLDR image is to be written. // // dwLength // [in] Length of the XLDR image, in bytes, to be written to flash // memory. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDWriteXldr(DWORD dwStartAddr, DWORD dwLength) { FlashInfo flashInfo; LPBYTE pSectorBuf, pImage; SectorInfo sectorInfo; SECTOR_ADDR sectorAddr, endSectorAddr; // Check for NAND device availability // if (!g_bNandExist) { EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to store image.\r\n"); return(FALSE); } EdbgOutputDebugString("INFO: Writing XLDR image to NAND (please wait)...\r\n"); if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // XLDR is placed in block #0 of the NAND device. // Block #0 is always good, so just erase it if (!FMD_EraseBlock(0)) { EdbgOutputDebugString("ERROR: Unable to erase NAND flash block #0\r\n"); return(FALSE); } // Get cached image location pImage = OEMMapMemAddr(dwStartAddr, dwStartAddr); // If image is larger than 4K, this must be xldr.bin produced by // ROMIMAGE if (dwLength > 0x1000) { // ROMIMAGE adds 4K page at the beginning of the image. // We will flash the first 2K bytes that appear after this 4K page. // pImage += 0x1000; dwLength -= 0x1000; } // Make sure XLDR length does not exceed size that can be supported by NANDFC (2KB) if (dwLength > NANDFC_BOOT_SIZE) { EdbgOutputDebugString("ERROR: XLDR exceeds 2KByte\r\n"); return(FALSE); } // Fill unused space with 0xFF memset(pImage + dwLength, 0xFF, (NANDFC_BOOT_SIZE) - dwLength); EdbgOutputDebugString("INFO: Using XLDR image from flash cache address 0x%x, size = %d\r\n", pImage, dwLength); sectorInfo.dwReserved1 = 0xFFFFFFFF; sectorInfo.bOEMReserved = 0x00; sectorInfo.bBadBlock = 0xFF; sectorInfo.wReserved2 = 0xFFFF; endSectorAddr = (NANDFC_BOOT_SIZE / flashInfo.wDataBytesPerSector); // Write XLDR to NAND flash pSectorBuf = pImage; for (sectorAddr = 0; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_WriteSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to update XLDR.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } // Read XLDR from NAND flash to verify contents pSectorBuf = pImage + NANDFC_BOOT_SIZE; for (sectorAddr = 0; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_ReadSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to verify XLDR.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } if (memcmp(pImage, pImage + NANDFC_BOOT_SIZE, NANDFC_BOOT_SIZE) != 0) { EdbgOutputDebugString("ERROR: Failed to verify XLDR.\r\n"); } EdbgOutputDebugString("INFO: Update of XLDR completed successfully.\r\n"); return(TRUE); } //----------------------------------------------------------------------------- // // Function: NANDWriteBoot // // This function writes to NAND flash memory the Boot image stored // in the RAM file cache area. // // Parameters: // dwStartAddr // [in] Address in flash memory where the start of the downloaded // Boot image is to be written. // // dwLength // [in] Length of the Boot image, in bytes, to be written to flash // memory. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDWriteBoot(DWORD dwStartAddr, DWORD dwLength) { FlashInfo flashInfo; LPBYTE pSectorBuf, pImage; SectorInfo sectorInfo; BLOCK_ID blockID, startBlockID, endBlockID; SECTOR_ADDR sectorAddr, startSectorAddr, endSectorAddr; // Check for NAND device availability // if (!g_bNandExist) { EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to store image.\r\n"); return(FALSE); } EdbgOutputDebugString("INFO: Writing Boot image to NAND (please wait)...\r\n"); if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // Make sure Boot length does not exceed reserved NAND size if (dwLength > IMAGE_BOOT_BOOTIMAGE_NAND_SIZE) { EdbgOutputDebugString("ERROR: Boot size exceeds reserved NAND region (size = 0x%x)\r\n", dwLength); return(FALSE); } // Calculate the physical block range for the EBOOT image startBlockID = IMAGE_BOOT_BOOTIMAGE_NAND_OFFSET / flashInfo.dwBytesPerBlock; endBlockID = startBlockID + (IMAGE_BOOT_BOOTIMAGE_NAND_SIZE / flashInfo.dwBytesPerBlock); EdbgOutputDebugString("INFO: Erasing NAND flash blocks [0x%x - 0x%x].\r\n", startBlockID, endBlockID); // Erase range of NAND blocks reserved for EBOOT for (blockID = startBlockID; blockID < endBlockID; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Erase the block... if (!FMD_EraseBlock(blockID)) { EdbgOutputDebugString("ERROR: Unable to erase NAND flash block [0x%x].\r\n", blockID); return(FALSE); } } // Get cached image location pImage = OEMMapMemAddr(dwStartAddr, dwStartAddr); // Fill unused space with 0xFF memset(pImage + dwLength, 0xFF, (IMAGE_BOOT_BOOTIMAGE_NAND_SIZE) - dwLength); EdbgOutputDebugString("INFO: Programming EBOOT/SBOOT image from flash cache address 0x%x, size = %d\r\n", pImage, dwLength); sectorInfo.dwReserved1 = 0xFFFFFFFF; sectorInfo.bOEMReserved = 0x00; sectorInfo.bBadBlock = 0xFF; sectorInfo.wReserved2 = 0xFFFF; // Write EBOOT to NAND flash pSectorBuf = pImage; for (blockID = startBlockID; blockID < endBlockID; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block startSectorAddr = blockID * flashInfo.wSectorsPerBlock; endSectorAddr = startSectorAddr + flashInfo.wSectorsPerBlock; for (sectorAddr = startSectorAddr; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_WriteSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to update EBOOT/SBOOT.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } } // Read EBOOT from NAND flash to verify contents pSectorBuf = pImage + IMAGE_BOOT_BOOTIMAGE_NAND_SIZE; for (blockID = startBlockID; blockID < endBlockID ; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block startSectorAddr = blockID * flashInfo.wSectorsPerBlock; endSectorAddr = startSectorAddr + flashInfo.wSectorsPerBlock; for (sectorAddr = startSectorAddr; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_ReadSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to update EBOOT/SBOOT.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } } EdbgOutputDebugString("INFO: Verifying image.\r\n"); if (memcmp(pImage, pImage + IMAGE_BOOT_BOOTIMAGE_NAND_SIZE, IMAGE_BOOT_BOOTIMAGE_NAND_SIZE) != 0) { EdbgOutputDebugString("ERROR: Failed to verify EBOOT/SBOOT.\r\n"); } EdbgOutputDebugString("INFO: Update of EBOOT/SBOOT completed successfully.\r\n"); return(TRUE); } //------------------------------------------------------------------------------ // // Function: NANDWriteIPL // // N/A // // Parameters: // None. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDWriteIPL(DWORD dwStartAddr, DWORD dwLength) { FlashInfo flashInfo; LPBYTE pSectorBuf, pImage; SectorInfo sectorInfo; BLOCK_ID blockID, startBlockID, endBlockID; SECTOR_ADDR sectorAddr, startSectorAddr, endSectorAddr; // Check for NAND device availability // if (!g_bNandExist) { EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to store image.\r\n"); return(FALSE); } EdbgOutputDebugString("INFO: Writing IPL image to NAND (please wait)...\r\n"); if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // Make sure IPL length does not exceed reserved NAND size if (dwLength > IMAGE_BOOT_IPLIMAGE_NAND_SIZE) { EdbgOutputDebugString("ERROR: IPL size exceeds reserved NAND region (size = 0x%x)\r\n", dwLength); return(FALSE); } // Calculate the physical block range for the IPL image startBlockID = IMAGE_BOOT_IPLIMAGE_NAND_OFFSET / flashInfo.dwBytesPerBlock; endBlockID = startBlockID + (IMAGE_BOOT_IPLIMAGE_NAND_SIZE / flashInfo.dwBytesPerBlock); EdbgOutputDebugString("INFO: Erasing NAND flash blocks [0x%x - 0x%x].\r\n", startBlockID, endBlockID); // Erase range of NAND blocks reserved for IPL for (blockID = startBlockID; blockID < endBlockID; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Erase the block... if (!FMD_EraseBlock(blockID)) { EdbgOutputDebugString("ERROR: Unable to erase NAND flash block [0x%x].\r\n", blockID); return(FALSE); } } // Get cached image location pImage = OEMMapMemAddr(dwStartAddr, dwStartAddr); // Fill unused space with 0xFF memset(pImage + dwLength, 0xFF, (IMAGE_BOOT_IPLIMAGE_NAND_SIZE) - dwLength); EdbgOutputDebugString("INFO: Programming IPL image from flash cache address 0x%x, size = %d\r\n", pImage, dwLength); sectorInfo.dwReserved1 = 0xFFFFFFFF; sectorInfo.bOEMReserved = 0x00; sectorInfo.bBadBlock = 0xFF; sectorInfo.wReserved2 = 0xFFFF; // Write IPL to NAND flash pSectorBuf = pImage; for (blockID = startBlockID; blockID < endBlockID; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block startSectorAddr = blockID * flashInfo.wSectorsPerBlock; endSectorAddr = startSectorAddr + flashInfo.wSectorsPerBlock; for (sectorAddr = startSectorAddr; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_WriteSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to update IPL.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } } // Read IPL from NAND flash to verify contents pSectorBuf = pImage + IMAGE_BOOT_IPLIMAGE_NAND_SIZE; for (blockID = startBlockID; blockID < endBlockID ; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block startSectorAddr = blockID * flashInfo.wSectorsPerBlock; endSectorAddr = startSectorAddr + flashInfo.wSectorsPerBlock; for (sectorAddr = startSectorAddr; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_ReadSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to update IPL.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } } EdbgOutputDebugString("INFO: Verifying image.\r\n"); if (memcmp(pImage, pImage + IMAGE_BOOT_IPLIMAGE_NAND_SIZE, IMAGE_BOOT_IPLIMAGE_NAND_SIZE) != 0) { EdbgOutputDebugString("ERROR: Failed to verify IPL.\r\n"); } EdbgOutputDebugString("INFO: Update of IPL completed successfully.\r\n"); return(TRUE); } //----------------------------------------------------------------------------- // // Function: NANDWriteNK // // This function writes to NAND flash memory the OS image stored // in the RAM file cache area. // // Parameters: // dwStartAddr // [in] Address in flash memory where the start of the downloaded // OS image is to be written. // // dwLength // [in] Length of the OS image, in bytes, to be written to flash // memory. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDWriteNK(DWORD dwStartAddr, DWORD dwLength) { FlashInfo flashInfo; LPBYTE pSectorBuf, pImage; SectorInfo sectorInfo; BLOCK_ID blockID, startBlockID, endBlockID; SECTOR_ADDR sectorAddr, startSectorAddr, endSectorAddr; UINT32 percentComplete, lastPercentComplete; // Check for NAND device availability // if (!g_bNandExist) { EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to store image.\r\n"); return(FALSE); } EdbgOutputDebugString("INFO: Writing NK image to NAND (please wait)...\r\n"); if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // Make sure NK length does not exceed reserved NAND size if (dwLength > IMAGE_BOOT_NKIMAGE_NAND_SIZE) { EdbgOutputDebugString("ERROR: NK size exceeds reserved NAND region (size = 0x%x)\r\n", dwLength); return(FALSE); } // Calculate the physical block range for the NK image startBlockID = IMAGE_BOOT_NKIMAGE_NAND_OFFSET / flashInfo.dwBytesPerBlock; endBlockID = startBlockID + (IMAGE_BOOT_NKIMAGE_NAND_SIZE / flashInfo.dwBytesPerBlock); EdbgOutputDebugString("INFO: Erasing NAND flash blocks [0x%x - 0x%x].\r\n", startBlockID, endBlockID); lastPercentComplete = 0; // Erase range of NAND blocks reserved for NK for (blockID = startBlockID; blockID < endBlockID; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Erase the block... if (!FMD_EraseBlock(blockID)) { EdbgOutputDebugString("ERROR: Unable to erase NAND flash block [0x%x].\r\n", blockID); return(FALSE); } } // Get cached image location pImage = OEMMapMemAddr(dwStartAddr, dwStartAddr); // Fill unused space with 0xFF memset(pImage + dwLength, 0xFF, (IMAGE_BOOT_NKIMAGE_NAND_SIZE) - dwLength); EdbgOutputDebugString("INFO: Programming NK image from flash cache address 0x%x, size = %d\r\n", pImage, dwLength); sectorInfo.dwReserved1 = 0xFFFFFFFF; sectorInfo.bOEMReserved = 0x00; sectorInfo.bBadBlock = 0xFF; sectorInfo.wReserved2 = 0xFFFF; // Write NK to NAND flash pSectorBuf = pImage; lastPercentComplete = 0; for (blockID = startBlockID; blockID < endBlockID; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block startSectorAddr = blockID * flashInfo.wSectorsPerBlock; endSectorAddr = startSectorAddr + flashInfo.wSectorsPerBlock; for (sectorAddr = startSectorAddr; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_WriteSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to update NK.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } percentComplete = 100 * (blockID - startBlockID + 1) / (endBlockID - startBlockID); // If percentage complete has changed, show the progress if (lastPercentComplete != percentComplete) { lastPercentComplete = percentComplete; OEMWriteDebugByte('\r'); EdbgOutputDebugString("INFO: Program is %d%% complete.", percentComplete); } } EdbgOutputDebugString("\r\nINFO: Reading image in NAND for verification.\r\n"); // Read NK from NAND flash to verify contents pSectorBuf = pImage + IMAGE_BOOT_NKIMAGE_NAND_SIZE; lastPercentComplete = 0; for (blockID = startBlockID; blockID < endBlockID ; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("\r\nINFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block startSectorAddr = blockID * flashInfo.wSectorsPerBlock; endSectorAddr = startSectorAddr + flashInfo.wSectorsPerBlock; for (sectorAddr = startSectorAddr; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_ReadSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("\r\nERROR: Failed to update NK.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } percentComplete = 100 * (blockID - startBlockID + 1) / (endBlockID - startBlockID); // If percentage complete has changed, show the progress if (lastPercentComplete != percentComplete) { lastPercentComplete = percentComplete; OEMWriteDebugByte('\r'); EdbgOutputDebugString("INFO: Read is %d%% complete.", percentComplete); } } EdbgOutputDebugString("\nINFO: Verifying image.\r\n"); if (memcmp(pImage, pImage + IMAGE_BOOT_NKIMAGE_NAND_SIZE, IMAGE_BOOT_NKIMAGE_NAND_SIZE) != 0) { EdbgOutputDebugString("ERROR: Failed to verify NK.\r\n"); } EdbgOutputDebugString("INFO: Update of NK completed successfully.\r\n"); return(TRUE); } //------------------------------------------------------------------------------ // // Function: IsSectorEmpty // // N/A // // Parameters: // None. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL IsSectorEmpty(UCHAR *pData, ULONG sectorSize, SectorInfo *pSectorInfo) { BOOL rc = FALSE; ULONG idx; if (pSectorInfo->dwReserved1 != 0xFFFFFFFF) goto cleanUp; if (pSectorInfo->wReserved2 != 0xFFFF) goto cleanUp; if (pSectorInfo->bOEMReserved != 0xFF) goto cleanUp; for (idx = 0; idx < sectorSize; idx++) { if (pData[idx] != 0xFF) goto cleanUp; } rc = TRUE; cleanUp: return rc; } //------------------------------------------------------------------------------ // // Function: NANDStartWriteBinDIO // // N/A // // Parameters: // None. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDStartWriteBinDIO(DWORD dwStartAddr, DWORD dwLength) { BLOCK_ID blockID, startBlockID, endBlockID; UINT32 percentComplete, lastPercentComplete = 0; // Remove-W4: Warning C4100 workaround UNREFERENCED_PARAMETER(dwStartAddr); // Check for NAND device availability // if (!g_bNandExist) { EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to store image.\r\n"); return(FALSE); } EdbgOutputDebugString("INFO: Prepare for writing DIO image to NAND.\r\n"); if (!FMD_GetInfo(&g_flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // Make sure DIO image length does not exceed reserved NAND size if (dwLength > IMAGE_BOOT_DIOIMAGE_NAND_SIZE) { EdbgOutputDebugString("ERROR: DIO image size exceeds reserved NAND region (size = 0x%x)\r\n", dwLength); return(FALSE); } // Force all blocks in XLDR(128KB), EBOOT(256KB) and IPL(256KB) to be reserved startBlockID = 0; endBlockID = (IMAGE_BOOT_DIOIMAGE_NAND_OFFSET / g_flashInfo.dwBytesPerBlock) - 1; for (blockID = startBlockID; blockID < endBlockID; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Set reserved status if ((FMD_GetBlockStatus(blockID) & BLOCK_STATUS_RESERVED) == 0) { EdbgOutputDebugString("INFO: Block [0x%x] not marked as bad or reserved. Force status to reserved.\r\n", blockID); if (!FMD_SetBlockStatus(blockID, BLOCK_STATUS_RESERVED)) { EdbgOutputDebugString("ERROR: Block [0x%x] force reserved status failed.\r\n", blockID); return(FALSE); } } } // Calculate the physical block range for the DIO image startBlockID = IMAGE_BOOT_DIOIMAGE_NAND_OFFSET / g_flashInfo.dwBytesPerBlock; endBlockID = startBlockID + (IMAGE_BOOT_DIOIMAGE_NAND_SIZE / g_flashInfo.dwBytesPerBlock); EdbgOutputDebugString("INFO: Erasing NAND flash blocks [0x%x - 0x%x].\r\n", startBlockID, endBlockID); // Erase range of NAND blocks reserved for DIO image for (blockID = startBlockID; blockID < endBlockID; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Erase the block... if (!FMD_EraseBlock(blockID)) { EdbgOutputDebugString("ERROR: Unable to erase NAND flash block [0x%x].\r\n", blockID); return(FALSE); } percentComplete = 100 * (blockID - startBlockID + 1) / (endBlockID - startBlockID); // If percentage complete has changed, show the progress if (lastPercentComplete != percentComplete) { lastPercentComplete = percentComplete; OEMWriteDebugByte('\r'); EdbgOutputDebugString("INFO: Erase is %d%% complete.", percentComplete); } } EdbgOutputDebugString("\r\nINFO: Ready to write DIO image ... \r\n"); return(TRUE); } //------------------------------------------------------------------------------ // // Function: NANDContinueWriteBinDIO // // N/A // // Parameters: // None. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDContinueWriteBinDIO(DWORD dwAddress, BYTE *pbData, DWORD dwSize) { BOOL bOK; BLOCK_ID blockID; SECTOR_ADDR sectorAddr; SectorInfo *pSectorInfo; UINT32 blockSize, sectorSize; UINT32 dwCount; static UINT32 nTimes = 0, dwBadBlock = 0; // Check for NAND device availability // if (!g_bNandExist) { EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to store image.\r\n"); return(FALSE); } // First we need to calculate position where to write sectorSize = g_flashInfo.wDataBytesPerSector + sizeof(SectorInfo); blockSize = g_flashInfo.wSectorsPerBlock * sectorSize; blockID = dwAddress / blockSize; sectorAddr = (dwAddress - blockID * blockSize) / sectorSize; // Shift block by DIO image region base blockID += (IMAGE_BOOT_DIOIMAGE_NAND_OFFSET / g_flashInfo.dwBytesPerBlock); // Skip the number of bad blocks blockID += dwBadBlock; // Write record dwCount = 0; while (dwCount < dwSize && blockID < g_flashInfo.dwNumBlocks) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); blockID++; dwBadBlock++; continue; } // Write sectors bOK = TRUE; while (sectorAddr < g_flashInfo.wSectorsPerBlock && dwCount < dwSize) { // First we have to check for empty sectors pSectorInfo = (SectorInfo *)(pbData + dwCount + g_flashInfo.wDataBytesPerSector); // Don't write empty sector if (IsSectorEmpty(pbData + dwCount, g_flashInfo.wDataBytesPerSector, pSectorInfo)) { // EdbgOutputDebugString("INFO: Skipping empty sector [0x%x].\r\n", sectorAddr); // Move to next sector dwCount += sectorSize; sectorAddr++; continue; } // Clear reserved flag if set pSectorInfo->bOEMReserved |= OEM_BLOCK_RESERVED; // Never ever write sector with bad block if (pSectorInfo->bBadBlock != 0xFF) { EdbgOutputDebugString("ERROR: Incorrect or corrupted DIO BIN file - bad block flag set.\r\n"); return(FALSE); } // Write sector if ((bOK = FMD_WriteSector(blockID * g_flashInfo.wSectorsPerBlock + sectorAddr, pbData + dwCount, pSectorInfo, 1)) == 0) { EdbgOutputDebugString("ERROR: Writing sector [0x%x] failed.\r\n", sectorAddr); break; } // Move to next sector dwCount += sectorSize; sectorAddr++; } // When sector write failed, mark block as bad and move back if (!bOK) { EdbgOutputDebugString("WARN: Block [0x%x] / sector [0x%x] write failed, mark block as bad.\r\n", blockID, sectorAddr); // First move back dwCount -= sectorAddr * sectorSize; // Mark block as bad FMD_SetBlockStatus(blockID, BLOCK_STATUS_BAD); blockID++; continue; } // We are done with block sectorAddr = 0; blockID++; } // Progress OEMWriteDebugByte('\r'); switch (nTimes++ % 4) { case 0: OEMWriteDebugByte('\\'); break; case 1: OEMWriteDebugByte('|'); break; case 2: OEMWriteDebugByte('/'); break; case 3: OEMWriteDebugByte('-'); } // Before we leave erase buffer memset(pbData, 0xFF, dwSize); // If we wrote all, we are succesfull return (dwCount >= dwSize); } //------------------------------------------------------------------------------ // // Function: NANDFinishWriteBinDIO // // N/A // // Parameters: // None. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDFinishWriteBinDIO() { if (!g_bNandExist) { EdbgOutputDebugString("\r\nINFO: No NAND present!\r\n"); return(FALSE); } // Nothing to do... EdbgOutputDebugString("\r\nINFO: Update of DIO image completed successfully.\r\n"); return TRUE; } //------------------------------------------------------------------------------ // // Function: NANDLoadIPL // // N/A // // Parameters: // None. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDLoadIPL(VOID) { FlashInfo flashInfo; LPBYTE pSectorBuf; SectorInfo sectorInfo; BLOCK_ID blockID, startBlockID, endBlockID; SECTOR_ADDR sectorAddr, startSectorAddr, endSectorAddr; // Check for NAND device availability // if (!g_bNandExist) { EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to read image.\r\n"); return(FALSE); } EdbgOutputDebugString("INFO: Reading IPL image from NAND (please wait)...\r\n"); if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // Calculate the physical block range for the NK image startBlockID = IMAGE_BOOT_IPLIMAGE_NAND_OFFSET / flashInfo.dwBytesPerBlock; endBlockID = startBlockID + (IMAGE_BOOT_IPLIMAGE_NAND_SIZE / flashInfo.dwBytesPerBlock); // Set image load address pSectorBuf = (LPBYTE) OALPAtoUA(IMAGE_BOOT_IPLIMAGE_RAM_START); EdbgOutputDebugString("INFO: Copying IPL image to RAM address 0x%x\r\n", pSectorBuf); // Copy IPL from NAND flash to RAM for (blockID = startBlockID; blockID < endBlockID ; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block startSectorAddr = blockID * flashInfo.wSectorsPerBlock; endSectorAddr = startSectorAddr + flashInfo.wSectorsPerBlock; for (sectorAddr = startSectorAddr; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_ReadSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to update IPL.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } } EdbgOutputDebugString("INFO: Copy of IPL completed successfully.\r\n"); return(TRUE); } //----------------------------------------------------------------------------- // // Function: NANDLoadNK // // This function loads an OS image from NAND flash memory into RAM for // execution. // // Parameters: // None. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDLoadNK(VOID) { FlashInfo flashInfo; LPBYTE pSectorBuf; SectorInfo sectorInfo; BLOCK_ID blockID, startBlockID, endBlockID; SECTOR_ADDR sectorAddr, startSectorAddr, endSectorAddr; UINT32 percentComplete, lastPercentComplete; // Check for NAND device availability // if (!g_bNandExist) { EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to read image.\r\n"); return(FALSE); } EdbgOutputDebugString("INFO: Reading NK image to NAND (please wait)...\r\n"); if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // Calculate the physical block range for the NK image startBlockID = IMAGE_BOOT_NKIMAGE_NAND_OFFSET / flashInfo.dwBytesPerBlock; endBlockID = startBlockID + (IMAGE_BOOT_NKIMAGE_NAND_SIZE / flashInfo.dwBytesPerBlock); // Set image load address pSectorBuf = (LPBYTE) OALPAtoUA(IMAGE_BOOT_NKIMAGE_RAM_PA_START); EdbgOutputDebugString("INFO: Copying NK image to RAM address 0x%x\r\n", pSectorBuf); lastPercentComplete = 0; // Copy NK from NAND flash to RAM for (blockID = startBlockID; blockID < endBlockID ; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block startSectorAddr = blockID * flashInfo.wSectorsPerBlock; endSectorAddr = startSectorAddr + flashInfo.wSectorsPerBlock; for (sectorAddr = startSectorAddr; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_ReadSector(sectorAddr, pSectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to update NK.\r\n"); return(FALSE); } pSectorBuf += flashInfo.wDataBytesPerSector; } percentComplete = 100 * (blockID - startBlockID + 1) / (endBlockID - startBlockID); // If percentage complete has changed, show the progress if (lastPercentComplete != percentComplete) { lastPercentComplete = percentComplete; OEMWriteDebugByte('\r'); EdbgOutputDebugString("INFO: Load is %d%% complete.", percentComplete); } } EdbgOutputDebugString("\r\nINFO: Copy of NK completed successfully.\r\n"); return(TRUE); } //----------------------------------------------------------------------------- // // Function: NANDFormatNK // // This function formats (erases) the NAND flash region reserved for OS // images. // // Parameters: // None. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDFormatNK(void) { FlashInfo flashInfo; BLOCK_ID blockID, startBlockID, endBlockID; UINT32 percentComplete, lastPercentComplete; // Get NAND flash data bytes per sector. // if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // Calculate the physical block range for the NK image startBlockID = IMAGE_BOOT_NKIMAGE_NAND_OFFSET / flashInfo.dwBytesPerBlock; endBlockID = startBlockID + (IMAGE_BOOT_NKIMAGE_NAND_SIZE / flashInfo.dwBytesPerBlock); EdbgOutputDebugString("INFO: Starting format of NAND NK region.\r\n"); lastPercentComplete = 0; for (blockID = startBlockID; blockID < endBlockID ; blockID++) { // Is the block bad? // if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("\r\nINFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Erase the block... // if (!FMD_EraseBlock(blockID)) { EdbgOutputDebugString("\r\nERROR: Unable to erase NAND flash block 0x%x.\r\n", blockID); return(FALSE); } else { percentComplete = 100 * (blockID - startBlockID + 1) / (endBlockID - startBlockID); // If percentage complete has changed, show the progress if (lastPercentComplete != percentComplete) { lastPercentComplete = percentComplete; OEMWriteDebugByte('\r'); EdbgOutputDebugString("INFO: Format is %d%% complete.", percentComplete); } } } EdbgOutputDebugString("\r\nINFO: Format of NAND NK region completed successfully.\r\n"); return(TRUE); } //----------------------------------------------------------------------------- // // Function: NANDFormatAll // // This function formats (erases) the entire NAND flash memory. // // Parameters: // None. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDFormatAll(void) { FlashInfo flashInfo; BLOCK_ID blockID, startBlockID, endBlockID; UINT32 percentComplete, lastPercentComplete; // Get NAND flash data bytes per sector. // if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // Calculate the physical block range for the enrire NAND device startBlockID = 0; endBlockID = flashInfo.dwNumBlocks; EdbgOutputDebugString("INFO: Starting format of all NAND regions.\r\n"); lastPercentComplete = 0; for (blockID = startBlockID; blockID < endBlockID ; blockID++) { // Is the block bad? // if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Erase the block... // if (!FMD_EraseBlock(blockID)) { EdbgOutputDebugString("ERROR: Unable to erase NAND flash block 0x%x.\r\n", blockID); return(FALSE); } else { percentComplete = 100 * (blockID - startBlockID + 1) / (endBlockID - startBlockID); // If percentage complete has changed, show the progress if (lastPercentComplete != percentComplete) { lastPercentComplete = percentComplete; OEMWriteDebugByte('\r'); EdbgOutputDebugString("INFO: Format is %d%% complete.", percentComplete); } } } EdbgOutputDebugString("\r\nINFO: Format of all NAND regions completed successfully.\r\n"); return(TRUE); } //------------------------------------------------------------------------------ // // Function: NANDLoadBootCFG // // Retrieves bootloader configuration information (menu settings, etc.) from // the NAND flash. // // Parameters: // eBootCFG // [out] Points to bootloader configuration that will be filled with // loaded data. // // cbBootCfgSize // [in] Size in bytes of the bootloader configuration. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDLoadBootCFG(BYTE *pBootCfg, DWORD cbBootCfgSize) { BOOL rc = FALSE; FlashInfo flashInfo; BLOCK_ID blockID, startBlockID, endBlockID; SECTOR_ADDR sectorAddr; if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } // Calculate the physical block range for the boot configuration startBlockID = (flashInfo.dwNumBlocks * flashInfo.dwBytesPerBlock - IMAGE_BOOT_BOOTCFG_NAND_SIZE) / flashInfo.dwBytesPerBlock; endBlockID = startBlockID + (IMAGE_BOOT_BOOTCFG_NAND_SIZE / flashInfo.dwBytesPerBlock); EdbgOutputDebugString("INFO: Loading boot configuration from NAND\r\n"); // Find a good block and load the boot configuration for (blockID = startBlockID; (blockID < endBlockID) && (rc == FALSE) ; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block sectorAddr = blockID * flashInfo.wSectorsPerBlock; rc = FMD_ReadSector(sectorAddr, sectorBuf, NULL, 1); } if (rc) { if (cbBootCfgSize > NANDFC_BOOT_SIZE) cbBootCfgSize = NANDFC_BOOT_SIZE; memcpy(pBootCfg, sectorBuf, cbBootCfgSize); } else { EdbgOutputDebugString("ERROR: Failed to load boot configuration from NAND\r\n"); } return rc; } //------------------------------------------------------------------------------ // // Function: NANDStoreBootCFG // // Stores bootloader configuration information (menu settings, etc.) to // the NAND flash. // // Parameters: // eBootCFG // [out] Points to bootloader configuration that will be stored. // // cbBootCfgSize // [in] Size in bytes of the bootloader configuration. // // Returns: // TRUE indicates success. FALSE indicates failure. // //----------------------------------------------------------------------------- BOOL NANDStoreBootCFG(BYTE *pBootCfg, DWORD cbBootCfgSize) { FlashInfo flashInfo; SectorInfo sectorInfo; BLOCK_ID blockID, startBlockID, endBlockID; SECTOR_ADDR sectorAddr, startSectorAddr, endSectorAddr; if (!FMD_GetInfo(&flashInfo)) { EdbgOutputDebugString("ERROR: Unable to get NAND flash information.\r\n"); return(FALSE); } if (cbBootCfgSize > NANDFC_BOOT_SIZE) cbBootCfgSize = NANDFC_BOOT_SIZE; memcpy(sectorBuf, pBootCfg, cbBootCfgSize); memset(sectorBuf + cbBootCfgSize, 0xFF, NANDFC_BOOT_SIZE - cbBootCfgSize); sectorInfo.dwReserved1 = 0xFFFFFFFF; sectorInfo.bOEMReserved = 0x00; sectorInfo.bBadBlock = 0xFF; sectorInfo.wReserved2 = 0xFFFF; // Calculate the physical block range for the boot configuration startBlockID = (flashInfo.dwNumBlocks * flashInfo.dwBytesPerBlock - IMAGE_BOOT_BOOTCFG_NAND_SIZE) / flashInfo.dwBytesPerBlock; endBlockID = startBlockID + (IMAGE_BOOT_BOOTCFG_NAND_SIZE / flashInfo.dwBytesPerBlock); EdbgOutputDebugString("INFO: Storing boot configuration to NAND\r\n"); // Erase range of NAND blocks reserved for boot configuration for (blockID = startBlockID; blockID < endBlockID; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Erase the block... if (!FMD_EraseBlock(blockID)) { EdbgOutputDebugString("ERROR: Unable to erase NAND flash block [0x%x].\r\n", blockID); return FALSE; } } // Find a good block and store the boot configuration for (blockID = startBlockID; blockID < endBlockID ; blockID++) { // Skip bad blocks if (FMD_GetBlockStatus(blockID) == BLOCK_STATUS_BAD) { EdbgOutputDebugString("INFO: Found bad NAND flash block [0x%x].\r\n", blockID); continue; } // Compute sector address based on current physical block startSectorAddr = blockID * flashInfo.wSectorsPerBlock; endSectorAddr = startSectorAddr + flashInfo.wSectorsPerBlock; // Write out the boot configuration to all sectors as filler so the // NAND FMD does not try to map it later for (sectorAddr = startSectorAddr; sectorAddr < endSectorAddr; sectorAddr++) { if (!FMD_WriteSector(sectorAddr, sectorBuf, §orInfo, 1)) { EdbgOutputDebugString("ERROR: Failed to update EBOOT.\r\n"); return FALSE; } } } EdbgOutputDebugString("INFO: Successfully stored boot configuration to NAND\r\n"); return TRUE; }