1 /** @file 2 3 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials are licensed and made available under 6 the terms and conditions of the BSD License that accompanies this distribution. 7 The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php. 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 14 15 **/ 16 17 #include <PiDxe.h> 18 19 #include <Library/FlashDeviceLib.h> 20 #include <Library/DebugLib.h> 21 #include <Library/BaseLib.h> 22 #include <Library/BaseMemoryLib.h> 23 #include <Guid/EventGroup.h> 24 #include <Library/SpiFlash.H> 25 26 #define FLASH_SIZE 0x400000 27 28 #define FLASH_DEVICE_BASE_ADDRESS (0xFFFFFFFF-FLASH_SIZE+1) 29 UINTN FlashDeviceBase = FLASH_DEVICE_BASE_ADDRESS; 30 31 EFI_SPI_PROTOCOL *mSpiProtocol = NULL; 32 33 EFI_STATUS 34 SpiFlashErase ( 35 UINT8 *BaseAddress, 36 UINTN NumBytes 37 ) 38 { 39 EFI_STATUS Status = EFI_SUCCESS; 40 UINT32 SectorSize; 41 UINT32 SpiAddress; 42 43 SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase; 44 SectorSize = SECTOR_SIZE_4KB; 45 while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) { 46 Status = mSpiProtocol->Execute ( 47 mSpiProtocol, 48 SPI_SERASE, 49 SPI_WREN, 50 FALSE, 51 TRUE, 52 FALSE, 53 (UINT32) SpiAddress, 54 0, 55 NULL, 56 EnumSpiRegionBios 57 ); 58 if (EFI_ERROR (Status)) { 59 break; 60 } 61 SpiAddress += SectorSize; 62 NumBytes -= SectorSize; 63 } 64 65 return Status; 66 } 67 68 69 EFI_STATUS 70 SpiFlashBlockErase ( 71 UINT8 *BaseAddress, 72 UINTN NumBytes 73 ) 74 { 75 EFI_STATUS Status = EFI_SUCCESS; 76 UINT32 SectorSize; 77 UINT32 SpiAddress; 78 79 SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase; 80 SectorSize = SECTOR_SIZE_64KB; 81 while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) { 82 Status = mSpiProtocol->Execute ( 83 mSpiProtocol, 84 SPI_BERASE, 85 SPI_WREN, 86 FALSE, 87 TRUE, 88 FALSE, 89 (UINT32) SpiAddress, 90 0, 91 NULL, 92 EnumSpiRegionBios 93 ); 94 if (EFI_ERROR (Status)) { 95 break; 96 } 97 SpiAddress += SectorSize; 98 NumBytes -= SectorSize; 99 } 100 101 return Status; 102 } 103 104 105 static 106 EFI_STATUS 107 SpiFlashWrite ( 108 UINT8 *DstBufferPtr, 109 UINT8 *Byte, 110 IN UINTN Length 111 ) 112 { 113 EFI_STATUS Status; 114 UINT32 NumBytes = (UINT32)Length; 115 UINT8* pBuf8 = Byte; 116 UINT32 SpiAddress; 117 118 SpiAddress = (UINT32)(UINTN)(DstBufferPtr) - (UINT32)FlashDeviceBase; 119 Status = mSpiProtocol->Execute ( 120 mSpiProtocol, 121 SPI_PROG, 122 SPI_WREN, 123 TRUE, 124 TRUE, 125 TRUE, 126 (UINT32)SpiAddress, 127 NumBytes, 128 pBuf8, 129 EnumSpiRegionBios 130 ); 131 return Status; 132 } 133 134 /** 135 Read the Serial Flash Status Registers. 136 137 @param SpiStatus Pointer to a caller-allocated UINT8. On successful return, it contains the 138 status data read from the Serial Flash Status Register. 139 140 141 @retval EFI_SUCCESS Operation success, status is returned in SpiStatus. 142 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and the operation failed. 143 144 **/ 145 EFI_STATUS 146 ReadStatusRegister ( 147 UINT8 *SpiStatus 148 ) 149 { 150 EFI_STATUS Status; 151 152 Status = mSpiProtocol->Execute ( 153 mSpiProtocol, 154 SPI_RDSR, 155 SPI_WREN, 156 TRUE, 157 FALSE, 158 FALSE, 159 0, 160 1, 161 SpiStatus, 162 EnumSpiRegionBios 163 ); 164 return Status; 165 } 166 167 EFI_STATUS 168 SpiFlashLock ( 169 IN UINT8 *BaseAddress, 170 IN UINTN NumBytes, 171 IN BOOLEAN Lock 172 ) 173 { 174 EFI_STATUS Status; 175 UINT8 SpiData; 176 UINT8 SpiStatus; 177 178 if (Lock) { 179 SpiData = SF_SR_WPE; 180 } else { 181 SpiData = 0; 182 } 183 184 // 185 // Always disable block protection to workaround tool issue. 186 // Feature may be re-enabled in a future bios. 187 // 188 SpiData = 0; 189 Status = mSpiProtocol->Execute ( 190 mSpiProtocol, 191 SPI_WRSR, 192 SPI_EWSR, 193 TRUE, 194 TRUE, 195 TRUE, 196 0, 197 1, 198 &SpiData, 199 EnumSpiRegionBios 200 ); 201 if (EFI_ERROR (Status)) { 202 return Status; 203 } 204 205 Status = ReadStatusRegister (&SpiStatus); 206 if (EFI_ERROR (Status)) { 207 return Status; 208 } 209 210 if ((SpiStatus & SpiData) != SpiData) { 211 Status = EFI_DEVICE_ERROR; 212 } 213 214 return Status; 215 } 216 217 218 /** 219 Read NumBytes bytes of data from the address specified by 220 PAddress into Buffer. 221 222 @param[in] PAddress The starting physical address of the read. 223 @param[in,out] NumBytes On input, the number of bytes to read. On output, the number 224 of bytes actually read. 225 @param[out] Buffer The destination data buffer for the read. 226 227 @retval EFI_SUCCESS. Opertion is successful. 228 @retval EFI_DEVICE_ERROR If there is any device errors. 229 230 **/ 231 EFI_STATUS 232 EFIAPI 233 LibFvbFlashDeviceRead ( 234 IN UINTN PAddress, 235 IN OUT UINTN *NumBytes, 236 OUT UINT8 *Buffer 237 ) 238 { 239 CopyMem(Buffer, (VOID*)PAddress, *NumBytes); 240 return EFI_SUCCESS; 241 } 242 243 244 /** 245 Write NumBytes bytes of data from Buffer to the address specified by 246 PAddresss. 247 248 @param[in] PAddress The starting physical address of the write. 249 @param[in,out] NumBytes On input, the number of bytes to write. On output, 250 the actual number of bytes written. 251 @param[in] Buffer The source data buffer for the write. 252 253 @retval EFI_SUCCESS. Opertion is successful. 254 @retval EFI_DEVICE_ERROR If there is any device errors. 255 256 **/ 257 EFI_STATUS 258 EFIAPI 259 LibFvbFlashDeviceWrite ( 260 IN UINTN PAddress, 261 IN OUT UINTN *NumBytes, 262 IN UINT8 *Buffer 263 ) 264 { 265 EFI_STATUS Status; 266 Status = SpiFlashWrite((UINT8 *)PAddress, Buffer, *NumBytes); 267 return Status; 268 } 269 270 271 /** 272 Erase the block staring at PAddress. 273 274 @param[in] PAddress The starting physical address of the block to be erased. 275 This library assume that caller garantee that the PAddress 276 is at the starting address of this block. 277 @param[in] LbaLength The length of the logical block to be erased. 278 279 @retval EFI_SUCCESS. Opertion is successful. 280 @retval EFI_DEVICE_ERROR If there is any device errors. 281 282 **/ 283 EFI_STATUS 284 EFIAPI 285 LibFvbFlashDeviceBlockErase ( 286 IN UINTN PAddress, 287 IN UINTN LbaLength 288 ) 289 { 290 EFI_STATUS Status; 291 Status = SpiFlashBlockErase((UINT8 *)PAddress, LbaLength); 292 293 return Status; 294 } 295 296 297 /** 298 Lock or unlock the block staring at PAddress. 299 300 @param[in] PAddress The starting physical address of region to be (un)locked. 301 @param[in] LbaLength The length of the logical block to be erased. 302 @param[in] Lock TRUE to lock. FALSE to unlock. 303 304 @retval EFI_SUCCESS. Opertion is successful. 305 @retval EFI_DEVICE_ERROR If there is any device errors. 306 307 **/ 308 EFI_STATUS 309 EFIAPI 310 LibFvbFlashDeviceBlockLock ( 311 IN UINTN PAddress, 312 IN UINTN LbaLength, 313 IN BOOLEAN Lock 314 ) 315 { 316 EFI_STATUS Status; 317 318 Status = SpiFlashLock((UINT8*)PAddress, LbaLength, Lock); 319 return Status; 320 } 321 322