/** @file * * Copyright (c) 2015, Hisilicon Limited. All rights reserved. * Copyright (c) 2015, Linaro Limited. All rights reserved. * * This program and the accompanying materials * are licensed and made available under the terms and conditions of the BSD License * which accompanies this distribution. The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * **/ #include #include #include #include #include "NorFlashHw.h" BOOLEAN gFlashBusy = FALSE; FLASH_INDEX gIndex = { 0, 0, 0, 0, 0, 0 }; UINT32 PortReadData ( UINT32 Index, UINT32 FlashAddr ) { switch (gFlashInfo[Index].ParallelNum) { case 2: return MmioRead32 (FlashAddr); case 1: return MmioRead16 (FlashAddr); default: DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:illegal PortWidth!\n", __FUNCTION__,__LINE__)); return 0xffffffff; } } EFI_STATUS PortWriteData ( UINT32 Index, UINT32 FlashAddr, UINT32 InputData ) { switch (gFlashInfo[Index].ParallelNum) { case 2: MmioWrite32 (FlashAddr, InputData); break; case 1: MmioWrite16 (FlashAddr, InputData); break; default: DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:illegal PortWidth!\n", __FUNCTION__,__LINE__)); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } UINT32 PortAdjustData( UINT32 Index, UINT32 ulInputData ) { switch (gFlashInfo[Index].ParallelNum) { case 2: return ulInputData; case 1: return (0x0000ffff & ulInputData ); default: DEBUG((EFI_D_ERROR,"[FLASH_S29GL256N_PortAdjustData]: Error--illegal g_ulFlashS29Gl256NPortWidth!\n\r")); return 0xffffffff; } } EFI_STATUS GetCommandIndex( UINT32 Index ) { UINT32 CommandCount = 0; UINT32 i; UINT8 Flag = 1; CommandCount = sizeof(gFlashCommandReset) / sizeof(FLASH_COMMAND_RESET); for(i = 0;i < CommandCount; i ++ ) { if(gFlashInfo[Index].CommandType & gFlashCommandReset[i].CommandType) { Flag = 0; gIndex.ReIndex = i; break; } } if(Flag) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Can not Get Reset Command!\n", __FUNCTION__,__LINE__)); return EFI_DEVICE_ERROR; } CommandCount = sizeof(gFlashCommandId) / sizeof(FLASH_COMMAND_ID); for(Flag = 1,i = 0;i < CommandCount; i ++ ) { if(gFlashInfo[Index].CommandType & gFlashCommandId[i].CommandType) { Flag = 0; gIndex.IdIndex = i; break; } } if(Flag) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Can not Get ID Command!\n", __FUNCTION__,__LINE__)); return EFI_DEVICE_ERROR; } CommandCount = sizeof(gFlashCommandWrite) / sizeof(FLASH_COMMAND_WRITE); for(Flag = 1, i = 0;i < CommandCount; i ++ ) { if(gFlashInfo[Index].CommandType & gFlashCommandWrite[i].CommandType) { Flag = 0; gIndex.WIndex = i; break; } } if(Flag) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Can not Get Write Command!\n", __FUNCTION__,__LINE__)); return EFI_DEVICE_ERROR; } CommandCount = sizeof(gFlashCommandErase) / sizeof(FLASH_COMMAND_ERASE); for(Flag = 1, i = 0;i < CommandCount; i ++ ) { if(gFlashInfo[Index].CommandType & gFlashCommandErase[i].CommandType) { Flag = 0; gIndex.WIndex = i; break; } } if(Flag) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Can not Get Erase Command!\n", __FUNCTION__,__LINE__)); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } VOID FlashReset(UINT32 Base) { (VOID)PortWriteData(gIndex.InfIndex, Base, gFlashCommandReset[gIndex.ReIndex].ResetData); (void)gBS->Stall(20000); } void GetManufacturerID(UINT32 Index, UINT32 Base, UINT8 *pbyData) { UINT32 dwAddr; FlashReset(Base); dwAddr = Base + (gFlashCommandId[gIndex.IdIndex].ManuIDAddressStep1 << gFlashInfo[Index].ParallelNum); (VOID)PortWriteData(Index, dwAddr, gFlashCommandId[gIndex.IdIndex].ManuIDDataStep1); dwAddr = Base + (gFlashCommandId[gIndex.IdIndex].ManuIDAddressStep2 << gFlashInfo[Index].ParallelNum); (VOID)PortWriteData(Index, dwAddr, gFlashCommandId[gIndex.IdIndex].ManuIDDataStep2); dwAddr = Base + (gFlashCommandId[gIndex.IdIndex].ManuIDAddressStep3 << gFlashInfo[Index].ParallelNum); (VOID)PortWriteData(Index, dwAddr, gFlashCommandId[gIndex.IdIndex].ManuIDDataStep3); *pbyData = (UINT8)PortReadData(Index, Base + (gFlashCommandId[gIndex.IdIndex].ManuIDAddress << gFlashInfo[Index].ParallelNum)); FlashReset(Base); //must reset to return to the read mode } EFI_STATUS FlashInit(UINT32 Base) { UINT32 FlashCount = 0; UINT32 i = 0; EFI_STATUS Status; UINT8 Flag = 1; UINT32 TempData = 0; UINT32 TempDev1 = 0; UINT32 TempDev2 = 0; UINT32 TempDev3 = 0; UINT32 dwAddr; FlashCount = sizeof(gFlashInfo) / sizeof(NOR_FLASH_INFO_TABLE); for(;i < FlashCount; i ++ ) { Status = GetCommandIndex(i); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Get Command Index %r!\n", __FUNCTION__,__LINE__, Status)); return Status; } FlashReset(Base); dwAddr = Base + (gFlashCommandId[gIndex.IdIndex].ManuIDAddressStep1 << gFlashInfo[i].ParallelNum); (VOID)PortWriteData(i, dwAddr, gFlashCommandId[gIndex.IdIndex].ManuIDDataStep1); dwAddr = Base + (gFlashCommandId[gIndex.IdIndex].ManuIDAddressStep2 << gFlashInfo[i].ParallelNum); (VOID)PortWriteData(i, dwAddr, gFlashCommandId[gIndex.IdIndex].ManuIDDataStep2); dwAddr = Base + (gFlashCommandId[gIndex.IdIndex].ManuIDAddressStep3 << gFlashInfo[i].ParallelNum); (VOID)PortWriteData(i, dwAddr, gFlashCommandId[gIndex.IdIndex].ManuIDDataStep3); //Get manufacture ID TempData = PortReadData(i, Base + (gFlashCommandId[gIndex.IdIndex].ManuIDAddress << gFlashInfo[i].ParallelNum)); //Get Device Id TempDev1 = PortReadData(i, Base + (gFlashCommandId[gIndex.IdIndex].DeviceIDAddress1 << gFlashInfo[i].ParallelNum)); TempDev2 = PortReadData(i, Base + (gFlashCommandId[gIndex.IdIndex].DeviceIDAddress2 << gFlashInfo[i].ParallelNum)); TempDev3 = PortReadData(i, Base + (gFlashCommandId[gIndex.IdIndex].DeviceIDAddress3 << gFlashInfo[i].ParallelNum)); DEBUG ((EFI_D_ERROR, "[cdtest]manufactor ID 0x%x!\n",TempData)); DEBUG ((EFI_D_ERROR, "[cdtest]Device ID 1 0x%x!\n",TempDev1)); DEBUG ((EFI_D_ERROR, "[cdtest]Device ID 2 0x%x!\n",TempDev2)); DEBUG ((EFI_D_ERROR, "[cdtest]Device ID 3 0x%x!\n",TempDev3)); FlashReset(Base); if((0xffffffff != TempData) && (PortAdjustData(i, gFlashInfo[i].ManufacturerID) == TempData)) { if((0xffffffff != TempDev1) && (PortAdjustData(i, gFlashInfo[i].DeviceID1) == TempDev1)) { if((0xffffffff != TempDev2) && (PortAdjustData(i, gFlashInfo[i].DeviceID2) == TempDev2)) { if((0xffffffff != TempDev3) && (PortAdjustData(i, gFlashInfo[i].DeviceID3) == TempDev3)) { Flag = 0; gIndex.InfIndex = i; break; } } } } } if(Flag) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } static BOOLEAN width8IsAll( const UINT64 Base, const UINT64 Offset, const UINT64 Length, const UINT8 Value ) { UINT64 NewAddr = Base + Offset; UINT64 NewLength = Length; while (NewLength --) { if (*(UINT8 *)(UINTN)NewAddr == Value) { NewAddr ++; continue; } else { return FALSE; } } return TRUE; } EFI_STATUS BufferWriteCommand(UINTN Base, UINTN Offset, void *pData) { UINT32 dwCommAddr; UINT32 *pdwData; UINT16 *pwData; UINT32 dwLoop; UINT32 ulWriteWordCount; UINT32 dwAddr; if(gFlashBusy) { DEBUG((EFI_D_ERROR, "[%a]:[%dL]:Flash is busy!\n", __FUNCTION__,__LINE__)); return EFI_NOT_READY; } gFlashBusy = TRUE; if(2 == gFlashInfo[gIndex.InfIndex].ParallelNum) { pdwData = (UINT32 *)pData; dwAddr = (UINT32)Base + (gFlashCommandWrite[gIndex.WIndex].BufferProgramAddressStep1 << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandWrite[gIndex.WIndex].BufferProgramDataStep1); dwAddr = (UINT32)Base + (gFlashCommandWrite[gIndex.WIndex].BufferProgramAddressStep2 << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandWrite[gIndex.WIndex].BufferProgramDataStep2); //dwAddr = Base + (Offset << gFlashInfo[gIndex.InfIndex].ParallelNum); dwAddr = (UINT32)Base + Offset; (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandWrite[gIndex.WIndex].BufferProgramDataStep3); ulWriteWordCount = ((gFlashInfo[gIndex.InfIndex].BufferProgramSize - 1) << 16) | (gFlashInfo[gIndex.InfIndex].BufferProgramSize - 1); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, ulWriteWordCount); for (dwLoop = 0; dwLoop < gFlashInfo[gIndex.InfIndex].BufferProgramSize; dwLoop ++) { dwCommAddr = (UINT32)Base + (UINT32)Offset + (dwLoop << gFlashInfo[gIndex.InfIndex].ParallelNum); MmioWrite32 (dwCommAddr, *pdwData); pdwData ++; } dwAddr = (UINT32)Base + (UINT32)Offset + ((gFlashInfo[gIndex.InfIndex].BufferProgramSize - 1) << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandWrite[gIndex.WIndex].BufferProgramtoFlash); } else { pwData = (UINT16 *)pData; dwAddr = (UINT32)Base + (gFlashCommandWrite[gIndex.WIndex].BufferProgramAddressStep1 << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandWrite[gIndex.WIndex].BufferProgramDataStep1); dwAddr = (UINT32)Base + (gFlashCommandWrite[gIndex.WIndex].BufferProgramAddressStep2 << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandWrite[gIndex.WIndex].BufferProgramDataStep2); //dwAddr = Base + (Offset << gFlashInfo[gIndex.InfIndex].ParallelNum); dwAddr = (UINT32)Base + Offset; (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandWrite[gIndex.WIndex].BufferProgramDataStep3); ulWriteWordCount = gFlashInfo[gIndex.InfIndex].BufferProgramSize - 1; (VOID)PortWriteData(gIndex.InfIndex, dwAddr, ulWriteWordCount); for (dwLoop = 0; dwLoop < gFlashInfo[gIndex.InfIndex].BufferProgramSize; dwLoop ++) { dwCommAddr = (UINT32)Base + (UINT32)Offset + (dwLoop << gFlashInfo[gIndex.InfIndex].ParallelNum); MmioWrite16 (dwCommAddr, *pwData); pwData ++; } dwAddr = (UINT32)Base + (UINT32)Offset + ((gFlashInfo[gIndex.InfIndex].BufferProgramSize - 1) << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandWrite[gIndex.WIndex].BufferProgramtoFlash); } (void)gBS->Stall(200); gFlashBusy = FALSE; return EFI_SUCCESS; } EFI_STATUS SectorEraseCommand(UINTN Base, UINTN Offset) { UINT32 dwAddr; if(gFlashBusy) { DEBUG((EFI_D_ERROR, "[%a]:[%dL]:Flash is busy!\n", __FUNCTION__,__LINE__)); return EFI_NOT_READY; } gFlashBusy = TRUE; dwAddr = (UINT32)Base + (gFlashCommandErase[gIndex.EIndex].SectorEraseAddressStep1 << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandErase[gIndex.EIndex].SectorEraseDataStep1); dwAddr = (UINT32)Base + (gFlashCommandErase[gIndex.EIndex].SectorEraseAddressStep2 << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandErase[gIndex.EIndex].SectorEraseDataStep2); dwAddr = (UINT32)Base + (gFlashCommandErase[gIndex.EIndex].SectorEraseAddressStep3 << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandErase[gIndex.EIndex].SectorEraseDataStep3); dwAddr = (UINT32)Base + (gFlashCommandErase[gIndex.EIndex].SectorEraseAddressStep4 << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandErase[gIndex.EIndex].SectorEraseDataStep4); dwAddr = (UINT32)Base + (gFlashCommandErase[gIndex.EIndex].SectorEraseAddressStep5 << gFlashInfo[gIndex.InfIndex].ParallelNum); (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandErase[gIndex.EIndex].SectorEraseDataStep5); dwAddr = (UINT32)Base + Offset; (VOID)PortWriteData(gIndex.InfIndex, dwAddr, gFlashCommandErase[gIndex.EIndex].SectorEraseDataStep6); (void)gBS->Stall(500000); gFlashBusy = FALSE; return EFI_SUCCESS; } EFI_STATUS CompleteCheck(UINT32 Base, UINT32 Offset, void *pData, UINT32 Length) { UINT32 dwTestAddr; UINT32 dwTestData; UINT32 dwTemp = 0; UINT32 dwTemp1 = 0; UINT32 i; UINT32 dwTimeOut = 3000000; if(gFlashBusy) { DEBUG((EFI_D_ERROR, "[%a]:[%dL]:Flash is busy!\n", __FUNCTION__,__LINE__)); return EFI_NOT_READY; } gFlashBusy = TRUE; if(2 == gFlashInfo[gIndex.InfIndex].ParallelNum) { dwTestAddr = Base + Offset + Length - sizeof(UINT32); dwTestData = *((UINT32 *)((UINT8 *)pData + Length - sizeof(UINT32))); while(dwTimeOut--) { dwTemp1 = MmioRead32 (dwTestAddr); if (dwTestData == dwTemp1) { dwTemp = MmioRead32 (dwTestAddr); dwTemp1 = MmioRead32 (dwTestAddr); if ((dwTemp == dwTemp1) && (dwTestData == dwTemp1)) { gFlashBusy = FALSE; return EFI_SUCCESS; } } (void)gBS->Stall(1); } if((UINT16)(dwTemp1 >> 16) != (UINT16)(dwTestData >> 16)) { DEBUG((EFI_D_ERROR, "CompleteCheck ERROR: chip1 address %x, buffer %x, flash %x!\n", Offset, dwTestData, dwTemp1)); } if((UINT16)(dwTemp1) != (UINT16)(dwTestData)) { DEBUG((EFI_D_ERROR, "CompleteCheck ERROR: chip2 address %x, buffer %x, flash %x!\n", Offset, dwTestData, dwTemp1)); } } else { dwTestAddr = Base + Offset + Length - sizeof(UINT16); dwTestData = *((UINT16 *)((UINT8 *)pData + Length - sizeof(UINT16))); while(dwTimeOut--) { dwTemp1 = MmioRead16 (dwTestAddr); if (dwTestData == dwTemp1) { dwTemp = MmioRead16 (dwTestAddr); dwTemp1 = MmioRead16 (dwTestAddr); if ((dwTemp == dwTemp1) && (dwTestData == dwTemp1)) { gFlashBusy = FALSE; return EFI_SUCCESS; } } (void)gBS->Stall(1); } } for(i = 0; i < 5; i ++) { DEBUG((EFI_D_ERROR, "CompleteCheck ERROR: flash %x\n",PortReadData(gIndex.InfIndex, dwTestAddr))); } FlashReset(Base); gFlashBusy = FALSE; DEBUG((EFI_D_ERROR, "CompleteCheck ERROR: timeout address %x, buffer %x, flash %x\n", Offset, dwTestData, dwTemp1)); return EFI_TIMEOUT; } EFI_STATUS IsNeedToWrite( IN UINT32 Base, IN UINT32 Offset, IN UINT8 *Buffer, IN UINT32 Length ) { UINTN NewAddr = Base + Offset; UINT8 FlashData = 0; UINT8 BufferData = 0; for(; Length > 0; Length --) { BufferData = *Buffer; //lint -epn -e511 FlashData = *(UINT8 *)NewAddr; if (BufferData != FlashData) { return TRUE; } NewAddr ++; Buffer ++; } return FALSE; } EFI_STATUS BufferWrite(UINT32 Offset, void *pData, UINT32 Length) { EFI_STATUS Status; UINT32 dwLoop; UINT32 Retry = 3; if (FALSE == IsNeedToWrite(gIndex.Base, Offset, (UINT8 *)pData, Length)) { return EFI_SUCCESS; } do { (void)BufferWriteCommand(gIndex.Base, Offset, pData); Status = CompleteCheck(gIndex.Base, Offset, pData, Length); if (EFI_SUCCESS == Status) { for (dwLoop = 0; dwLoop < Length; dwLoop ++) { if (*(UINT8 *)(UINTN)(gIndex.Base + Offset + dwLoop) != *((UINT8 *)pData + dwLoop)) { DEBUG((EFI_D_ERROR, "Flash_WriteUnit ERROR: address %x, buffer %x, flash %x\n", Offset, *((UINT8 *)pData + dwLoop), *(UINT8 *)(UINTN)(gIndex.Base + Offset + dwLoop))); Status = EFI_ABORTED; continue; } } } else { DEBUG((EFI_D_ERROR, "Flash_WriteUnit ERROR: complete check failed, %r\n", Status)); continue; } } while ((Retry--) && EFI_ERROR(Status)); return Status; } EFI_STATUS SectorErase(UINT32 Base, UINT32 Offset) { UINT8 gTemp[FLASH_MAX_UNIT]; UINT64 dwLoop = FLASH_MAX_UNIT - 1; UINT32 Retry = 3; EFI_STATUS Status; do { gTemp[dwLoop] = 0xFF; }while (dwLoop --); do { (void)SectorEraseCommand(Base, Offset); Status = CompleteCheck(Base, Offset, (void *)gTemp, FLASH_MAX_UNIT); if (EFI_SUCCESS == Status) { if (width8IsAll(Base,Offset - (Offset % gFlashInfo[gIndex.InfIndex].BlockSize), gFlashInfo[gIndex.InfIndex].BlockSize, 0xFF)) { return EFI_SUCCESS; } else { DEBUG((EFI_D_ERROR, "Flash_SectorErase ERROR: not all address equal 0xFF\n")); Status = EFI_ABORTED; continue; } } else { DEBUG((EFI_D_ERROR, "Flash_SectorErase ERROR: complete check failed, %r\n", Status)); continue; } }while ((Retry--) && EFI_ERROR(Status)); if(Retry) { //do nothing for pclint } return Status; }