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