2 Implementation of helper routines for DXE environment.
4 Copyright (c) 2013 Intel Corporation.
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Library/UefiBootServicesTableLib.h>
19 #include <Library/S3BootScriptLib.h>
20 #include <Library/DxeServicesLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
22 #include <Library/I2cLib.h>
23 #include <Protocol/SmmBase2.h>
24 #include <Protocol/Spi.h>
25 #include <Protocol/VariableLock.h>
27 #include <Guid/MemoryConfigData.h>
28 #include <Guid/QuarkVariableLock.h>
30 #include "CommonHeader.h"
32 #define FLASH_BLOCK_SIZE SIZE_4KB
37 EFI_SPI_PROTOCOL
*mPlatHelpSpiProtocolRef
= NULL
;
40 // Routines defined in other source modules of this component.
44 // Routines local to this component.
48 // Routines shared with other souce modules in this component.
52 Pcal9555GetPortRegBit (
53 IN CONST UINT32 Pcal9555SlaveAddr
,
54 IN CONST UINT32 GpioNum
,
55 IN CONST UINT8 RegBase
62 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr
;
63 EFI_I2C_ADDR_MODE I2cAddrMode
;
68 I2cDeviceAddr
.I2CDeviceAddress
= (UINTN
) Pcal9555SlaveAddr
;
69 I2cAddrMode
= EfiI2CSevenBitAddrMode
;
73 GpioNumMask
= (UINT8
) (1 << GpioNum
);
75 SubAddr
= RegBase
+ 1;
76 GpioNumMask
= (UINT8
) (1 << (GpioNum
- 8));
80 // Output port value always at 2nd byte in Data variable.
82 RegValuePtr
= &Data
[1];
85 // On read entry sub address at 2nd byte, on read exit output
86 // port value in 2nd byte.
91 Status
= I2cReadMultipleByte (
98 ASSERT_EFI_ERROR (Status
);
101 // Adjust output port bit given callers request.
103 return ((*RegValuePtr
& GpioNumMask
) != 0);
107 Pcal9555SetPortRegBit (
108 IN CONST UINT32 Pcal9555SlaveAddr
,
109 IN CONST UINT32 GpioNum
,
110 IN CONST UINT8 RegBase
,
111 IN CONST BOOLEAN LogicOne
118 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr
;
119 EFI_I2C_ADDR_MODE I2cAddrMode
;
124 I2cDeviceAddr
.I2CDeviceAddress
= (UINTN
) Pcal9555SlaveAddr
;
125 I2cAddrMode
= EfiI2CSevenBitAddrMode
;
129 GpioNumMask
= (UINT8
) (1 << GpioNum
);
131 SubAddr
= RegBase
+ 1;
132 GpioNumMask
= (UINT8
) (1 << (GpioNum
- 8));
136 // Output port value always at 2nd byte in Data variable.
138 RegValuePtr
= &Data
[1];
141 // On read entry sub address at 2nd byte, on read exit output
142 // port value in 2nd byte.
147 Status
= I2cReadMultipleByte (
154 ASSERT_EFI_ERROR (Status
);
157 // Adjust output port bit given callers request.
160 *RegValuePtr
= *RegValuePtr
| GpioNumMask
;
162 *RegValuePtr
= *RegValuePtr
& ~(GpioNumMask
);
166 // Update register. Sub address at 1st byte, value at 2nd byte.
170 Status
= I2cWriteMultipleByte (
176 ASSERT_EFI_ERROR (Status
);
182 IN EFI_SMM_SYSTEM_TABLE2
*Smst
185 if (mPlatHelpSpiProtocolRef
== NULL
) {
187 Smst
->SmmLocateProtocol (
188 &gEfiSmmSpiProtocolGuid
,
190 (VOID
**) &mPlatHelpSpiProtocolRef
193 gBS
->LocateProtocol (
194 &gEfiSpiProtocolGuid
,
196 (VOID
**) &mPlatHelpSpiProtocolRef
199 ASSERT (mPlatHelpSpiProtocolRef
!= NULL
);
201 return mPlatHelpSpiProtocolRef
;
205 // Routines exported by this source module.
209 Find pointer to RAW data in Firmware volume file.
211 @param FvNameGuid Firmware volume to search. If == NULL search all.
212 @param FileNameGuid Firmware volume file to search for.
213 @param SectionData Pointer to RAW data section of found file.
214 @param SectionDataSize Pointer to UNITN to get size of RAW data.
216 @retval EFI_SUCCESS Raw Data found.
217 @retval EFI_INVALID_PARAMETER FileNameGuid == NULL.
218 @retval EFI_NOT_FOUND Firmware volume file not found.
219 @retval EFI_UNSUPPORTED Unsupported in current enviroment (PEI or DXE).
224 PlatformFindFvFileRawDataSection (
225 IN CONST EFI_GUID
*FvNameGuid OPTIONAL
,
226 IN CONST EFI_GUID
*FileNameGuid
,
227 OUT VOID
**SectionData
,
228 OUT UINTN
*SectionDataSize
231 if (FileNameGuid
== NULL
|| SectionData
== NULL
|| SectionDataSize
== NULL
) {
232 return EFI_INVALID_PARAMETER
;
234 if (FvNameGuid
!= NULL
) {
235 return EFI_UNSUPPORTED
; // Searching in specific FV unsupported in DXE.
238 return GetSectionFromAnyFv (FileNameGuid
, EFI_SECTION_RAW
, 0, SectionData
, SectionDataSize
);
242 Find free spi protect register and write to it to protect a flash region.
244 @param DirectValue Value to directly write to register.
245 if DirectValue == 0 the use Base & Length below.
246 @param BaseAddress Base address of region in Flash Memory Map.
247 @param Length Length of region to protect.
249 @retval EFI_SUCCESS Free spi protect register found & written.
250 @retval EFI_NOT_FOUND Free Spi protect register not found.
251 @retval EFI_DEVICE_ERROR Unable to write to spi protect register.
255 PlatformWriteFirstFreeSpiProtect (
256 IN CONST UINT32 DirectValue
,
257 IN CONST UINT32 BaseAddress
,
258 IN CONST UINT32 Length
262 UINT32 PchRootComplexBar
;
265 PchRootComplexBar
= QNC_RCRB_BASE
;
267 Status
= WriteFirstFreeSpiProtect (
275 if (!EFI_ERROR (Status
)) {
276 S3BootScriptSaveMemWrite (
277 S3BootScriptWidthUint32
,
278 (UINTN
) (PchRootComplexBar
+ FreeOffset
),
280 (VOID
*) (UINTN
) (PchRootComplexBar
+ FreeOffset
)
288 Lock legacy SPI static configuration information.
290 Function will assert if unable to lock config.
295 PlatformFlashLockConfig (
300 EFI_SPI_PROTOCOL
*SpiProtocol
;
303 // Enable lock of legacy SPI static configuration information.
306 SpiProtocol
= LocateSpiProtocol (NULL
); // This routine will not be called in SMM.
307 ASSERT_EFI_ERROR (SpiProtocol
!= NULL
);
308 if (SpiProtocol
!= NULL
) {
309 Status
= SpiProtocol
->Lock (SpiProtocol
);
311 if (!EFI_ERROR (Status
)) {
312 DEBUG ((EFI_D_INFO
, "Platform: Spi Config Locked Down\n"));
313 } else if (Status
== EFI_ACCESS_DENIED
) {
314 DEBUG ((EFI_D_INFO
, "Platform: Spi Config already locked down\n"));
316 ASSERT_EFI_ERROR (Status
);
322 Platform Variable Lock.
324 @retval EFI_SUCCESS Platform Variable Lock successful.
325 @retval EFI_NOT_FOUND No protocol instances were found that match Protocol and
331 PlatformVariableLock (
335 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLockProtocol
;
337 Status
= gBS
->LocateProtocol (&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLockProtocol
);
338 ASSERT_EFI_ERROR (Status
);
340 Status
= VariableLockProtocol
->RequestToLock (
341 VariableLockProtocol
,
342 QUARK_VARIABLE_LOCK_NAME
,
343 &gQuarkVariableLockGuid
345 ASSERT_EFI_ERROR (Status
);
347 // Memory Config Data shouldn't be writable when Quark Variable Lock is enabled.
348 Status
= VariableLockProtocol
->RequestToLock (
349 VariableLockProtocol
,
350 EFI_MEMORY_CONFIG_DATA_NAME
,
351 &gEfiMemoryConfigDataGuid
353 ASSERT_EFI_ERROR (Status
);
357 Lock regions and config of SPI flash given the policy for this platform.
359 Function will assert if unable to lock regions or config.
361 @param PreBootPolicy If TRUE do Pre Boot Flash Lock Policy.
366 PlatformFlashLockPolicy (
367 IN CONST BOOLEAN PreBootPolicy
371 UINT64 CpuAddressNvStorage
;
372 UINT64 CpuAddressFlashDevice
;
374 EFI_BOOT_MODE BootMode
;
375 UINTN SpiFlashDeviceSize
;
377 BootMode
= GetBootModeHob ();
379 SpiFlashDeviceSize
= (UINTN
) PcdGet32 (PcdSpiFlashDeviceSize
);
380 CpuAddressFlashDevice
= SIZE_4GB
- SpiFlashDeviceSize
;
383 "Platform:FlashDeviceSize = 0x%08x Bytes\n",
388 // If not in update or recovery mode, lock stuff down
390 if ((BootMode
!= BOOT_IN_RECOVERY_MODE
) && (BootMode
!= BOOT_ON_FLASH_UPDATE
)) {
395 CpuAddressNvStorage
= (UINT64
) PcdGet32 (PcdFlashNvStorageVariableBase
);
398 // Lock from start of flash device up to Smi writable flash storage areas.
401 if (!PlatformIsSpiRangeProtected ((UINT32
) SpiAddress
, (UINT32
) (CpuAddressNvStorage
- CpuAddressFlashDevice
))) {
404 "Platform: Protect Region Base:Len 0x%08x:0x%08x\n",
405 (UINTN
) SpiAddress
, (UINTN
)(CpuAddressNvStorage
- CpuAddressFlashDevice
))
407 Status
= PlatformWriteFirstFreeSpiProtect (
410 (UINT32
) (CpuAddressNvStorage
- CpuAddressFlashDevice
)
413 ASSERT_EFI_ERROR (Status
);
416 // Move Spi Address to after Smi writable flash storage areas.
418 SpiAddress
= CpuAddressNvStorage
- CpuAddressFlashDevice
;
419 SpiAddress
+= ((UINT64
) PcdGet32 (PcdFlashNvStorageVariableSize
));
422 // Lock from end of OEM area to end of flash part.
424 if (!PlatformIsSpiRangeProtected ((UINT32
) SpiAddress
, SpiFlashDeviceSize
- ((UINT32
) SpiAddress
))) {
427 "Platform: Protect Region Base:Len 0x%08x:0x%08x\n",
429 (UINTN
) (SpiFlashDeviceSize
- ((UINT32
) SpiAddress
)))
431 ASSERT (SpiAddress
< ((UINT64
) SpiFlashDeviceSize
));
432 Status
= PlatformWriteFirstFreeSpiProtect (
435 SpiFlashDeviceSize
- ((UINT32
) SpiAddress
)
438 ASSERT_EFI_ERROR (Status
);
443 // Always Lock flash config registers if about to boot a boot option
444 // else lock depending on boot mode.
446 if (PreBootPolicy
|| (BootMode
!= BOOT_ON_FLASH_UPDATE
)) {
447 PlatformFlashLockConfig ();
451 // Enable Quark Variable lock if PreBootPolicy.
454 PlatformVariableLock ();
459 Erase and Write to platform flash.
461 Routine accesses one flash block at a time, each access consists
462 of an erase followed by a write of FLASH_BLOCK_SIZE. One or both
463 of DoErase & DoWrite params must be TRUE.
466 CpuWriteAddress must be aligned to FLASH_BLOCK_SIZE.
467 DataSize must be a multiple of FLASH_BLOCK_SIZE.
469 @param Smst If != NULL then InSmm and use to locate
471 @param CpuWriteAddress Address in CPU memory map of flash region.
472 @param Data The buffer containing the data to be written.
473 @param DataSize Amount of data to write.
474 @param DoErase Earse each block.
475 @param DoWrite Write to each block.
477 @retval EFI_SUCCESS Operation successful.
478 @retval EFI_NOT_READY Required resources not setup.
479 @retval EFI_INVALID_PARAMETER Invalid parameter.
480 @retval Others Unexpected error happened.
485 PlatformFlashEraseWrite (
487 IN UINTN CpuWriteAddress
,
495 UINT64 CpuBaseAddress
;
496 SPI_INIT_INFO
*SpiInfo
;
499 UINTN SpiWriteAddress
;
500 EFI_SPI_PROTOCOL
*SpiProtocol
;
502 if (!DoErase
&& !DoWrite
) {
503 return EFI_INVALID_PARAMETER
;
505 if (DoWrite
&& Data
== NULL
) {
506 return EFI_INVALID_PARAMETER
;
508 if ((CpuWriteAddress
% FLASH_BLOCK_SIZE
) != 0) {
509 return EFI_INVALID_PARAMETER
;
511 if ((DataSize
% FLASH_BLOCK_SIZE
) != 0) {
512 return EFI_INVALID_PARAMETER
;
514 SpiProtocol
= LocateSpiProtocol ((EFI_SMM_SYSTEM_TABLE2
*)Smst
);
515 if (SpiProtocol
== NULL
) {
516 return EFI_NOT_READY
;
520 // Find info to allow usage of SpiProtocol->Execute.
522 Status
= SpiProtocol
->Info (
526 if (EFI_ERROR(Status
)) {
529 ASSERT (SpiInfo
->InitTable
!= NULL
);
530 ASSERT (SpiInfo
->EraseOpcodeIndex
< SPI_NUM_OPCODE
);
531 ASSERT (SpiInfo
->ProgramOpcodeIndex
< SPI_NUM_OPCODE
);
533 CpuBaseAddress
= PcdGet32 (PcdFlashAreaBaseAddress
) - (UINT32
)SpiInfo
->InitTable
->BiosStartOffset
;
534 ASSERT(CpuBaseAddress
>= (SIZE_4GB
- SIZE_8MB
));
535 if (CpuWriteAddress
< CpuBaseAddress
) {
536 return (EFI_INVALID_PARAMETER
);
539 SpiWriteAddress
= CpuWriteAddress
- ((UINTN
) CpuBaseAddress
);
542 (EFI_D_INFO
, "PlatformFlashWrite:SpiWriteAddress=%08x EraseIndex=%d WriteIndex=%d\n",
544 (UINTN
) SpiInfo
->EraseOpcodeIndex
,
545 (UINTN
) SpiInfo
->ProgramOpcodeIndex
547 for (Index
=0; Index
< DataSize
/ FLASH_BLOCK_SIZE
; Index
++) {
550 (EFI_D_INFO
, "PlatformFlashWrite:Erase[%04x] SpiWriteAddress=%08x\n",
554 Status
= SpiProtocol
->Execute (
556 SpiInfo
->EraseOpcodeIndex
,// OpcodeIndex
557 0, // PrefixOpcodeIndex
561 SpiWriteAddress
, // Address
564 EnumSpiRegionAll
// SPI_REGION_TYPE
566 if (EFI_ERROR(Status
)) {
573 (EFI_D_INFO
, "PlatformFlashWrite:Write[%04x] SpiWriteAddress=%08x\n",
577 Status
= SpiProtocol
->Execute (
579 SpiInfo
->ProgramOpcodeIndex
, // OpcodeIndex
580 0, // PrefixOpcodeIndex
584 SpiWriteAddress
, // Address
585 FLASH_BLOCK_SIZE
, // Data Number
589 if (EFI_ERROR(Status
)) {
592 WriteBuf
+=FLASH_BLOCK_SIZE
;
594 SpiWriteAddress
+=FLASH_BLOCK_SIZE
;
599 /** Check if System booted with recovery Boot Stage1 image.
601 @retval TRUE If system booted with recovery Boot Stage1 image.
602 @retval FALSE If system booted with normal stage1 image.
607 PlatformIsBootWithRecoveryStage1 (
611 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
616 Set the direction of Pcal9555 IO Expander GPIO pin.
618 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
619 @param GpioNum Gpio direction to configure - values 0-7 for Port0
621 @param CfgAsInput If TRUE set pin direction as input else set as output.
626 PlatformPcal9555GpioSetDir (
627 IN CONST UINT32 Pcal9555SlaveAddr
,
628 IN CONST UINT32 GpioNum
,
629 IN CONST BOOLEAN CfgAsInput
632 Pcal9555SetPortRegBit (
635 PCAL9555_REG_CFG_PORT0
,
641 Set the level of Pcal9555 IO Expander GPIO high or low.
643 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
644 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
646 @param HighLevel If TRUE set pin high else set pin low.
651 PlatformPcal9555GpioSetLevel (
652 IN CONST UINT32 Pcal9555SlaveAddr
,
653 IN CONST UINT32 GpioNum
,
654 IN CONST BOOLEAN HighLevel
657 Pcal9555SetPortRegBit (
660 PCAL9555_REG_OUT_PORT0
,
667 Enable pull-up/pull-down resistors of Pcal9555 GPIOs.
669 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
670 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
676 PlatformPcal9555GpioEnablePull (
677 IN CONST UINT32 Pcal9555SlaveAddr
,
678 IN CONST UINT32 GpioNum
681 Pcal9555SetPortRegBit (
684 PCAL9555_REG_PULL_EN_PORT0
,
691 Disable pull-up/pull-down resistors of Pcal9555 GPIOs.
693 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
694 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
700 PlatformPcal9555GpioDisablePull (
701 IN CONST UINT32 Pcal9555SlaveAddr
,
702 IN CONST UINT32 GpioNum
705 Pcal9555SetPortRegBit (
708 PCAL9555_REG_PULL_EN_PORT0
,
715 Get state of Pcal9555 GPIOs.
717 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander.
718 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15
721 @retval TRUE GPIO pin is high
722 @retval FALSE GPIO pin is low
726 PlatformPcal9555GpioGetState (
727 IN CONST UINT32 Pcal9555SlaveAddr
,
728 IN CONST UINT32 GpioNum
731 return Pcal9555GetPortRegBit (Pcal9555SlaveAddr
, GpioNum
, PCAL9555_REG_IN_PORT0
);