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