summaryrefslogtreecommitdiff
path: root/Silicon/Hisilicon/Drivers/NorFlashDxe/NorFlashDxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/Hisilicon/Drivers/NorFlashDxe/NorFlashDxe.c')
-rw-r--r--Silicon/Hisilicon/Drivers/NorFlashDxe/NorFlashDxe.c594
1 files changed, 594 insertions, 0 deletions
diff --git a/Silicon/Hisilicon/Drivers/NorFlashDxe/NorFlashDxe.c b/Silicon/Hisilicon/Drivers/NorFlashDxe/NorFlashDxe.c
new file mode 100644
index 0000000000..8b8a5d7a3f
--- /dev/null
+++ b/Silicon/Hisilicon/Drivers/NorFlashDxe/NorFlashDxe.c
@@ -0,0 +1,594 @@
+/** @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 <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ArmLib.h>
+#include <Library/PcdLib.h>
+#include <Protocol/NorFlashProtocol.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Protocol/Cpu.h>
+#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;
+}