Home | History | Annotate | Download | only in NorFlashDxe
      1 /** @file
      2 *
      3 *  Copyright (c) 2015, Hisilicon Limited. All rights reserved.
      4 *  Copyright (c) 2015, Linaro Limited. All rights reserved.
      5 *
      6 *  This program and the accompanying materials
      7 *  are licensed and made available under the terms and conditions of the BSD License
      8 *  which accompanies this distribution.  The full text of the license may be found at
      9 *  http://opensource.org/licenses/bsd-license.php
     10 *
     11 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 *
     14 **/
     15 
     16 
     17 #include <Uefi.h>
     18 #include <Library/DebugLib.h>
     19 #include <Library/UefiBootServicesTableLib.h>
     20 #include <Library/ArmLib.h>
     21 #include <Library/PcdLib.h>
     22 #include <Protocol/NorFlashProtocol.h>
     23 #include <Library/DxeServicesTableLib.h>
     24 #include <Protocol/Cpu.h>
     25 #include "NorFlashHw.h"
     26 
     27 
     28 EFI_STATUS Erase(
     29    IN UNI_NOR_FLASH_PROTOCOL   *This,
     30    IN  UINT32                   Offset,
     31    IN  UINT32                   Length
     32   );
     33 
     34 EFI_STATUS  Write(
     35   IN UNI_NOR_FLASH_PROTOCOL   *This,
     36   IN  UINT32                  Offset,
     37   IN  UINT8                  *Buffer,
     38   UINT32                     ulLength
     39   );
     40 
     41 EFI_STATUS Read(
     42   IN UNI_NOR_FLASH_PROTOCOL   *This,
     43   IN UINT32                   Offset,
     44   IN OUT UINT8               *Buffer,
     45   IN UINT32                   ulLen
     46   );
     47 
     48 UNI_NOR_FLASH_PROTOCOL gUniNorFlash = {
     49     Erase,
     50     Write,
     51     Read
     52 };
     53 
     54 
     55 EFI_STATUS
     56 EFIAPI Read(
     57   IN UNI_NOR_FLASH_PROTOCOL   *This,
     58   IN UINT32                   Offset,
     59   IN OUT UINT8               *Buffer,
     60   IN UINT32                    ulLen
     61   )
     62 {
     63     UINT32       index;
     64     UINT64 ullAddr;
     65     UINT32 ullCnt = 0;
     66     UINT32 *puiBuffer32 = NULL;
     67     UINT32 *puiDst32 = NULL;
     68     UINT8 *pucBuffer8 = NULL;
     69     UINT8 *pucDst8 = NULL;
     70 
     71     if (Offset + ulLen > (gFlashInfo[gIndex.InfIndex].SingleChipSize * gFlashInfo[gIndex.InfIndex].ParallelNum))
     72     {
     73         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Exceed the flash scope!\n", __FUNCTION__,__LINE__));
     74         return EFI_INVALID_PARAMETER;
     75     }
     76     if (0 == ulLen)
     77     {
     78         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Length is Zero!\n", __FUNCTION__,__LINE__));
     79         return EFI_INVALID_PARAMETER;
     80     }
     81     if (NULL == Buffer)
     82     {
     83         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Buffer is NULL!\n", __FUNCTION__,__LINE__));
     84         return EFI_BAD_BUFFER_SIZE;
     85     }
     86 
     87 
     88     ullAddr = gIndex.Base + Offset;
     89 
     90     pucBuffer8 = (UINT8 *)Buffer;
     91     pucDst8    = (UINT8 *)((UINTN)ullAddr);
     92 
     93 
     94     if (ulLen < FOUR_BYTE_UNIT)
     95     {
     96         for(index = 0; index< ulLen; index++)
     97         {
     98             *pucBuffer8++ = *pucDst8++;
     99         }
    100     }
    101     else
    102     {
    103 
    104         ullCnt = Offset % FOUR_BYTE_UNIT;
    105         ullCnt = FOUR_BYTE_UNIT - ullCnt;
    106 
    107         for(index = 0; index < ullCnt; index++)
    108         {
    109             *pucBuffer8++ = *pucDst8++;
    110         }
    111 
    112         ulLen -= ullCnt;
    113 
    114         puiBuffer32 = (UINT32 *)pucBuffer8;
    115         puiDst32    = (UINT32 *)pucDst8;
    116         ullCnt      = ulLen / FOUR_BYTE_UNIT;
    117 
    118         for(index = 0; index < ullCnt; index++)
    119         {
    120             *puiBuffer32++ = *puiDst32++;
    121         }
    122 
    123         ullCnt     = ulLen % FOUR_BYTE_UNIT;
    124         pucBuffer8 = (UINT8 *)puiBuffer32;
    125         pucDst8    = (UINT8 *)puiDst32;
    126 
    127         for(index = 0; index < ullCnt; index++)
    128         {
    129             *pucBuffer8++ = *pucDst8++;
    130         }
    131     }
    132 
    133     return EFI_SUCCESS;
    134 }
    135 
    136 
    137 
    138 static EFI_STATUS WriteAfterErase_Fill(
    139     IN  const UINT32       Offset,
    140     IN  const UINT8       *Buffer,
    141     IN  const UINT32       Length
    142     )
    143 {
    144     EFI_STATUS Status;
    145     UINT32 Loop;
    146     UINT32 DataOffset;
    147     UINT32 NewOffset;
    148     UINT8 *NewDataUnit;
    149 
    150     UINT32 FlashUnitLength;
    151 
    152     FlashUnitLength = gFlashInfo[gIndex.InfIndex].BufferProgramSize << gFlashInfo[gIndex.InfIndex].ParallelNum;
    153 
    154     if (0 == Length)
    155     {
    156         return EFI_SUCCESS;
    157     }
    158     if ((Offset % FlashUnitLength + Length) > FlashUnitLength)
    159     {
    160         DEBUG ((EFI_D_INFO, "[%a]:[%dL]:Exceed the Flash Size!\n", __FUNCTION__,__LINE__));
    161         return EFI_UNSUPPORTED;
    162     }
    163 
    164 
    165     Status = gBS->AllocatePool(EfiBootServicesData, FlashUnitLength, (VOID *)&NewDataUnit);
    166     if (EFI_ERROR(Status))
    167     {
    168         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Allocate Pool failed, %r!\n", __FUNCTION__,__LINE__, Status));
    169         return Status;
    170     }
    171 
    172 
    173     NewOffset = Offset - (Offset % FlashUnitLength);
    174 
    175     gBS->CopyMem((VOID *)NewDataUnit, (VOID *)(UINTN)(gIndex.Base + NewOffset), FlashUnitLength);
    176 
    177     DataOffset = Offset % FlashUnitLength;
    178     for (Loop = 0; Loop < Length; Loop ++)
    179     {
    180         NewDataUnit[(UINT32)(DataOffset + Loop)] = Buffer[Loop];
    181     }
    182 
    183     Status = BufferWrite(NewOffset, (void *)NewDataUnit, FlashUnitLength);
    184     if (EFI_ERROR(Status))
    185     {
    186         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:BufferWrite %r!\n", __FUNCTION__,__LINE__, Status));
    187         return Status;
    188     }
    189 
    190     (void)gBS->FreePool((VOID *)NewDataUnit);
    191     return Status;
    192 }
    193 
    194 
    195 static EFI_STATUS WriteAfterErase_Final(
    196     IN  UINT32       Offset,
    197     IN  UINT8       *Buffer,
    198     IN  UINT32       Length
    199     )
    200 {
    201     EFI_STATUS Status;
    202     UINT32 Loop;
    203     UINT32 FlashUnitLength;
    204 
    205     FlashUnitLength = gFlashInfo[gIndex.InfIndex].BufferProgramSize << gFlashInfo[gIndex.InfIndex].ParallelNum;
    206 
    207     if (0 == Length)
    208     {
    209         return EFI_SUCCESS;
    210     }
    211 
    212     if (0 != (Offset % FlashUnitLength))
    213     {
    214         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: Offset must be a multiple of 0x%x!\n", __FUNCTION__,__LINE__,FlashUnitLength));
    215         return EFI_UNSUPPORTED;
    216     }
    217 
    218 
    219     Loop = Length / FlashUnitLength;
    220     while (Loop --)
    221     {
    222         Status = BufferWrite(Offset, (void *)Buffer, FlashUnitLength);
    223         if (EFI_ERROR(Status))
    224         {
    225             DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:BufferWrite Failed: %r!\n", __FUNCTION__,__LINE__, Status));
    226             return EFI_DEVICE_ERROR;
    227         }
    228         Offset += FlashUnitLength;
    229         Buffer += FlashUnitLength;
    230     }
    231 
    232 
    233     Length = Length % FlashUnitLength;
    234     if (Length)
    235     {
    236         Status = WriteAfterErase_Fill(Offset, Buffer, Length);
    237         if (EFI_ERROR(Status))
    238         {
    239             DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:WriteAfterErase_Fill failed,%r!\n", __FUNCTION__,__LINE__, Status));
    240             return Status;
    241         }
    242     }
    243 
    244     return EFI_SUCCESS;
    245 }
    246 
    247 EFI_STATUS
    248 WriteAfterErase(
    249     UINT32       TempBase,
    250     UINT32       Offset,
    251     UINT8       *Buffer,
    252     UINT32       Length
    253   )
    254 {
    255     EFI_STATUS Status;
    256     UINT32 FlashUnitLength;
    257 
    258     FlashUnitLength = gFlashInfo[gIndex.InfIndex].BufferProgramSize << gFlashInfo[gIndex.InfIndex].ParallelNum;
    259 
    260     if (0 == Length)
    261     {
    262         return EFI_SUCCESS;
    263     }
    264 
    265 
    266     if (Offset % FlashUnitLength)
    267     {
    268         UINT32 TempLength;
    269 
    270 
    271         TempLength = FlashUnitLength - (Offset % FlashUnitLength);
    272         if (TempLength > Length)
    273         {
    274             TempLength = Length;
    275         }
    276         Status = WriteAfterErase_Fill(Offset, Buffer, TempLength);
    277         if (EFI_ERROR(Status))
    278         {
    279             DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: %r!\n", __FUNCTION__,__LINE__, Status));
    280             return Status;
    281         }
    282 
    283         Offset += TempLength;
    284         Length -= TempLength;
    285         Buffer += TempLength;
    286 
    287         //Desc:if Offset >= gOneFlashSize,modify base
    288         if (0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
    289         {
    290             TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize;
    291             gIndex.Base = TempBase;
    292             Offset = 0;
    293         }
    294     }
    295 
    296 
    297     Status = WriteAfterErase_Final(Offset, Buffer, Length);
    298     if (EFI_ERROR(Status))
    299     {
    300         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: %r!\n", __FUNCTION__,__LINE__, Status));
    301         return Status;
    302     }
    303 
    304     return EFI_SUCCESS;
    305 }
    306 
    307 
    308 EFI_STATUS
    309 FlashSectorErase(
    310     UINT32      TempBase,
    311     UINT32      Offset,
    312     UINT32      Length
    313   )
    314 {
    315     EFI_STATUS  Status;
    316     UINT32 SectorOffset;
    317     UINT8 *StaticBuffer;
    318     UINT8 *Buffer;
    319     UINT32 TempOffset;
    320     UINT32 TempLength;
    321     UINT32 LeftLength;
    322 
    323 
    324     if (0 == Length)
    325     {
    326         return EFI_SUCCESS;
    327     }
    328 
    329     LeftLength = gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum));
    330     if (LeftLength < Length)
    331     {
    332         return EFI_UNSUPPORTED;
    333     }
    334 
    335 
    336     SectorOffset = Offset - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum));
    337 
    338     Status = gBS->AllocatePool(EfiBootServicesData, gFlashInfo[gIndex.InfIndex].BlockSize * (UINTN)gFlashInfo[gIndex.InfIndex].ParallelNum, (VOID *)&StaticBuffer);
    339     if (EFI_ERROR(Status))
    340     {
    341         return Status;
    342     }
    343 
    344     Buffer = StaticBuffer;
    345 
    346     gBS->CopyMem((VOID *)Buffer, (VOID *)(UINTN)(TempBase + SectorOffset),
    347                  (gFlashInfo[gIndex.InfIndex].BlockSize * (UINTN)gFlashInfo[gIndex.InfIndex].ParallelNum));
    348 
    349 
    350     Status = SectorErase(TempBase, SectorOffset);
    351     if (EFI_ERROR(Status))
    352     {
    353         goto DO;
    354     }
    355 
    356 
    357     TempOffset = SectorOffset;
    358     TempLength = Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum);
    359 
    360     Status = WriteAfterErase(TempBase, TempOffset, Buffer, TempLength);
    361     if (EFI_ERROR(Status))
    362     {
    363         goto DO;
    364     }
    365 
    366 
    367     Buffer = Buffer + TempLength + Length;
    368     TempOffset = Offset + Length;
    369     TempLength = SectorOffset + (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum) - TempOffset;
    370 
    371     Status = WriteAfterErase(TempBase, TempOffset, Buffer, TempLength);
    372     if (EFI_ERROR(Status))
    373     {
    374         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: %r!\n", __FUNCTION__,__LINE__,Status));
    375         goto DO;
    376     }
    377 
    378     (void)gBS->FreePool((VOID *)StaticBuffer);
    379     return EFI_SUCCESS;
    380 
    381 DO:
    382     (void)gBS->FreePool((VOID *)StaticBuffer);
    383     return Status;
    384 }
    385 
    386 
    387 EFI_STATUS
    388 EFIAPI Erase(
    389    IN UNI_NOR_FLASH_PROTOCOL   *This,
    390    IN UINT32                   Offset,
    391    IN UINT32                   Length
    392   )
    393 {
    394     EFI_STATUS  Status = EFI_SUCCESS;
    395     UINT32 Sectors;
    396     UINT32 TempLength;
    397     UINT32 TempBase;
    398     UINT32 Loop;
    399 
    400 
    401     if (Offset + Length > (gFlashInfo[gIndex.InfIndex].SingleChipSize * gFlashInfo[gIndex.InfIndex].ParallelNum))
    402     {
    403         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Exceed the Flash Size!\n", __FUNCTION__,__LINE__));
    404         return EFI_ABORTED;
    405     }
    406     if (0 == Length)
    407     {
    408         return EFI_SUCCESS;
    409     }
    410 
    411 
    412     Sectors = ((Offset + Length - 1) / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) - (Offset / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) + 1;
    413     TempBase = gIndex.Base;
    414 
    415     //if Offset >= gOneFlashSize,modify base
    416     if(0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
    417     {
    418         TempBase +=  gFlashInfo[gIndex.InfIndex].SingleChipSize * (Offset/gFlashInfo[gIndex.InfIndex].SingleChipSize);
    419         Offset = Offset - (Offset & gFlashInfo[gIndex.InfIndex].SingleChipSize);
    420     }
    421 
    422     for (Loop = 0; Loop <= Sectors; Loop ++)
    423     {
    424 
    425         TempLength = gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum));
    426 
    427 
    428         if (TempLength > Length)
    429         {
    430             TempLength = Length;
    431         }
    432 
    433         Status = FlashSectorErase(TempBase, Offset, TempLength);
    434         if (EFI_ERROR(Status))
    435         {
    436             DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: FlashErase One Sector Error, Status = %r!\n", __FUNCTION__,__LINE__,Status));
    437             return Status;
    438         }
    439 
    440         Offset += TempLength;
    441 
    442          //if Offset >= gOneFlashSize,modify base
    443         if (0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
    444         {
    445             TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize;
    446             Offset = 0;
    447         }
    448         Length -= TempLength;
    449     }
    450 
    451     return Status;
    452 }
    453 
    454 
    455 EFI_STATUS
    456 EFIAPI Write(
    457   IN UNI_NOR_FLASH_PROTOCOL   *This,
    458   IN UINT32                   Offset,
    459   IN UINT8                   *Buffer,
    460   UINT32                     ulLength
    461   )
    462 {
    463     EFI_STATUS  Status;
    464     UINT32     TempLength;
    465     UINT32       TempBase;
    466     UINT32           Loop;
    467     UINT32        Sectors;
    468 
    469     if((Offset + ulLength) > (gFlashInfo[gIndex.InfIndex].SingleChipSize * gFlashInfo[gIndex.InfIndex].ParallelNum))
    470     {
    471         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Exceed the Flash Size!\n", __FUNCTION__,__LINE__));
    472         return EFI_INVALID_PARAMETER;
    473     }
    474     if (0 == ulLength)
    475     {
    476         return EFI_SUCCESS;
    477     }
    478 
    479 
    480     Sectors = ((Offset + ulLength - 1) / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) - (Offset / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) + 1;
    481     TempBase = gIndex.Base;
    482 
    483     //if Offset >= gOneFlashSize,modify base
    484     if(0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
    485     {
    486         TempBase +=  gFlashInfo[gIndex.InfIndex].SingleChipSize * (Offset/gFlashInfo[gIndex.InfIndex].SingleChipSize);
    487         Offset = Offset - (Offset & gFlashInfo[gIndex.InfIndex].SingleChipSize);
    488     }
    489 
    490     for (Loop = 0; Loop <= Sectors; Loop ++)
    491     {
    492 
    493         TempLength = gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum));
    494 
    495 
    496         if (TempLength > ulLength)
    497         {
    498             TempLength = ulLength;
    499         }
    500 
    501 
    502         if (TRUE == IsNeedToWrite(TempBase, Offset, Buffer, TempLength))
    503         {
    504             Status = FlashSectorErase(TempBase, Offset, TempLength);
    505             if (EFI_ERROR(Status))
    506             {
    507                 DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:FlashErase One Sector Error, Status = %r!\n", __FUNCTION__,__LINE__,Status));
    508                 return Status;
    509             }
    510 
    511 
    512             Status = WriteAfterErase(TempBase, Offset, Buffer, TempLength);
    513             if (EFI_ERROR(Status))
    514             {
    515                 DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:WriteAfterErase Status = %r!\n", __FUNCTION__,__LINE__,Status));
    516                 return Status;
    517             }
    518         }
    519 
    520         Offset += TempLength;
    521         Buffer += TempLength;
    522 
    523          //if Offset >= gOneFlashSize,modify base
    524         if (0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
    525         {
    526             TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize;
    527             Offset = 0;
    528         }
    529         ulLength -= TempLength;
    530     }
    531 
    532     return EFI_SUCCESS;
    533 }
    534 
    535 
    536 VOID SetFlashAttributeToUncache(VOID)
    537 {
    538     EFI_CPU_ARCH_PROTOCOL             *gCpu           = NULL;
    539     EFI_STATUS Status;
    540 
    541     Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
    542     if (EFI_ERROR(Status))
    543     {
    544         DEBUG((EFI_D_ERROR, "LocateProtocol gEfiCpuArchProtocolGuid Status = %r !\n", Status));
    545     }
    546 
    547     Status = gCpu->SetMemoryAttributes(
    548                      gCpu,
    549                      PcdGet64(PcdNORFlashBase),
    550                      PcdGet32(PcdNORFlashCachableSize),
    551                      EFI_MEMORY_UC
    552                      );
    553 
    554     if (EFI_ERROR(Status))
    555     {
    556         DEBUG((EFI_D_ERROR, "gCpu->SetMemoryAttributes Status = %r !\n", Status));
    557     }
    558 
    559 }
    560 
    561 EFI_STATUS
    562 EFIAPI InitializeFlash (
    563   IN EFI_HANDLE         ImageHandle,
    564   IN EFI_SYSTEM_TABLE  *SystemTable)
    565 {
    566     EFI_STATUS Status;
    567 
    568 
    569     gIndex.Base = (UINT32)PcdGet64(PcdNORFlashBase);
    570 
    571     SetFlashAttributeToUncache();
    572     Status = FlashInit(gIndex.Base);
    573     if (EFI_ERROR(Status))
    574     {
    575         DEBUG((EFI_D_ERROR, "Init Flash Error !\n"));
    576         return Status;
    577     }
    578     else
    579     {
    580         DEBUG((EFI_D_ERROR, "Init Flash OK!\n"));
    581     }
    582 
    583     Status = gBS->InstallProtocolInterface (
    584                             &ImageHandle,
    585                             &gUniNorFlashProtocolGuid,
    586                             EFI_NATIVE_INTERFACE,
    587                             &gUniNorFlash);
    588     if(EFI_SUCCESS != Status)
    589     {
    590         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Install Protocol Interface %r!\n", __FUNCTION__,__LINE__,Status));
    591     }
    592 
    593     return Status;
    594 }
    595