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