Home | History | Annotate | Download | only in Devices
      1 /*******************************************************************************
      2 Copyright (C) 2016 Marvell International Ltd.
      3 
      4 Marvell BSD License Option
      5 
      6 If you received this File from Marvell, you may opt to use, redistribute and/or
      7 modify this File under the following licensing terms.
      8 Redistribution and use in source and binary forms, with or without modification,
      9 are permitted provided that the following conditions are met:
     10 
     11 * Redistributions of source code must retain the above copyright notice,
     12   this list of conditions and the following disclaimer.
     13 
     14 * Redistributions in binary form must reproduce the above copyright
     15   notice, this list of conditions and the following disclaimer in the
     16   documentation and/or other materials provided with the distribution.
     17 
     18 * Neither the name of Marvell nor the names of its contributors may be
     19   used to endorse or promote products derived from this software without
     20   specific prior written permission.
     21 
     22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32 
     33 *******************************************************************************/
     34 #include "MvSpiFlash.h"
     35 
     36 MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
     37 SPI_FLASH_INSTANCE  *mSpiFlashInstance;
     38 
     39 STATIC
     40 VOID
     41 SpiFlashFormatAddress (
     42   IN      UINT32  Address,
     43   IN      UINT8   AddrSize,
     44   IN OUT  UINT8   *Cmd
     45   )
     46 {
     47   if (AddrSize == 4) {
     48       Cmd[1] = Address >> 24;
     49       Cmd[2] = Address >> 16;
     50       Cmd[3] = Address >> 8;
     51       Cmd[4] = Address;
     52   } else {
     53       Cmd[1] = Address >> 16;
     54       Cmd[2] = Address >> 8;
     55       Cmd[3] = Address;
     56   }
     57 }
     58 
     59 STATIC
     60 EFI_STATUS
     61 MvSpiFlashReadCmd (
     62   IN  SPI_DEVICE *Slave,
     63   IN  UINT8 *Cmd,
     64   IN  UINTN CmdSize,
     65   OUT UINT8 *DataIn,
     66   IN  UINTN DataSize
     67   )
     68 {
     69   EFI_STATUS Status;
     70 
     71   // Send command and gather response
     72   Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd,
     73     CmdSize, NULL, DataIn, DataSize);
     74 
     75   return Status;
     76 }
     77 
     78 STATIC
     79 EFI_STATUS
     80 MvSpiFlashWriteEnableCmd (
     81   IN  SPI_DEVICE   *Slave
     82   )
     83 {
     84   EFI_STATUS Status;
     85   UINT8 CmdEn = CMD_WRITE_ENABLE;
     86 
     87   // Send write_enable command
     88   Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1,
     89     &CmdEn, NULL, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
     90 
     91   return Status;
     92 }
     93 
     94 STATIC
     95 EFI_STATUS
     96 MvSpiFlashWriteCommon (
     97   IN SPI_DEVICE *Slave,
     98   IN UINT8 *Cmd,
     99   IN UINT32 Length,
    100   IN UINT8* Buffer,
    101   IN UINT32 BufferLength
    102   )
    103 {
    104   UINT8 CmdStatus = CMD_READ_STATUS;
    105   UINT8 State;
    106   UINT32 Counter = 0xFFFFF;
    107   UINT8 poll_bit = STATUS_REG_POLL_WIP;
    108   UINT8 check_status = 0x0;
    109 
    110   CmdStatus = (UINT8)PcdGet32 (PcdSpiFlashPollCmd);
    111   if (CmdStatus == CMD_FLAG_STATUS) {
    112     poll_bit = STATUS_REG_POLL_PEC;
    113     check_status = poll_bit;
    114   }
    115 
    116   // Send command
    117   MvSpiFlashWriteEnableCmd (Slave);
    118 
    119   // Write data
    120   SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd, Length,
    121     Buffer, NULL, BufferLength);
    122 
    123   // Poll status register
    124   SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &CmdStatus,
    125     NULL, SPI_TRANSFER_BEGIN);
    126   do {
    127     SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, NULL, &State,
    128       0);
    129     Counter--;
    130     if ((State & poll_bit) == check_status)
    131       break;
    132   } while (Counter > 0);
    133   if (Counter == 0) {
    134     DEBUG((DEBUG_ERROR, "SpiFlash: Timeout while writing to spi flash\n"));
    135     return EFI_DEVICE_ERROR;
    136   }
    137 
    138   // Deactivate CS
    139   SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 0, NULL, NULL, SPI_TRANSFER_END);
    140 
    141   return EFI_SUCCESS;
    142 }
    143 
    144 STATIC
    145 VOID
    146 SpiFlashCmdBankaddrWrite (
    147   IN SPI_DEVICE *Slave,
    148   IN UINT8 BankSel
    149   )
    150 {
    151   UINT8 Cmd = CMD_BANK_WRITE;
    152 
    153   MvSpiFlashWriteCommon (Slave, &Cmd, 1, &BankSel, 1);
    154 }
    155 
    156 STATIC
    157 UINT8
    158 SpiFlashBank (
    159   IN SPI_DEVICE *Slave,
    160   IN UINT32 Offset
    161   )
    162 {
    163   UINT8 BankSel;
    164 
    165   BankSel = Offset / SPI_FLASH_16MB_BOUN;
    166 
    167   SpiFlashCmdBankaddrWrite (Slave, BankSel);
    168 
    169   return BankSel;
    170 }
    171 
    172 EFI_STATUS
    173 MvSpiFlashErase (
    174   IN SPI_DEVICE *Slave,
    175   IN UINTN Offset,
    176   IN UINTN Length
    177   )
    178 {
    179   EFI_STATUS Status;
    180   UINT32 AddrSize, EraseAddr;
    181   UINTN EraseSize;
    182   UINT8 Cmd[5];
    183 
    184   AddrSize  = PcdGet32 (PcdSpiFlashAddressCycles);
    185   EraseSize = PcdGet64 (PcdSpiFlashEraseSize);
    186 
    187   // Check input parameters
    188   if (Offset % EraseSize || Length % EraseSize) {
    189     DEBUG((DEBUG_ERROR, "SpiFlash: Either erase offset or length "
    190       "is not multiple of erase size\n"));
    191     return EFI_DEVICE_ERROR;
    192   }
    193 
    194   Cmd[0] = CMD_ERASE_64K;
    195   while (Length) {
    196     EraseAddr = Offset;
    197 
    198     SpiFlashBank (Slave, EraseAddr);
    199 
    200     SpiFlashFormatAddress (EraseAddr, AddrSize, Cmd);
    201 
    202     // Programm proper erase address
    203     Status = MvSpiFlashWriteCommon (Slave, Cmd, AddrSize + 1, NULL, 0);
    204       if (EFI_ERROR (Status)) {
    205         DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming target address\n"));
    206         return Status;
    207       }
    208 
    209     Offset += EraseSize;
    210     Length -= EraseSize;
    211   }
    212   return EFI_SUCCESS;
    213 }
    214 
    215 EFI_STATUS
    216 MvSpiFlashRead (
    217   IN SPI_DEVICE   *Slave,
    218   IN UINT32       Offset,
    219   IN UINTN        Length,
    220   IN VOID         *Buf
    221   )
    222 {
    223   EFI_STATUS Status = EFI_SUCCESS;
    224   UINT8 Cmd[6];
    225   UINT32 AddrSize, ReadAddr, ReadLength, RemainLength;
    226   UINTN BankSel = 0;
    227 
    228   AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
    229 
    230   Cmd[0] = CMD_READ_ARRAY_FAST;
    231 
    232   // Sign end of address with 0 byte
    233   Cmd[5] = 0;
    234 
    235   while (Length) {
    236     ReadAddr = Offset;
    237 
    238     BankSel = SpiFlashBank (Slave, ReadAddr);
    239 
    240     RemainLength = (SPI_FLASH_16MB_BOUN * (BankSel + 1)) - Offset;
    241     if (Length < RemainLength) {
    242       ReadLength = Length;
    243     } else {
    244       ReadLength = RemainLength;
    245     }
    246     SpiFlashFormatAddress (ReadAddr, AddrSize, Cmd);
    247     // Program proper read address and read data
    248     Status = MvSpiFlashReadCmd (Slave, Cmd, AddrSize + 2, Buf, Length);
    249 
    250     Offset += ReadLength;
    251     Length -= ReadLength;
    252     Buf += ReadLength;
    253   }
    254 
    255   return Status;
    256 }
    257 
    258 EFI_STATUS
    259 MvSpiFlashWrite (
    260   IN SPI_DEVICE *Slave,
    261   IN UINT32     Offset,
    262   IN UINTN      Length,
    263   IN VOID       *Buf
    264   )
    265 {
    266   EFI_STATUS Status;
    267   UINTN ByteAddr, ChunkLength, ActualIndex, PageSize;
    268   UINT32 WriteAddr;
    269   UINT8 Cmd[5], AddrSize;
    270 
    271   AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
    272   PageSize = PcdGet32 (PcdSpiFlashPageSize);
    273 
    274   Cmd[0] = CMD_PAGE_PROGRAM;
    275 
    276   for (ActualIndex = 0; ActualIndex < Length; ActualIndex += ChunkLength) {
    277     WriteAddr = Offset;
    278 
    279     SpiFlashBank (Slave, WriteAddr);
    280 
    281     ByteAddr = Offset % PageSize;
    282 
    283     ChunkLength = MIN(Length - ActualIndex, (UINT64) (PageSize - ByteAddr));
    284 
    285     SpiFlashFormatAddress (WriteAddr, AddrSize, Cmd);
    286 
    287     // Program proper write address and write data
    288     Status = MvSpiFlashWriteCommon (Slave, Cmd, AddrSize + 1, Buf + ActualIndex,
    289       ChunkLength);
    290     if (EFI_ERROR (Status)) {
    291       DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming write address\n"));
    292       return Status;
    293     }
    294 
    295     Offset += ChunkLength;
    296   }
    297   return EFI_SUCCESS;
    298 }
    299 
    300 STATIC
    301 EFI_STATUS
    302 MvSpiFlashUpdateBlock (
    303   IN SPI_DEVICE *Slave,
    304   IN UINT32 Offset,
    305   IN UINTN ToUpdate,
    306   IN UINT8 *Buf,
    307   IN UINT8 *TmpBuf,
    308   IN UINTN EraseSize
    309   )
    310 {
    311   EFI_STATUS Status;
    312 
    313   // Read backup
    314   Status = MvSpiFlashRead (Slave, Offset, EraseSize, TmpBuf);
    315     if (EFI_ERROR (Status)) {
    316       DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while reading old data\n"));
    317       return Status;
    318     }
    319 
    320   // Erase entire sector
    321   Status = MvSpiFlashErase (Slave, Offset, EraseSize);
    322   if (EFI_ERROR (Status)) {
    323       DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while erasing block\n"));
    324       return Status;
    325     }
    326 
    327   // Write new data
    328   MvSpiFlashWrite (Slave, Offset, ToUpdate, Buf);
    329   if (EFI_ERROR (Status)) {
    330       DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing new data\n"));
    331       return Status;
    332     }
    333 
    334   // Write backup
    335   if (ToUpdate != EraseSize) {
    336     Status = MvSpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpdate,
    337       &TmpBuf[ToUpdate]);
    338     if (EFI_ERROR (Status)) {
    339       DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing backup\n"));
    340       return Status;
    341     }
    342   }
    343 
    344   return EFI_SUCCESS;
    345 }
    346 
    347 EFI_STATUS
    348 MvSpiFlashUpdate (
    349   IN SPI_DEVICE *Slave,
    350   IN UINT32 Offset,
    351   IN UINTN ByteCount,
    352   IN UINT8 *Buf
    353   )
    354 {
    355   EFI_STATUS Status;
    356   UINT64 EraseSize, ToUpdate, Scale = 1;
    357   UINT8 *TmpBuf, *End;
    358 
    359   EraseSize = PcdGet64 (PcdSpiFlashEraseSize);
    360 
    361   End = Buf + ByteCount;
    362 
    363   TmpBuf = (UINT8 *)AllocateZeroPool (EraseSize);
    364   if (TmpBuf == NULL) {
    365     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
    366     return EFI_OUT_OF_RESOURCES;
    367   }
    368 
    369   if (End - Buf >= 200)
    370     Scale = (End - Buf) / 100;
    371 
    372   for (; Buf < End; Buf += ToUpdate, Offset += ToUpdate) {
    373     ToUpdate = MIN((UINT64)(End - Buf), EraseSize);
    374     Print (L"   \rUpdating, %d%%", 100 - (End - Buf) / Scale);
    375     Status = MvSpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buf, TmpBuf, EraseSize);
    376 
    377     if (EFI_ERROR (Status)) {
    378       DEBUG((DEBUG_ERROR, "SpiFlash: Error while updating\n"));
    379       return Status;
    380     }
    381   }
    382 
    383   Print(L"\n");
    384   FreePool (TmpBuf);
    385 
    386   return EFI_SUCCESS;
    387 }
    388 
    389 EFI_STATUS
    390 EFIAPI
    391 MvSpiFlashReadId (
    392   IN     SPI_DEVICE *SpiDev,
    393   IN     UINT32     DataByteCount,
    394   IN OUT UINT8      *Buffer
    395   )
    396 {
    397   EFI_STATUS Status;
    398   UINT8 *DataOut;
    399 
    400   DataOut = (UINT8 *) AllocateZeroPool (DataByteCount);
    401   if (DataOut == NULL) {
    402     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
    403     return EFI_OUT_OF_RESOURCES;
    404   }
    405   Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, SpiDev,
    406     DataByteCount, Buffer, DataOut, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
    407   if (EFI_ERROR(Status)) {
    408     FreePool (DataOut);
    409     DEBUG((DEBUG_ERROR, "SpiFlash: Spi transfer error\n"));
    410     return Status;
    411   }
    412 
    413   // Bytes 1,2 and 3 contain SPI flash ID
    414   Buffer[0] = DataOut[1];
    415   Buffer[1] = DataOut[2];
    416   Buffer[2] = DataOut[3];
    417 
    418   FreePool (DataOut);
    419 
    420   return EFI_SUCCESS;
    421 }
    422 
    423 EFI_STATUS
    424 EFIAPI
    425 MvSpiFlashInit (
    426   IN MARVELL_SPI_FLASH_PROTOCOL *This,
    427   IN SPI_DEVICE *Slave
    428   )
    429 {
    430   EFI_STATUS Status;
    431   UINT8 Cmd, StatusRegister;
    432   UINT32 AddrSize;
    433 
    434   AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
    435 
    436   if (AddrSize == 4) {
    437     // Set 4 byte address mode
    438     Status = MvSpiFlashWriteEnableCmd (Slave);
    439     if (EFI_ERROR (Status)) {
    440       DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n"));
    441       return Status;
    442     }
    443 
    444     Cmd = CMD_4B_ADDR_ENABLE;
    445     Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &Cmd, NULL,
    446       SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
    447     if (EFI_ERROR (Status)) {
    448       DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting 4B address\n"));
    449       return Status;
    450     }
    451   }
    452 
    453   // Write flash status register
    454   Status = MvSpiFlashWriteEnableCmd (Slave);
    455   if (EFI_ERROR (Status)) {
    456     DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n"));
    457     return Status;
    458   }
    459 
    460   Cmd = CMD_WRITE_STATUS_REG;
    461   StatusRegister = 0x0;
    462   Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, &Cmd, 1,
    463     &StatusRegister, NULL, 1);
    464   if (EFI_ERROR (Status)) {
    465     DEBUG((DEBUG_ERROR, "SpiFlash: Error with spi transfer\n"));
    466     return Status;
    467   }
    468 
    469   return EFI_SUCCESS;
    470 }
    471 
    472 EFI_STATUS
    473 MvSpiFlashInitProtocol (
    474   IN MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol
    475   )
    476 {
    477 
    478   SpiFlashProtocol->Init = MvSpiFlashInit;
    479   SpiFlashProtocol->ReadId = MvSpiFlashReadId;
    480   SpiFlashProtocol->Read = MvSpiFlashRead;
    481   SpiFlashProtocol->Write = MvSpiFlashWrite;
    482   SpiFlashProtocol->Erase = MvSpiFlashErase;
    483   SpiFlashProtocol->Update = MvSpiFlashUpdate;
    484 
    485   return EFI_SUCCESS;
    486 }
    487 
    488 EFI_STATUS
    489 EFIAPI
    490 MvSpiFlashEntryPoint (
    491   IN EFI_HANDLE       ImageHandle,
    492   IN EFI_SYSTEM_TABLE *SystemTable
    493   )
    494 {
    495   EFI_STATUS  Status;
    496 
    497   Status = gBS->LocateProtocol (
    498     &gMarvellSpiMasterProtocolGuid,
    499     NULL,
    500     (VOID **)&SpiMasterProtocol
    501   );
    502   if (EFI_ERROR (Status)) {
    503     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot locate SPI Master protocol\n"));
    504     return EFI_DEVICE_ERROR;
    505   }
    506 
    507   mSpiFlashInstance = AllocateZeroPool (sizeof (SPI_FLASH_INSTANCE));
    508 
    509   if (mSpiFlashInstance == NULL) {
    510     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
    511     return EFI_OUT_OF_RESOURCES;
    512   }
    513 
    514   MvSpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol);
    515 
    516   mSpiFlashInstance->Signature = SPI_FLASH_SIGNATURE;
    517 
    518   Status = gBS->InstallMultipleProtocolInterfaces (
    519                   &(mSpiFlashInstance->Handle),
    520                   &gMarvellSpiFlashProtocolGuid,
    521                   &(mSpiFlashInstance->SpiFlashProtocol),
    522                   NULL
    523                   );
    524   if (EFI_ERROR (Status)) {
    525     FreePool (mSpiFlashInstance);
    526     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot install SPI flash protocol\n"));
    527     return EFI_DEVICE_ERROR;
    528   }
    529 
    530   return EFI_SUCCESS;
    531 }
    532