]> git.proxmox.com Git - mirror_edk2.git/blob - Vlv2TbltDevicePkg/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c
Vlv2TbltDevicePkg: Sync FLASH libraries from UDK2017 branch
[mirror_edk2.git] / Vlv2TbltDevicePkg / Feature / Capsule / Library / PlatformFlashAccessLib / PlatformFlashAccessLib.c
1 /** @file
2 Platform Flash Access library.
3
4 Copyright (c) 2017, 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 opreation.
385
386 @param[in] FirmwareType The type of firmware.
387 @param[in] FlashAddress The address of flash device to be accessed.
388 @param[in] FlashAddressType The type of flash device address.
389 @param[in] Buffer The pointer to the data buffer.
390 @param[in] Length The length of data buffer in bytes.
391
392 @retval EFI_SUCCESS The operation returns successfully.
393 @retval EFI_WRITE_PROTECTED The flash device is read only.
394 @retval EFI_UNSUPPORTED The flash device access is unsupported.
395 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
396 **/
397 EFI_STATUS
398 EFIAPI
399 PerformFlashWrite (
400 IN PLATFORM_FIRMWARE_TYPE FirmwareType,
401 IN EFI_PHYSICAL_ADDRESS FlashAddress,
402 IN FLASH_ADDRESS_TYPE FlashAddressType,
403 IN VOID *Buffer,
404 IN UINTN Length
405 )
406 {
407 EFI_STATUS Status = EFI_SUCCESS;
408 UINTN Index;
409 EFI_PHYSICAL_ADDRESS Address;
410 UINTN CountOfBlocks;
411 EFI_TPL OldTpl;
412 BOOLEAN FlashError;
413 UINT8 *Buf;
414 UINTN LpcBaseAddress;
415 UINT8 Data8Or;
416 UINT8 Data8And;
417 UINT8 BiosCntl;
418
419 Index = 0;
420 Address = 0;
421 CountOfBlocks = 0;
422 FlashError = FALSE;
423 Buf = Buffer;
424
425 DEBUG((DEBUG_INFO | DEBUG_ERROR, "PerformFlashWrite - 0x%x(%x) - 0x%x\n", (UINTN)FlashAddress, (UINTN)FlashAddressType, Length));
426 if (FlashAddressType == FlashAddressTypeRelativeAddress) {
427 FlashAddress = FlashAddress + mInternalFdAddress;
428 }
429
430 CountOfBlocks = (UINTN) (Length / BLOCK_SIZE);
431 Address = FlashAddress;
432
433 LpcBaseAddress = MmPciAddress (0,
434 DEFAULT_PCI_BUS_NUMBER_PCH,
435 PCI_DEVICE_NUMBER_PCH_LPC,
436 PCI_FUNCTION_NUMBER_PCH_LPC,
437 0
438 );
439 BiosCntl = MmioRead8 (LpcBaseAddress + R_PCH_LPC_BIOS_CNTL);
440 if ((BiosCntl & B_PCH_LPC_BIOS_CNTL_SMM_BWP) == B_PCH_LPC_BIOS_CNTL_SMM_BWP) {
441 ///
442 /// Clear SMM_BWP bit (D31:F0:RegDCh[5])
443 ///
444 Data8And = (UINT8) ~B_PCH_LPC_BIOS_CNTL_SMM_BWP;
445 Data8Or = 0x00;
446
447 MmioAndThenOr8 (
448 LpcBaseAddress + R_PCH_LPC_BIOS_CNTL,
449 Data8And,
450 Data8Or
451 );
452 DEBUG((DEBUG_INFO, "PerformFlashWrite Clear SMM_BWP bit\n"));
453 }
454
455 //
456 // Raise TPL to TPL_NOTIFY to block any event handler,
457 // while still allowing RaiseTPL(TPL_NOTIFY) within
458 // output driver during Print()
459 //
460 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
461 for (Index = 0; Index < CountOfBlocks; Index++) {
462 //
463 // Handle block based on address and contents.
464 //
465 if (!EFI_ERROR (InternalCompareBlock (Address, Buf))) {
466 DEBUG((DEBUG_INFO, "Skipping block at 0x%lx (already programmed)\n", Address));
467 } else {
468 //
469 // Display a dot for each block being updated.
470 //
471 Print (L".");
472
473 //
474 // Make updating process uninterruptable,
475 // so that the flash memory area is not accessed by other entities
476 // which may interfere with the updating process
477 //
478 Status = InternalEraseBlock (Address);
479 if (EFI_ERROR(Status)) {
480 gBS->RestoreTPL (OldTpl);
481 FlashError = TRUE;
482 goto Done;
483 }
484 Status = InternalWriteBlock (
485 Address,
486 Buf,
487 (UINT32)(Length > BLOCK_SIZE ? BLOCK_SIZE : Length)
488 );
489 if (EFI_ERROR(Status)) {
490 gBS->RestoreTPL (OldTpl);
491 FlashError = TRUE;
492 goto Done;
493 }
494 }
495
496 //
497 // Move to next block to update.
498 //
499 Address += BLOCK_SIZE;
500 Buf += BLOCK_SIZE;
501 if (Length > BLOCK_SIZE) {
502 Length -= BLOCK_SIZE;
503 } else {
504 Length = 0;
505 }
506 }
507 gBS->RestoreTPL (OldTpl);
508
509 Done:
510 if ((BiosCntl & B_PCH_LPC_BIOS_CNTL_SMM_BWP) == B_PCH_LPC_BIOS_CNTL_SMM_BWP) {
511 //
512 // Restore original control setting
513 //
514 MmioWrite8 (LpcBaseAddress + R_PCH_LPC_BIOS_CNTL, BiosCntl);
515 }
516
517 //
518 // Print flash update failure message if error detected.
519 //
520 if (FlashError) {
521 Print (L"No %r\n", Status);
522 }
523
524 return EFI_SUCCESS;
525 }
526
527 /**
528 Perform microcode write opreation.
529
530 @param[in] FlashAddress The address of flash device to be accessed.
531 @param[in] Buffer The pointer to the data buffer.
532 @param[in] Length The length of data buffer in bytes.
533
534 @retval EFI_SUCCESS The operation returns successfully.
535 @retval EFI_WRITE_PROTECTED The flash device is read only.
536 @retval EFI_UNSUPPORTED The flash device access is unsupported.
537 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
538 **/
539 EFI_STATUS
540 EFIAPI
541 MicrocodeFlashWrite (
542 IN EFI_PHYSICAL_ADDRESS FlashAddress,
543 IN VOID *Buffer,
544 IN UINTN Length
545 )
546 {
547 EFI_PHYSICAL_ADDRESS AlignedFlashAddress;
548 VOID *AlignedBuffer;
549 UINTN AlignedLength;
550 UINTN OffsetHead;
551 UINTN OffsetTail;
552 EFI_STATUS Status;
553
554 DEBUG((DEBUG_INFO, "MicrocodeFlashWrite - 0x%x - 0x%x\n", (UINTN)FlashAddress, Length));
555
556 //
557 // Need make buffer 64K aligned to support ERASE
558 //
559 // [Aligned] FlashAddress [Aligned]
560 // | | |
561 // V V V
562 // +--------------+========+------------+
563 // | OffsetHeader | Length | OffsetTail |
564 // +--------------+========+------------+
565 // ^
566 // |<-----------AlignedLength----------->
567 // |
568 // AlignedFlashAddress
569 //
570 OffsetHead = FlashAddress & (ALINGED_SIZE - 1);
571 OffsetTail = (FlashAddress + Length) & (ALINGED_SIZE - 1);
572 if (OffsetTail != 0) {
573 OffsetTail = ALINGED_SIZE - OffsetTail;
574 }
575
576 if ((OffsetHead != 0) || (OffsetTail != 0)) {
577 AlignedFlashAddress = FlashAddress - OffsetHead;
578 AlignedLength = Length + OffsetHead + OffsetTail;
579
580 AlignedBuffer = AllocatePool(AlignedLength);
581 if (AlignedBuffer == NULL) {
582 return EFI_OUT_OF_RESOURCES;
583 }
584 //
585 // Save original buffer
586 //
587 if (OffsetHead != 0) {
588 CopyMem((UINT8 *)AlignedBuffer, (VOID *)(UINTN)AlignedFlashAddress, OffsetHead);
589 }
590 if (OffsetTail != 0) {
591 CopyMem((UINT8 *)AlignedBuffer + OffsetHead + Length, (VOID *)(UINTN)(AlignedFlashAddress + OffsetHead + Length), OffsetTail);
592 }
593 //
594 // Override new buffer
595 //
596 CopyMem((UINT8 *)AlignedBuffer + OffsetHead, Buffer, Length);
597 } else {
598 AlignedFlashAddress = FlashAddress;
599 AlignedBuffer = Buffer;
600 AlignedLength = Length;
601 }
602
603 Status = PerformFlashWrite(
604 PlatformFirmwareTypeSystemFirmware,
605 AlignedFlashAddress,
606 FlashAddressTypeAbsoluteAddress,
607 AlignedBuffer,
608 AlignedLength
609 );
610 if ((OffsetHead != 0) || (OffsetTail != 0)) {
611 FreePool (AlignedBuffer);
612 }
613 return Status;
614 }
615
616 /**
617 Platform Flash Access Lib Constructor.
618 **/
619 EFI_STATUS
620 EFIAPI
621 PerformFlashAccessLibConstructor (
622 VOID
623 )
624 {
625 EFI_STATUS Status;
626 mInternalFdAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32(PcdFlashAreaBaseAddress);
627 DEBUG((DEBUG_INFO, "PcdFlashAreaBaseAddress - 0x%x\n", mInternalFdAddress));
628
629 Status = gBS->LocateProtocol (
630 &gEfiSpiProtocolGuid,
631 NULL,
632 (VOID **) &mSpiProtocol
633 );
634 ASSERT_EFI_ERROR(Status);
635
636 return EFI_SUCCESS;
637 }