1 /** @file
2
3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
4
5
6 This program and the accompanying materials are licensed and made available under
7
8 the terms and conditions of the BSD License that accompanies this distribution.
9
10 The full text of the license may be found at
11
12 http://opensource.org/licenses/bsd-license.php.
13
14
15
16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19
20
21
22
23
24 **/
25
26 #include <PiDxe.h>
27
28 #include <Library/FlashDeviceLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/BaseLib.h>
31 #include <Library/UefiBootServicesTableLib.h>
32 #include <Library/UefiRuntimeServicesTableLib.h>
33 #include <Library/BaseMemoryLib.h>
34 #include <Library/UefiRuntimeLib.h>
SpiFlashErase(UINT8 * BaseAddress,UINTN NumBytes)35 #include <Protocol/SmmBase2.h>
36 #include <Guid/EventGroup.h>
37 #include "SpiChipDefinitions.h"
38
39 UINTN FlashDeviceBase = FLASH_DEVICE_BASE_ADDRESS;
40
41 EFI_SPI_PROTOCOL *mSpiProtocol = NULL;
42
43 EFI_STATUS
44 SpiFlashErase (
45 UINT8 *BaseAddress,
46 UINTN NumBytes
47 )
48 {
49 EFI_STATUS Status = EFI_SUCCESS;
50 UINT32 SectorSize;
51 UINT32 SpiAddress;
52
53 SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase;
54 SectorSize = SECTOR_SIZE_4KB;
55 while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) {
56 Status = mSpiProtocol->Execute (
57 mSpiProtocol,
58 SPI_SERASE,
59 SPI_WREN,
60 FALSE,
61 TRUE,
62 FALSE,
63 (UINT32) SpiAddress,
64 0,
65 NULL,
66 EnumSpiRegionBios
67 );
68 if (EFI_ERROR (Status)) {
69 break;
70 }
SpiFlashBlockErase(UINT8 * BaseAddress,UINTN NumBytes)71 SpiAddress += SectorSize;
72 NumBytes -= SectorSize;
73 }
74
75 return Status;
76 }
77
78
79 EFI_STATUS
80 SpiFlashBlockErase (
81 UINT8 *BaseAddress,
82 UINTN NumBytes
83 )
84 {
85 EFI_STATUS Status = EFI_SUCCESS;
86 UINT32 SectorSize;
87 UINT32 SpiAddress;
88
89 SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase;
90 SectorSize = SECTOR_SIZE_64KB;
91 while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) {
92 Status = mSpiProtocol->Execute (
93 mSpiProtocol,
94 SPI_BERASE,
95 SPI_WREN,
96 FALSE,
97 TRUE,
98 FALSE,
99 (UINT32) SpiAddress,
100 0,
101 NULL,
102 EnumSpiRegionBios
103 );
104 if (EFI_ERROR (Status)) {
105 break;
106 }
107 SpiAddress += SectorSize;
SpiFlashWrite(UINT8 * DstBufferPtr,UINT8 * Byte,IN UINTN Length)108 NumBytes -= SectorSize;
109 }
110
111 return Status;
112 }
113
114
115 static
116 EFI_STATUS
117 SpiFlashWrite (
118 UINT8 *DstBufferPtr,
119 UINT8 *Byte,
120 IN UINTN Length
121 )
122 {
123 EFI_STATUS Status;
124 UINT32 NumBytes = (UINT32)Length;
125 UINT8* pBuf8 = Byte;
126 UINT32 SpiAddress;
127
128 SpiAddress = (UINT32)(UINTN)(DstBufferPtr) - (UINT32)FlashDeviceBase;
129 Status = mSpiProtocol->Execute (
130 mSpiProtocol,
131 SPI_PROG,
132 SPI_WREN,
133 TRUE,
134 TRUE,
135 TRUE,
136 (UINT32)SpiAddress,
137 NumBytes,
138 pBuf8,
139 EnumSpiRegionBios
140 );
141 return Status;
142 }
143
144 /**
145 Read the Serial Flash Status Registers.
146
ReadStatusRegister(UINT8 * SpiStatus)147 @param SpiStatus Pointer to a caller-allocated UINT8. On successful return, it contains the
148 status data read from the Serial Flash Status Register.
149
150
151 @retval EFI_SUCCESS Operation success, status is returned in SpiStatus.
152 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and the operation failed.
153
154 **/
155 EFI_STATUS
156 ReadStatusRegister (
157 UINT8 *SpiStatus
158 )
159 {
160 EFI_STATUS Status;
161
162 Status = mSpiProtocol->Execute (
163 mSpiProtocol,
164 SPI_RDSR,
165 SPI_WREN,
166 TRUE,
167 FALSE,
168 FALSE,
169 0,
170 1,
171 SpiStatus,
172 EnumSpiRegionBios
173 );
174 return Status;
175 }
176
177 EFI_STATUS
178 SpiFlashLock (
179 IN UINT8 *BaseAddress,
180 IN UINTN NumBytes,
181 IN BOOLEAN Lock
182 )
183 {
184 EFI_STATUS Status;
185 UINT8 SpiData;
186 UINT8 SpiStatus;
187
188 if (Lock) {
189 SpiData = SF_SR_WPE;
190 } else {
191 SpiData = 0;
192 }
193
194 //
195 // Always disable block protection to workaround tool issue.
196 // Feature may be re-enabled in a future bios.
197 //
198 SpiData = 0;
199 Status = mSpiProtocol->Execute (
200 mSpiProtocol,
201 SPI_WRSR,
202 SPI_EWSR,
203 TRUE,
204 TRUE,
205 TRUE,
206 0,
207 1,
208 &SpiData,
209 EnumSpiRegionBios
210 );
211 if (EFI_ERROR (Status)) {
212 return Status;
213 }
214
215 Status = ReadStatusRegister (&SpiStatus);
216 if (EFI_ERROR (Status)) {
217 return Status;
218 }
219
220 if ((SpiStatus & SpiData) != SpiData) {
221 Status = EFI_DEVICE_ERROR;
222 }
223
224 return Status;
225 }
226
227
228 /**
229 Read NumBytes bytes of data from the address specified by
230 PAddress into Buffer.
231
232 @param[in] PAddress The starting physical address of the read.
233 @param[in,out] NumBytes On input, the number of bytes to read. On output, the number
LibFvbFlashDeviceRead(IN UINTN PAddress,IN OUT UINTN * NumBytes,OUT UINT8 * Buffer)234 of bytes actually read.
235 @param[out] Buffer The destination data buffer for the read.
236
237 @retval EFI_SUCCESS. Opertion is successful.
238 @retval EFI_DEVICE_ERROR If there is any device errors.
239
240 **/
241 EFI_STATUS
242 EFIAPI
243 LibFvbFlashDeviceRead (
244 IN UINTN PAddress,
245 IN OUT UINTN *NumBytes,
246 OUT UINT8 *Buffer
247 )
248 {
249 CopyMem(Buffer, (VOID*)PAddress, *NumBytes);
250 return EFI_SUCCESS;
251 }
252
253
254 /**
255 Write NumBytes bytes of data from Buffer to the address specified by
256 PAddresss.
257
258 @param[in] PAddress The starting physical address of the write.
259 @param[in,out] NumBytes On input, the number of bytes to write. On output,
LibFvbFlashDeviceWrite(IN UINTN PAddress,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)260 the actual number of bytes written.
261 @param[in] Buffer The source data buffer for the write.
262
263 @retval EFI_SUCCESS. Opertion is successful.
264 @retval EFI_DEVICE_ERROR If there is any device errors.
265
266 **/
267 EFI_STATUS
268 EFIAPI
269 LibFvbFlashDeviceWrite (
270 IN UINTN PAddress,
271 IN OUT UINTN *NumBytes,
272 IN UINT8 *Buffer
273 )
274 {
275 EFI_STATUS Status;
276 Status = SpiFlashWrite((UINT8 *)PAddress, Buffer, *NumBytes);
277 return Status;
278 }
279
280
281 /**
282 Erase the block staring at PAddress.
283
284 @param[in] PAddress The starting physical address of the block to be erased.
285 This library assume that caller garantee that the PAddress
LibFvbFlashDeviceBlockErase(IN UINTN PAddress,IN UINTN LbaLength)286 is at the starting address of this block.
287 @param[in] LbaLength The length of the logical block to be erased.
288
289 @retval EFI_SUCCESS. Opertion is successful.
290 @retval EFI_DEVICE_ERROR If there is any device errors.
291
292 **/
293 EFI_STATUS
294 EFIAPI
295 LibFvbFlashDeviceBlockErase (
296 IN UINTN PAddress,
297 IN UINTN LbaLength
298 )
299 {
300 EFI_STATUS Status;
301 Status = SpiFlashBlockErase((UINT8 *)PAddress, LbaLength);
302
303 return Status;
304 }
305
306
307 /**
308 Lock or unlock the block staring at PAddress.
309
310 @param[in] PAddress The starting physical address of region to be (un)locked.
LibFvbFlashDeviceBlockLock(IN UINTN PAddress,IN UINTN LbaLength,IN BOOLEAN Lock)311 @param[in] LbaLength The length of the logical block to be erased.
312 @param[in] Lock TRUE to lock. FALSE to unlock.
313
314 @retval EFI_SUCCESS. Opertion is successful.
315 @retval EFI_DEVICE_ERROR If there is any device errors.
316
317 **/
318 EFI_STATUS
319 EFIAPI
320 LibFvbFlashDeviceBlockLock (
321 IN UINTN PAddress,
322 IN UINTN LbaLength,
323 IN BOOLEAN Lock
324 )
325 {
326 EFI_STATUS Status;
327
328 Status = SpiFlashLock((UINT8*)PAddress, LbaLength, Lock);
329 return Status;
330 }
331
332 VOID
333 EFIAPI
334 LibFvbFlashDeviceVirtualAddressChangeNotifyEvent (
335 IN EFI_EVENT Event,
336 IN VOID *Context
337 )
338 {
339 gRT->ConvertPointer (0, (VOID **) &mSpiProtocol);
340 gRT->ConvertPointer (0, (VOID **) &FlashDeviceBase);
341 }
342
343
344 /**
345 The library constructuor.
346
347 The function does the necessary initialization work for this library
348 instance. Please put all initialization works in it.
349
350 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
LibFvbFlashDeviceSupportInit(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)351 @param[in] SystemTable A pointer to the EFI system table.
352
353 @retval EFI_SUCCESS The function always return EFI_SUCCESS for now.
354 It will ASSERT on error for debug version.
355 @retval EFI_ERROR Please reference LocateProtocol for error code details.
356
357 **/
358 EFI_STATUS
359 EFIAPI
360 LibFvbFlashDeviceSupportInit (
361 IN EFI_HANDLE ImageHandle,
362 IN EFI_SYSTEM_TABLE *SystemTable
363 )
364 {
365 EFI_STATUS Status;
366 EFI_EVENT Event;
367 UINT8 SfId[3];
368 UINT8 FlashIndex;
369 UINT8 SpiReadError;
370 UINT8 SpiNotMatchError;
371 EFI_SMM_BASE2_PROTOCOL *SmmBase;
372 BOOLEAN InSmm;
373
374 SpiReadError = 0x00;
375 SpiNotMatchError = 0x00;
376
377 InSmm = FALSE;
378 Status = gBS->LocateProtocol (
379 &gEfiSmmBase2ProtocolGuid,
380 NULL,
381 (void **)&SmmBase
382 );
383 if (!EFI_ERROR(Status)) {
384 Status = SmmBase->InSmm(SmmBase, &InSmm);
385 if (EFI_ERROR(Status)) {
386 InSmm = FALSE;
387 }
388 }
389
390 if (!InSmm) {
391 Status = gBS->LocateProtocol (
392 &gEfiSpiProtocolGuid,
393 NULL,
394 (VOID **)&mSpiProtocol
395 );
396 ASSERT_EFI_ERROR (Status);
397
398 Status = gBS->CreateEventEx (
399 EVT_NOTIFY_SIGNAL,
400 TPL_NOTIFY,
401 LibFvbFlashDeviceVirtualAddressChangeNotifyEvent,
402 NULL,
403 &gEfiEventVirtualAddressChangeGuid,
404 &Event
405 );
406 ASSERT_EFI_ERROR (Status);
407 } else {
408 Status = gBS->LocateProtocol (
409 &gEfiSmmSpiProtocolGuid,
410 NULL,
411 (VOID **)&mSpiProtocol
412 );
413 ASSERT_EFI_ERROR (Status);
414 }
415
416
417 for (FlashIndex = EnumSpiFlashW25Q64; FlashIndex < EnumSpiFlashMax; FlashIndex++) {
418 Status = mSpiProtocol->Init (mSpiProtocol, &(mInitTable[FlashIndex]));
419 if (!EFI_ERROR (Status)) {
420 //
421 // Read Vendor/Device IDs to check if the driver supports the Serial Flash device.
422 //
423 Status = mSpiProtocol->Execute (
424 mSpiProtocol,
425 SPI_READ_ID,
426 SPI_WREN,
427 TRUE,
428 FALSE,
429 FALSE,
430 0,
431 3,
432 SfId,
433 EnumSpiRegionAll
434 );
435 if (!EFI_ERROR (Status)) {
436 if ((SfId[0] == mInitTable[FlashIndex].VendorId) &&
437 (SfId[1] == mInitTable[FlashIndex].DeviceId0) &&
438 (SfId[2] == mInitTable[FlashIndex].DeviceId1)) {
439 //
440 // Found a matching SPI device, FlashIndex now contains flash device.
441 //
442 DEBUG ((EFI_D_ERROR, "OK - Found SPI Flash Type in SPI Flash Driver, Device Type ID 0 = 0x%02x!\n", mInitTable[FlashIndex].DeviceId0));
443 DEBUG ((EFI_D_ERROR, "Device Type ID 1 = 0x%02x!\n", mInitTable[FlashIndex].DeviceId1));
444
445 if (mInitTable[FlashIndex].BiosStartOffset == (UINTN) (-1)) {
446 DEBUG ((EFI_D_ERROR, "ERROR - The size of BIOS image is bigger than SPI Flash device!\n"));
447 CpuDeadLoop ();
448 }
449 break;
450 } else {
451 SpiNotMatchError++;
452 }
453 } else {
454 SpiReadError++;
455 }
456 }
457 }
458
459 DEBUG ((EFI_D_ERROR, "SPI flash chip VID = 0x%X, DID0 = 0x%X, DID1 = 0x%X\n", SfId[0], SfId[1], SfId[2]));
460
461 if (FlashIndex < EnumSpiFlashMax) {
462 return EFI_SUCCESS;
463 } else {
464 if (SpiReadError != 0) {
465 DEBUG ((EFI_D_ERROR, "ERROR - SPI Read ID execution failed! Error Count = %d\n", SpiReadError));
466 }
467 else {
468 if (SpiNotMatchError != 0) {
469 DEBUG ((EFI_D_ERROR, "ERROR - No supported SPI flash chip found! Error Count = %d\n", SpiNotMatchError));
470 DEBUG ((EFI_D_ERROR, "SPI flash chip VID = 0x%X, DID0 = 0x%X, DID1 = 0x%X\n", SfId[0], SfId[1], SfId[2]));
471 }
472 }
473 return EFI_UNSUPPORTED;
474 }
475 }
476
477