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