/** @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 #include #include #include #include "NorFlashHw.h" EFI_STATUS Erase( IN UNI_NOR_FLASH_PROTOCOL *This, IN UINT32 Offset, IN UINT32 Length ); EFI_STATUS Write( IN UNI_NOR_FLASH_PROTOCOL *This, IN UINT32 Offset, IN UINT8 *Buffer, UINT32 ulLength ); EFI_STATUS Read( IN UNI_NOR_FLASH_PROTOCOL *This, IN UINT32 Offset, IN OUT UINT8 *Buffer, IN UINT32 ulLen ); UNI_NOR_FLASH_PROTOCOL gUniNorFlash = { Erase, Write, Read }; EFI_STATUS EFIAPI Read( IN UNI_NOR_FLASH_PROTOCOL *This, IN UINT32 Offset, IN OUT UINT8 *Buffer, IN UINT32 ulLen ) { UINT32 index; UINT64 ullAddr; UINT32 ullCnt = 0; UINT32 *puiBuffer32 = NULL; UINT32 *puiDst32 = NULL; UINT8 *pucBuffer8 = NULL; UINT8 *pucDst8 = NULL; if (Offset + ulLen > (gFlashInfo[gIndex.InfIndex].SingleChipSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Exceed the flash scope!\n", __FUNCTION__,__LINE__)); return EFI_INVALID_PARAMETER; } if (0 == ulLen) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Length is Zero!\n", __FUNCTION__,__LINE__)); return EFI_INVALID_PARAMETER; } if (NULL == Buffer) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Buffer is NULL!\n", __FUNCTION__,__LINE__)); return EFI_BAD_BUFFER_SIZE; } ullAddr = gIndex.Base + Offset; pucBuffer8 = (UINT8 *)Buffer; pucDst8 = (UINT8 *)((UINTN)ullAddr); if (ulLen < FOUR_BYTE_UNIT) { for(index = 0; index< ulLen; index++) { *pucBuffer8++ = *pucDst8++; } } else { ullCnt = Offset % FOUR_BYTE_UNIT; ullCnt = FOUR_BYTE_UNIT - ullCnt; for(index = 0; index < ullCnt; index++) { *pucBuffer8++ = *pucDst8++; } ulLen -= ullCnt; puiBuffer32 = (UINT32 *)pucBuffer8; puiDst32 = (UINT32 *)pucDst8; ullCnt = ulLen / FOUR_BYTE_UNIT; for(index = 0; index < ullCnt; index++) { *puiBuffer32++ = *puiDst32++; } ullCnt = ulLen % FOUR_BYTE_UNIT; pucBuffer8 = (UINT8 *)puiBuffer32; pucDst8 = (UINT8 *)puiDst32; for(index = 0; index < ullCnt; index++) { *pucBuffer8++ = *pucDst8++; } } return EFI_SUCCESS; } static EFI_STATUS WriteAfterErase_Fill( IN const UINT32 Offset, IN const UINT8 *Buffer, IN const UINT32 Length ) { EFI_STATUS Status; UINT32 Loop; UINT32 DataOffset; UINT32 NewOffset; UINT8 *NewDataUnit; UINT32 FlashUnitLength; FlashUnitLength = gFlashInfo[gIndex.InfIndex].BufferProgramSize << gFlashInfo[gIndex.InfIndex].ParallelNum; if (0 == Length) { return EFI_SUCCESS; } if ((Offset % FlashUnitLength + Length) > FlashUnitLength) { DEBUG ((EFI_D_INFO, "[%a]:[%dL]:Exceed the Flash Size!\n", __FUNCTION__,__LINE__)); return EFI_UNSUPPORTED; } Status = gBS->AllocatePool(EfiBootServicesData, FlashUnitLength, (VOID *)&NewDataUnit); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Allocate Pool failed, %r!\n", __FUNCTION__,__LINE__, Status)); return Status; } NewOffset = Offset - (Offset % FlashUnitLength); gBS->CopyMem((VOID *)NewDataUnit, (VOID *)(UINTN)(gIndex.Base + NewOffset), FlashUnitLength); DataOffset = Offset % FlashUnitLength; for (Loop = 0; Loop < Length; Loop ++) { NewDataUnit[(UINT32)(DataOffset + Loop)] = Buffer[Loop]; } Status = BufferWrite(NewOffset, (void *)NewDataUnit, FlashUnitLength); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:BufferWrite %r!\n", __FUNCTION__,__LINE__, Status)); return Status; } (void)gBS->FreePool((VOID *)NewDataUnit); return Status; } static EFI_STATUS WriteAfterErase_Final( IN UINT32 Offset, IN UINT8 *Buffer, IN UINT32 Length ) { EFI_STATUS Status; UINT32 Loop; UINT32 FlashUnitLength; FlashUnitLength = gFlashInfo[gIndex.InfIndex].BufferProgramSize << gFlashInfo[gIndex.InfIndex].ParallelNum; if (0 == Length) { return EFI_SUCCESS; } if (0 != (Offset % FlashUnitLength)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: Offset must be a multiple of 0x%x!\n", __FUNCTION__,__LINE__,FlashUnitLength)); return EFI_UNSUPPORTED; } Loop = Length / FlashUnitLength; while (Loop --) { Status = BufferWrite(Offset, (void *)Buffer, FlashUnitLength); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:BufferWrite Failed: %r!\n", __FUNCTION__,__LINE__, Status)); return EFI_DEVICE_ERROR; } Offset += FlashUnitLength; Buffer += FlashUnitLength; } Length = Length % FlashUnitLength; if (Length) { Status = WriteAfterErase_Fill(Offset, Buffer, Length); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:WriteAfterErase_Fill failed,%r!\n", __FUNCTION__,__LINE__, Status)); return Status; } } return EFI_SUCCESS; } EFI_STATUS WriteAfterErase( UINT32 TempBase, UINT32 Offset, UINT8 *Buffer, UINT32 Length ) { EFI_STATUS Status; UINT32 FlashUnitLength; FlashUnitLength = gFlashInfo[gIndex.InfIndex].BufferProgramSize << gFlashInfo[gIndex.InfIndex].ParallelNum; if (0 == Length) { return EFI_SUCCESS; } if (Offset % FlashUnitLength) { UINT32 TempLength; TempLength = FlashUnitLength - (Offset % FlashUnitLength); if (TempLength > Length) { TempLength = Length; } Status = WriteAfterErase_Fill(Offset, Buffer, TempLength); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: %r!\n", __FUNCTION__,__LINE__, Status)); return Status; } Offset += TempLength; Length -= TempLength; Buffer += TempLength; //Desc:if Offset >= gOneFlashSize,modify base if (0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize)) { TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize; gIndex.Base = TempBase; Offset = 0; } } Status = WriteAfterErase_Final(Offset, Buffer, Length); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: %r!\n", __FUNCTION__,__LINE__, Status)); return Status; } return EFI_SUCCESS; } EFI_STATUS FlashSectorErase( UINT32 TempBase, UINT32 Offset, UINT32 Length ) { EFI_STATUS Status; UINT32 SectorOffset; UINT8 *StaticBuffer; UINT8 *Buffer; UINT32 TempOffset; UINT32 TempLength; UINT32 LeftLength; if (0 == Length) { return EFI_SUCCESS; } LeftLength = gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)); if (LeftLength < Length) { return EFI_UNSUPPORTED; } SectorOffset = Offset - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)); Status = gBS->AllocatePool(EfiBootServicesData, gFlashInfo[gIndex.InfIndex].BlockSize * (UINTN)gFlashInfo[gIndex.InfIndex].ParallelNum, (VOID *)&StaticBuffer); if (EFI_ERROR(Status)) { return Status; } Buffer = StaticBuffer; gBS->CopyMem((VOID *)Buffer, (VOID *)(UINTN)(TempBase + SectorOffset), (gFlashInfo[gIndex.InfIndex].BlockSize * (UINTN)gFlashInfo[gIndex.InfIndex].ParallelNum)); Status = SectorErase(TempBase, SectorOffset); if (EFI_ERROR(Status)) { goto DO; } TempOffset = SectorOffset; TempLength = Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum); Status = WriteAfterErase(TempBase, TempOffset, Buffer, TempLength); if (EFI_ERROR(Status)) { goto DO; } Buffer = Buffer + TempLength + Length; TempOffset = Offset + Length; TempLength = SectorOffset + (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum) - TempOffset; Status = WriteAfterErase(TempBase, TempOffset, Buffer, TempLength); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: %r!\n", __FUNCTION__,__LINE__,Status)); goto DO; } (void)gBS->FreePool((VOID *)StaticBuffer); return EFI_SUCCESS; DO: (void)gBS->FreePool((VOID *)StaticBuffer); return Status; } EFI_STATUS EFIAPI Erase( IN UNI_NOR_FLASH_PROTOCOL *This, IN UINT32 Offset, IN UINT32 Length ) { EFI_STATUS Status = EFI_SUCCESS; UINT32 Sectors; UINT32 TempLength; UINT32 TempBase; UINT32 Loop; if (Offset + Length > (gFlashInfo[gIndex.InfIndex].SingleChipSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Exceed the Flash Size!\n", __FUNCTION__,__LINE__)); return EFI_ABORTED; } if (0 == Length) { return EFI_SUCCESS; } Sectors = ((Offset + Length - 1) / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) - (Offset / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) + 1; TempBase = gIndex.Base; //if Offset >= gOneFlashSize,modify base if(0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize)) { TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize * (Offset/gFlashInfo[gIndex.InfIndex].SingleChipSize); Offset = Offset - (Offset & gFlashInfo[gIndex.InfIndex].SingleChipSize); } for (Loop = 0; Loop <= Sectors; Loop ++) { TempLength = gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)); if (TempLength > Length) { TempLength = Length; } Status = FlashSectorErase(TempBase, Offset, TempLength); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: FlashErase One Sector Error, Status = %r!\n", __FUNCTION__,__LINE__,Status)); return Status; } Offset += TempLength; //if Offset >= gOneFlashSize,modify base if (0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize)) { TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize; Offset = 0; } Length -= TempLength; } return Status; } EFI_STATUS EFIAPI Write( IN UNI_NOR_FLASH_PROTOCOL *This, IN UINT32 Offset, IN UINT8 *Buffer, UINT32 ulLength ) { EFI_STATUS Status; UINT32 TempLength; UINT32 TempBase; UINT32 Loop; UINT32 Sectors; if((Offset + ulLength) > (gFlashInfo[gIndex.InfIndex].SingleChipSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Exceed the Flash Size!\n", __FUNCTION__,__LINE__)); return EFI_INVALID_PARAMETER; } if (0 == ulLength) { return EFI_SUCCESS; } Sectors = ((Offset + ulLength - 1) / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) - (Offset / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) + 1; TempBase = gIndex.Base; //if Offset >= gOneFlashSize,modify base if(0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize)) { TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize * (Offset/gFlashInfo[gIndex.InfIndex].SingleChipSize); Offset = Offset - (Offset & gFlashInfo[gIndex.InfIndex].SingleChipSize); } for (Loop = 0; Loop <= Sectors; Loop ++) { TempLength = gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)); if (TempLength > ulLength) { TempLength = ulLength; } if (TRUE == IsNeedToWrite(TempBase, Offset, Buffer, TempLength)) { Status = FlashSectorErase(TempBase, Offset, TempLength); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:FlashErase One Sector Error, Status = %r!\n", __FUNCTION__,__LINE__,Status)); return Status; } Status = WriteAfterErase(TempBase, Offset, Buffer, TempLength); if (EFI_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:WriteAfterErase Status = %r!\n", __FUNCTION__,__LINE__,Status)); return Status; } } Offset += TempLength; Buffer += TempLength; //if Offset >= gOneFlashSize,modify base if (0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize)) { TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize; Offset = 0; } ulLength -= TempLength; } return EFI_SUCCESS; } VOID SetFlashAttributeToUncache(VOID) { EFI_CPU_ARCH_PROTOCOL *gCpu = NULL; EFI_STATUS Status; Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "LocateProtocol gEfiCpuArchProtocolGuid Status = %r !\n", Status)); } Status = gCpu->SetMemoryAttributes( gCpu, PcdGet64(PcdNORFlashBase), PcdGet32(PcdNORFlashCachableSize), EFI_MEMORY_UC ); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "gCpu->SetMemoryAttributes Status = %r !\n", Status)); } } EFI_STATUS EFIAPI InitializeFlash ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { EFI_STATUS Status; gIndex.Base = (UINT32)PcdGet64(PcdNORFlashBase); SetFlashAttributeToUncache(); Status = FlashInit(gIndex.Base); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "Init Flash Error !\n")); return Status; } else { DEBUG((EFI_D_ERROR, "Init Flash OK!\n")); } Status = gBS->InstallProtocolInterface ( &ImageHandle, &gUniNorFlashProtocolGuid, EFI_NATIVE_INTERFACE, &gUniNorFlash); if(EFI_SUCCESS != Status) { DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Install Protocol Interface %r!\n", __FUNCTION__,__LINE__,Status)); } return Status; }