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
SpiFlashErase(UINT8 * BaseAddress,UINTN NumBytes)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
SpiFlashBlockErase(UINT8 * BaseAddress,UINTN NumBytes)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
SpiFlashWrite(UINT8 * DstBufferPtr,UINT8 * Byte,IN UINTN Length)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
ReadStatusRegister(UINT8 * SpiStatus)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
SpiFlashLock(IN UINT8 * BaseAddress,IN UINTN NumBytes,IN BOOLEAN Lock)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
LibFvbFlashDeviceRead(IN UINTN PAddress,IN OUT UINTN * NumBytes,OUT UINT8 * Buffer)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
LibFvbFlashDeviceWrite(IN UINTN PAddress,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)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
LibFvbFlashDeviceBlockErase(IN UINTN PAddress,IN UINTN LbaLength)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
LibFvbFlashDeviceBlockLock(IN UINTN PAddress,IN UINTN LbaLength,IN BOOLEAN Lock)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