]> git.proxmox.com Git - mirror_edk2.git/blob - Vlv2TbltDevicePkg/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c
079c3ef2d68e975227bc472c03acc7c8b77cce2d
[mirror_edk2.git] / Vlv2TbltDevicePkg / Feature / Capsule / Library / PlatformFlashAccessLib / PlatformFlashAccessLib.c
1 /** @file
2 Platform Flash Access library.
3
4 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8 #include <Uefi.h>
9
10 #include <PiDxe.h>
11
12 #include <Library/BaseLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/PcdLib.h>
16 #include <Library/PlatformFlashAccessLib.h>
17 //#include <Library/FlashDeviceLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Protocol/Spi.h>
20 #include <Library/CacheMaintenanceLib.h>
21 #include "PchAccess.h"
22 #include <Library/IoLib.h>
23 #include <Library/UefiLib.h>
24 #include <Library/UefiBootServicesTableLib.h>
25 #include <Library/PrintLib.h>
26
27 //#define SECTOR_SIZE_64KB 0x10000 // Common 64kBytes sector size
28 //#define ALINGED_SIZE SECTOR_SIZE_64KB
29
30 #define BLOCK_SIZE 0x1000
31 #define ALINGED_SIZE BLOCK_SIZE
32
33 #define R_PCH_LPC_BIOS_CNTL 0xDC
34 #define B_PCH_LPC_BIOS_CNTL_SMM_BWP 0x20 ///< SMM BIOS write protect disable
35
36 //
37 // Prefix Opcode Index on the host SPI controller
38 //
39 typedef enum {
40 SPI_WREN, // Prefix Opcode 0: Write Enable
41 SPI_EWSR, // Prefix Opcode 1: Enable Write Status Register
42 } PREFIX_OPCODE_INDEX;
43 //
44 // Opcode Menu Index on the host SPI controller
45 //
46 typedef enum {
47 SPI_READ_ID, // Opcode 0: READ ID, Read cycle with address
48 SPI_READ, // Opcode 1: READ, Read cycle with address
49 SPI_RDSR, // Opcode 2: Read Status Register, No address
50 SPI_WRDI_SFDP, // Opcode 3: Write Disable or Discovery Parameters, No address
51 SPI_SERASE, // Opcode 4: Sector Erase (4KB), Write cycle with address
52 SPI_BERASE, // Opcode 5: Block Erase (32KB), Write cycle with address
53 SPI_PROG, // Opcode 6: Byte Program, Write cycle with address
54 SPI_WRSR, // Opcode 7: Write Status Register, No address
55 } SPI_OPCODE_INDEX;
56
57 STATIC EFI_PHYSICAL_ADDRESS mInternalFdAddress;
58
59 EFI_SPI_PROTOCOL *mSpiProtocol;
60
61 /**
62 Read NumBytes bytes of data from the address specified by
63 PAddress into Buffer.
64
65 @param[in] Address The starting physical address of the read.
66 @param[in,out] NumBytes On input, the number of bytes to read. On output, the number
67 of bytes actually read.
68 @param[out] Buffer The destination data buffer for the read.
69
70 @retval EFI_SUCCESS Opertion is successful.
71 @retval EFI_DEVICE_ERROR If there is any device errors.
72
73 **/
74 EFI_STATUS
75 EFIAPI
76 SpiFlashRead (
77 IN UINTN Address,
78 IN OUT UINT32 *NumBytes,
79 OUT UINT8 *Buffer
80 )
81 {
82 EFI_STATUS Status = EFI_SUCCESS;
83 UINTN Offset = 0;
84
85 ASSERT ((NumBytes != NULL) && (Buffer != NULL));
86
87
88 //if (Address >= (UINTN)PcdGet32 (PcdGbeRomBase) && Address < (UINTN)PcdGet32 (PcdPDRRomBase)) {
89 Offset = Address - (UINTN)PcdGet32 (PcdFlashChipBase);
90
91 Status = mSpiProtocol->Execute (
92 mSpiProtocol,
93 1, //SPI_READ,
94 0, //SPI_WREN,
95 TRUE,
96 TRUE,
97 FALSE,
98 Offset,
99 BLOCK_SIZE,
100 Buffer,
101 EnumSpiRegionAll
102 );
103 return Status;
104 }
105
106 /**
107 Write NumBytes bytes of data from Buffer to the address specified by
108 PAddresss.
109
110 @param[in] Address The starting physical address of the write.
111 @param[in,out] NumBytes On input, the number of bytes to write. On output,
112 the actual number of bytes written.
113 @param[in] Buffer The source data buffer for the write.
114
115 @retval EFI_SUCCESS Opertion is successful.
116 @retval EFI_DEVICE_ERROR If there is any device errors.
117
118 **/
119 EFI_STATUS
120 EFIAPI
121 SpiFlashWrite (
122 IN UINTN Address,
123 IN OUT UINT32 *NumBytes,
124 IN UINT8 *Buffer
125 )
126 {
127 EFI_STATUS Status;
128 UINTN Offset;
129 UINT32 Length;
130 UINT32 RemainingBytes;
131
132 ASSERT ((NumBytes != NULL) && (Buffer != NULL));
133 ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashChipBase));
134
135 Offset = Address - (UINTN)PcdGet32 (PcdFlashChipBase);
136
137 ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashChipSize));
138
139 Status = EFI_SUCCESS;
140 RemainingBytes = *NumBytes;
141
142 while (RemainingBytes > 0) {
143 if (RemainingBytes > SIZE_4KB) {
144 Length = SIZE_4KB;
145 } else {
146 Length = RemainingBytes;
147 }
148 Status = mSpiProtocol->Execute (
149 mSpiProtocol,
150 SPI_PROG,
151 SPI_WREN,
152 TRUE,
153 TRUE,
154 TRUE,
155 (UINT32) Offset,
156 Length,
157 Buffer,
158 EnumSpiRegionAll
159 );
160 if (EFI_ERROR (Status)) {
161 break;
162 }
163 RemainingBytes -= Length;
164 Offset += Length;
165 Buffer += Length;
166 }
167
168 //
169 // Actual number of bytes written
170 //
171 *NumBytes -= RemainingBytes;
172
173 return Status;
174 }
175
176
177 EFI_STATUS
178 InternalReadBlock (
179 IN EFI_PHYSICAL_ADDRESS BaseAddress,
180 OUT VOID *ReadBuffer
181 )
182 {
183 EFI_STATUS Status;
184 UINT32 BlockSize;
185
186 BlockSize = BLOCK_SIZE;
187
188 Status = SpiFlashRead ((UINTN) BaseAddress, &BlockSize, ReadBuffer);
189
190 return Status;
191 }
192
193 /**
194 Erase the block starting at Address.
195
196 @param[in] Address The starting physical address of the block to be erased.
197 This library assume that caller garantee that the PAddress
198 is at the starting address of this block.
199 @param[in] NumBytes On input, the number of bytes of the logical block to be erased.
200 On output, the actual number of bytes erased.
201
202 @retval EFI_SUCCESS. Opertion is successful.
203 @retval EFI_DEVICE_ERROR If there is any device errors.
204
205 **/
206 EFI_STATUS
207 EFIAPI
208 SpiFlashBlockErase (
209 IN UINTN Address,
210 IN UINTN *NumBytes
211 )
212 {
213 EFI_STATUS Status;
214 UINTN Offset;
215 UINTN RemainingBytes;
216
217 ASSERT (NumBytes != NULL);
218 ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashChipBase));
219
220 Offset = Address - (UINTN)PcdGet32 (PcdFlashChipBase);
221
222 ASSERT ((*NumBytes % SIZE_4KB) == 0);
223 ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashChipSize));
224
225 Status = EFI_SUCCESS;
226 RemainingBytes = *NumBytes;
227
228 //
229 // To adjust the Offset with Bios/Gbe
230 //
231 // if (Address >= (UINTN)PcdGet32 (PcdFlashChipBase)) {
232 // Offset = Address - (UINTN)PcdGet32 (PcdFlashChipBase);
233
234 while (RemainingBytes > 0) {
235 Status = mSpiProtocol->Execute (
236 mSpiProtocol,
237 SPI_SERASE,
238 SPI_WREN,
239 FALSE,
240 TRUE,
241 FALSE,
242 (UINT32) Offset,
243 0,
244 NULL,
245 EnumSpiRegionAll
246 );
247 if (EFI_ERROR (Status)) {
248 break;
249 }
250 RemainingBytes -= SIZE_4KB;
251 Offset += SIZE_4KB;
252 }
253 // }
254
255 //
256 // Actual number of bytes erased
257 //
258 *NumBytes -= RemainingBytes;
259
260 return Status;
261 }
262
263 /**
264
265 Routine Description:
266
267 Erase the whole block.
268
269 Arguments:
270
271 BaseAddress - Base address of the block to be erased.
272
273 Returns:
274
275 EFI_SUCCESS - The command completed successfully.
276 Other - Device error or wirte-locked, operation failed.
277
278 **/
279 EFI_STATUS
280 InternalEraseBlock (
281 IN EFI_PHYSICAL_ADDRESS BaseAddress
282 )
283 {
284 EFI_STATUS Status;
285 UINTN NumBytes;
286
287 NumBytes = BLOCK_SIZE;
288
289 Status = SpiFlashBlockErase ((UINTN) BaseAddress, &NumBytes);
290
291 return Status;
292 }
293
294 EFI_STATUS
295 InternalCompareBlock (
296 IN EFI_PHYSICAL_ADDRESS BaseAddress,
297 IN UINT8 *Buffer
298 )
299 {
300 EFI_STATUS Status;
301 VOID *CompareBuffer;
302 UINT32 NumBytes;
303 INTN CompareResult;
304
305 NumBytes = BLOCK_SIZE;
306 CompareBuffer = AllocatePool (NumBytes);
307 if (CompareBuffer == NULL) {
308 Status = EFI_OUT_OF_RESOURCES;
309 goto Done;
310 }
311
312 Status = SpiFlashRead ((UINTN) BaseAddress, &NumBytes, CompareBuffer);
313 if (EFI_ERROR (Status)) {
314 goto Done;
315 }
316 CompareResult = CompareMem (CompareBuffer, Buffer, BLOCK_SIZE);
317 if (CompareResult != 0) {
318 Status = EFI_VOLUME_CORRUPTED;
319 }
320
321 Done:
322 if (CompareBuffer != NULL) {
323 FreePool (CompareBuffer);
324 }
325
326 return Status;
327 }
328
329 /**
330
331 Routine Description:
332
333 Write a block of data.
334
335 Arguments:
336
337 BaseAddress - Base address of the block.
338 Buffer - Data buffer.
339 BufferSize - Size of the buffer.
340
341 Returns:
342
343 EFI_SUCCESS - The command completed successfully.
344 EFI_INVALID_PARAMETER - Invalid parameter, can not proceed.
345 Other - Device error or wirte-locked, operation failed.
346
347 **/
348 EFI_STATUS
349 InternalWriteBlock (
350 IN EFI_PHYSICAL_ADDRESS BaseAddress,
351 IN UINT8 *Buffer,
352 IN UINT32 BufferSize
353 )
354 {
355 EFI_STATUS Status;
356
357 Status = SpiFlashWrite ((UINTN) BaseAddress, &BufferSize, Buffer);
358
359 if (EFI_ERROR (Status)) {
360 DEBUG((DEBUG_ERROR, "\nFlash write error."));
361 return Status;
362 }
363
364 WriteBackInvalidateDataCacheRange ((VOID *) (UINTN) BaseAddress, BLOCK_SIZE);
365
366 Status = InternalCompareBlock (BaseAddress, Buffer);
367 if (EFI_ERROR (Status)) {
368 DEBUG((DEBUG_ERROR, "\nError when writing to BaseAddress %x with different at offset %x.", BaseAddress, Status));
369 } else {
370 DEBUG((DEBUG_INFO, "\nVerified data written to Block at %x is correct.", BaseAddress));
371 }
372
373 return Status;
374
375 }
376
377 /**
378 Perform flash write operation with progress indicator. The start and end
379 completion percentage values are passed into this function. If the requested
380 flash write operation is broken up, then completion percentage between the
381 start and end values may be passed to the provided Progress function. The
382 caller of this function is required to call the Progress function for the
383 start and end completion percentage values. This allows the Progress,
384 StartPercentage, and EndPercentage parameters to be ignored if the requested
385 flash write operation can not be broken up
386
387 @param[in] FirmwareType The type of firmware.
388 @param[in] FlashAddress The address of flash device to be accessed.
389 @param[in] FlashAddressType The type of flash device address.
390 @param[in] Buffer The pointer to the data buffer.
391 @param[in] Length The length of data buffer in bytes.
392 @param[in] Progress A function used report the progress of the
393 firmware update. This is an optional parameter
394 that may be NULL.
395 @param[in] StartPercentage The start completion percentage value that may
396 be used to report progress during the flash
397 write operation.
398 @param[in] EndPercentage The end completion percentage value that may
399 be used to report progress during the flash
400 write operation.
401
402 @retval EFI_SUCCESS The operation returns successfully.
403 @retval EFI_WRITE_PROTECTED The flash device is read only.
404 @retval EFI_UNSUPPORTED The flash device access is unsupported.
405 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
406 **/
407 EFI_STATUS
408 EFIAPI
409 PerformFlashWriteWithProgress (
410 IN PLATFORM_FIRMWARE_TYPE FirmwareType,
411 IN EFI_PHYSICAL_ADDRESS FlashAddress,
412 IN FLASH_ADDRESS_TYPE FlashAddressType,
413 IN VOID *Buffer,
414 IN UINTN Length,
415 IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, OPTIONAL
416 IN UINTN StartPercentage,
417 IN UINTN EndPercentage
418 )
419 {
420 EFI_STATUS Status = EFI_SUCCESS;
421 UINTN Index;
422 EFI_PHYSICAL_ADDRESS Address;
423 UINTN CountOfBlocks;
424 EFI_TPL OldTpl;
425 BOOLEAN FlashError;
426 UINT8 *Buf;
427 UINTN LpcBaseAddress;
428 UINT8 Data8Or;
429 UINT8 Data8And;
430 UINT8 BiosCntl;
431
432 Index = 0;
433 Address = 0;
434 CountOfBlocks = 0;
435 FlashError = FALSE;
436 Buf = Buffer;
437
438 DEBUG((DEBUG_INFO | DEBUG_ERROR, "PerformFlashWrite - 0x%x(%x) - 0x%x\n", (UINTN)FlashAddress, (UINTN)FlashAddressType, Length));
439 if (FlashAddressType == FlashAddressTypeRelativeAddress) {
440 FlashAddress = FlashAddress + mInternalFdAddress;
441 }
442
443 CountOfBlocks = (UINTN) (Length / BLOCK_SIZE);
444 Address = FlashAddress;
445
446 LpcBaseAddress = MmPciAddress (0,
447 DEFAULT_PCI_BUS_NUMBER_PCH,
448 PCI_DEVICE_NUMBER_PCH_LPC,
449 PCI_FUNCTION_NUMBER_PCH_LPC,
450 0
451 );
452 BiosCntl = MmioRead8 (LpcBaseAddress + R_PCH_LPC_BIOS_CNTL);
453 if ((BiosCntl & B_PCH_LPC_BIOS_CNTL_SMM_BWP) == B_PCH_LPC_BIOS_CNTL_SMM_BWP) {
454 ///
455 /// Clear SMM_BWP bit (D31:F0:RegDCh[5])
456 ///
457 Data8And = (UINT8) ~B_PCH_LPC_BIOS_CNTL_SMM_BWP;
458 Data8Or = 0x00;
459
460 MmioAndThenOr8 (
461 LpcBaseAddress + R_PCH_LPC_BIOS_CNTL,
462 Data8And,
463 Data8Or
464 );
465 DEBUG((DEBUG_INFO, "PerformFlashWrite Clear SMM_BWP bit\n"));
466 }
467
468 //
469 // Raise TPL to TPL_NOTIFY to block any event handler,
470 // while still allowing RaiseTPL(TPL_NOTIFY) within
471 // output driver during Print()
472 //
473 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
474 for (Index = 0; Index < CountOfBlocks; Index++) {
475 if (Progress != NULL) {
476 Progress (StartPercentage + ((Index * (EndPercentage - StartPercentage)) / CountOfBlocks));
477 }
478 //
479 // Handle block based on address and contents.
480 //
481 if (!EFI_ERROR (InternalCompareBlock (Address, Buf))) {
482 DEBUG((DEBUG_INFO, "Skipping block at 0x%lx (already programmed)\n", Address));
483 } else {
484 //
485 // Make updating process uninterruptable,
486 // so that the flash memory area is not accessed by other entities
487 // which may interfere with the updating process
488 //
489 Status = InternalEraseBlock (Address);
490 if (EFI_ERROR(Status)) {
491 gBS->RestoreTPL (OldTpl);
492 FlashError = TRUE;
493 goto Done;
494 }
495 Status = InternalWriteBlock (
496 Address,
497 Buf,
498 (UINT32)(Length > BLOCK_SIZE ? BLOCK_SIZE : Length)
499 );
500 if (EFI_ERROR(Status)) {
501 gBS->RestoreTPL (OldTpl);
502 FlashError = TRUE;
503 goto Done;
504 }
505 }
506
507 //
508 // Move to next block to update.
509 //
510 Address += BLOCK_SIZE;
511 Buf += BLOCK_SIZE;
512 if (Length > BLOCK_SIZE) {
513 Length -= BLOCK_SIZE;
514 } else {
515 Length = 0;
516 }
517 }
518 gBS->RestoreTPL (OldTpl);
519
520 Done:
521 if ((BiosCntl & B_PCH_LPC_BIOS_CNTL_SMM_BWP) == B_PCH_LPC_BIOS_CNTL_SMM_BWP) {
522 //
523 // Restore original control setting
524 //
525 MmioWrite8 (LpcBaseAddress + R_PCH_LPC_BIOS_CNTL, BiosCntl);
526 }
527
528 if (Progress != NULL) {
529 Progress (EndPercentage);
530 }
531
532 if (FlashError) {
533 return EFI_WRITE_PROTECTED;
534 }
535
536 return EFI_SUCCESS;
537 }
538
539 /**
540 Perform flash write operation.
541
542 @param[in] FirmwareType The type of firmware.
543 @param[in] FlashAddress The address of flash device to be accessed.
544 @param[in] FlashAddressType The type of flash device address.
545 @param[in] Buffer The pointer to the data buffer.
546 @param[in] Length The length of data buffer in bytes.
547
548 @retval EFI_SUCCESS The operation returns successfully.
549 @retval EFI_WRITE_PROTECTED The flash device is read only.
550 @retval EFI_UNSUPPORTED The flash device access is unsupported.
551 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
552 **/
553 EFI_STATUS
554 EFIAPI
555 PerformFlashWrite (
556 IN PLATFORM_FIRMWARE_TYPE FirmwareType,
557 IN EFI_PHYSICAL_ADDRESS FlashAddress,
558 IN FLASH_ADDRESS_TYPE FlashAddressType,
559 IN VOID *Buffer,
560 IN UINTN Length
561 )
562 {
563 return PerformFlashWriteWithProgress (
564 FirmwareType,
565 FlashAddress,
566 FlashAddressType,
567 Buffer,
568 Length,
569 NULL,
570 0,
571 0
572 );
573 }
574
575 /**
576 Perform microcode write operation.
577
578 @param[in] FlashAddress The address of flash device to be accessed.
579 @param[in] Buffer The pointer to the data buffer.
580 @param[in] Length The length of data buffer in bytes.
581
582 @retval EFI_SUCCESS The operation returns successfully.
583 @retval EFI_WRITE_PROTECTED The flash device is read only.
584 @retval EFI_UNSUPPORTED The flash device access is unsupported.
585 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
586 **/
587 EFI_STATUS
588 EFIAPI
589 MicrocodeFlashWrite (
590 IN EFI_PHYSICAL_ADDRESS FlashAddress,
591 IN VOID *Buffer,
592 IN UINTN Length
593 )
594 {
595 EFI_PHYSICAL_ADDRESS AlignedFlashAddress;
596 VOID *AlignedBuffer;
597 UINTN AlignedLength;
598 UINTN OffsetHead;
599 UINTN OffsetTail;
600 EFI_STATUS Status;
601
602 DEBUG((DEBUG_INFO, "MicrocodeFlashWrite - 0x%x - 0x%x\n", (UINTN)FlashAddress, Length));
603
604 //
605 // Need make buffer 64K aligned to support ERASE
606 //
607 // [Aligned] FlashAddress [Aligned]
608 // | | |
609 // V V V
610 // +--------------+========+------------+
611 // | OffsetHeader | Length | OffsetTail |
612 // +--------------+========+------------+
613 // ^
614 // |<-----------AlignedLength----------->
615 // |
616 // AlignedFlashAddress
617 //
618 OffsetHead = FlashAddress & (ALINGED_SIZE - 1);
619 OffsetTail = (FlashAddress + Length) & (ALINGED_SIZE - 1);
620 if (OffsetTail != 0) {
621 OffsetTail = ALINGED_SIZE - OffsetTail;
622 }
623
624 if ((OffsetHead != 0) || (OffsetTail != 0)) {
625 AlignedFlashAddress = FlashAddress - OffsetHead;
626 AlignedLength = Length + OffsetHead + OffsetTail;
627
628 AlignedBuffer = AllocatePool(AlignedLength);
629 if (AlignedBuffer == NULL) {
630 return EFI_OUT_OF_RESOURCES;
631 }
632 //
633 // Save original buffer
634 //
635 if (OffsetHead != 0) {
636 CopyMem((UINT8 *)AlignedBuffer, (VOID *)(UINTN)AlignedFlashAddress, OffsetHead);
637 }
638 if (OffsetTail != 0) {
639 CopyMem((UINT8 *)AlignedBuffer + OffsetHead + Length, (VOID *)(UINTN)(AlignedFlashAddress + OffsetHead + Length), OffsetTail);
640 }
641 //
642 // Override new buffer
643 //
644 CopyMem((UINT8 *)AlignedBuffer + OffsetHead, Buffer, Length);
645 } else {
646 AlignedFlashAddress = FlashAddress;
647 AlignedBuffer = Buffer;
648 AlignedLength = Length;
649 }
650
651 Status = PerformFlashWrite(
652 PlatformFirmwareTypeSystemFirmware,
653 AlignedFlashAddress,
654 FlashAddressTypeAbsoluteAddress,
655 AlignedBuffer,
656 AlignedLength
657 );
658 if ((OffsetHead != 0) || (OffsetTail != 0)) {
659 FreePool (AlignedBuffer);
660 }
661 return Status;
662 }
663
664 /**
665 Platform Flash Access Lib Constructor.
666 **/
667 EFI_STATUS
668 EFIAPI
669 PerformFlashAccessLibConstructor (
670 VOID
671 )
672 {
673 EFI_STATUS Status;
674 mInternalFdAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32(PcdFlashAreaBaseAddress);
675 DEBUG((DEBUG_INFO, "PcdFlashAreaBaseAddress - 0x%x\n", mInternalFdAddress));
676
677 Status = gBS->LocateProtocol (
678 &gEfiSpiProtocolGuid,
679 NULL,
680 (VOID **) &mSpiProtocol
681 );
682 ASSERT_EFI_ERROR(Status);
683
684 return EFI_SUCCESS;
685 }