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