public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Chiu, Chasel" <chasel.chiu@intel.com>
To: "Kubacki, Michael A" <michael.a.kubacki@intel.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Chaganty, Rangasai V" <rangasai.v.chaganty@intel.com>,
	"Desimone, Nathaniel L" <nathaniel.l.desimone@intel.com>,
	"Gao, Liming" <liming.gao@intel.com>,
	"Kinney, Michael D" <michael.d.kinney@intel.com>,
	"Sinha, Ankit" <ankit.sinha@intel.com>
Subject: Re: [edk2-platforms][PATCH V1 23/37] CoffeelakeSiliconPkg/Pch: Add PEI private library instances
Date: Sat, 17 Aug 2019 01:14:30 +0000	[thread overview]
Message-ID: <3C3EFB470A303B4AB093197B6777CCEC5046239E@PGSMSX111.gar.corp.intel.com> (raw)
In-Reply-To: <20190817001603.30632-24-michael.a.kubacki@intel.com>

Reviewed-by: Chasel Chiu <chasel.chiu@intel.com>


> -----Original Message-----
> From: Kubacki, Michael A
> Sent: Saturday, August 17, 2019 8:16 AM
> To: devel@edk2.groups.io
> Cc: Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Chiu, Chasel
> <chasel.chiu@intel.com>; Desimone, Nathaniel L
> <nathaniel.l.desimone@intel.com>; Gao, Liming <liming.gao@intel.com>;
> Kinney, Michael D <michael.d.kinney@intel.com>; Sinha, Ankit
> <ankit.sinha@intel.com>
> Subject: [edk2-platforms][PATCH V1 23/37] CoffeelakeSiliconPkg/Pch: Add PEI
> private library instances
> 
> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2082
> 
> Adds PCH PEI private library class instances. These library instances
> may be compatible with other boot phases as indicated by the library type.
> 
> * PeiDxeSmmGpioPrivateLibCnl
> * PeiDxeSmmPchDmiLib
> * PeiDxeSmmPchDmiWithS3Lib
> * PeiDxeSmmPchInitCommonLib
> * PeiDxeSmmPchPciExpressHelpersLib
> * PeiDxeSmmPchPsfPrivateLibCnl
> * PeiDxeSmmPmcPrivateLibCnl
> * PeiDxeSmmPmcPrivateLibWithS3
> * PeiGpioHelpersLib
> * PeiGpioNameBufferLib
> * PeiPmcPrivateLibCnl
> 
> Cc: Sai Chaganty <rangasai.v.chaganty@intel.com>
> Cc: Chasel Chiu <chasel.chiu@intel.com>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ankit Sinha <ankit.sinha@intel.com>
> Signed-off-by: Michael Kubacki <michael.a.kubacki@intel.com>
> ---
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivat
> eLib/PeiDxeSmmGpioPrivateLibCnl.inf                |   45 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib
> /PeiDxeSmmPchDmiLib.inf                             |   40 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib
> /PeiDxeSmmPchDmiWithS3Lib.inf                       |   40 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitCo
> mmonLib/PeiDxeSmmPchInitCommonLib.inf               |   34 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpr
> essHelpersLib/PeiDxeSmmPchPciExpressHelpersLib.inf |   42 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPriv
> ateLib/PeiDxeSmmPchPsfPrivateLibCnl.inf            |   41 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivat
> eLib/PeiDxeSmmPmcPrivateLibCnl.inf                  |   48 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivat
> eLib/PeiDxeSmmPmcPrivateLibWithS3.inf               |   39 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivat
> eLib/PeiPmcPrivateLibCnl.inf                        |   40 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/Pei
> GpioHelpersLib.inf                               |   42 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBufferLi
> b/PeiGpioNameBufferLib.inf                         |   35 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivat
> eLib/GpioNativePrivateLibInternal.h                |  477 ++++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib
> /PchDmi14.h                                         |   70 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib
> /PchDmi15.h                                         |  113 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpr
> essHelpersLib/PchPciExpressHelpersLibrary.h        |   42 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPriv
> ateLib/PchPsfPrivateLibInternal.h                  |  490 ++++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivat
> eLib/PmcPrivateLibInternal.h                        |   47 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivat
> eLib/GpioNamesCnl.c                                |  166 ++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivat
> eLib/GpioNativePrivateLib.c                        | 1304 +++++++++++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivat
> eLib/GpioNativePrivateLibCnl.c                     | 2275 ++++++++++++++++++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivat
> eLib/GpioPrivateLib.c                              |  752 ++++++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivat
> eLib/GpioPrivateLibCnl.c                           |  225 ++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib
> /PchDmi14.c                                         |   67 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib
> /PchDmi15.c                                         |  113 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib
> /PchDmiLib.c                                        |  569 +++++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib
> /PchDmiWithS3Lib.c                                  |   79 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitCo
> mmonLib/PchInitCommon.c                             |  221 ++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpr
> essHelpersLib/PchPciExpressHelpersLibrary.c        | 2407
> ++++++++++++++++++++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPriv
> ateLib/PchPsfPrivateLib.c                          |  542 +++++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPriv
> ateLib/PchPsfPrivateLibCnl.c                       |  338 +++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivat
> eLib/PeiPmcPrivateLib.c                             |   92 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivat
> eLib/PmcPrivateLib.c                                | 1033 +++++++++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivat
> eLib/PmcPrivateLibClient.c                          |   73 +
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivat
> eLib/PmcPrivateLibCnl.c                             |  360 +++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivat
> eLib/PmcPrivateLibWithS3.c                          |  194 ++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/Pei
> GpioHelpersLib.c                                 |  356 +++
> 
> Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBufferLi
> b/GpioNameBufferPei.c                              |   68 +
>  37 files changed, 12919 insertions(+)
> 
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/PeiDxeSmmGpioPrivateLibCnl.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/PeiDxeSmmGpioPrivateLibCnl.inf
> new file mode 100644
> index 0000000000..318b54a99c
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/PeiDxeSmmGpioPrivateLibCnl.inf
> @@ -0,0 +1,45 @@
> +## @file
> +#  Component description file for the PeiDxeSmmGpioPrivateLib
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION                    = 0x00010017
> +BASE_NAME                      = PeiDxeSmmGpioPrivateLibCnl
> +FILE_GUID                      = E078A734-BEA0-47CF-A476-3742316D01FC
> +VERSION_STRING                 = 1.0
> +MODULE_TYPE                    = BASE
> +LIBRARY_CLASS                  = GpioPrivateLib
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
> +#
> +
> +
> +[LibraryClasses]
> +  BaseLib
> +  IoLib
> +  DebugLib
> +  PmcLib
> +  PchInfoLib
> +  GpioLib
> +  GpioNameBufferLib
> +  SataLib
> +
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  CoffeelakeSiliconPkg/SiPkg.dec
> +
> +
> +[Sources]
> +  GpioPrivateLib.c
> +  GpioNativePrivateLib.c
> +  GpioPrivateLibCnl.c
> +  GpioNativePrivateLibCnl.c
> +  GpioNamesCnl.c
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PeiDxeSmmPchDmiLib.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PeiDxeSmmPchDmiLib.inf
> new file mode 100644
> index 0000000000..b36fc15901
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PeiDxeSmmPchDmiLib.inf
> @@ -0,0 +1,40 @@
> +## @file
> +#  Component description file for the PeiDxeSmmPchDmiLib
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION                    = 0x00010017
> +BASE_NAME                      = PeiDxeSmmPchDmiLib
> +FILE_GUID                      = 067DC1C4-2668-4F06-9921-307514B66B34
> +VERSION_STRING                 = 1.0
> +MODULE_TYPE                    = BASE
> +LIBRARY_CLASS                  = PchDmiLib
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[LibraryClasses]
> +  BaseLib
> +  IoLib
> +  DebugLib
> +  PchInfoLib
> +  PchPcrLib
> +
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  CoffeelakeSiliconPkg/SiPkg.dec
> +
> +
> +[Sources]
> +  PchDmiLib.c
> +  PchDmi14.c
> +  PchDmi15.c
> +
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PeiDxeSmmPchDmiWithS3Lib.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PeiDxeSmmPchDmiWithS3Lib.inf
> new file mode 100644
> index 0000000000..1eda7cdba8
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PeiDxeSmmPchDmiWithS3Lib.inf
> @@ -0,0 +1,40 @@
> +## @file
> +#  Component description file for the PeiDxeSmmPchDmiWithS3Lib
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION                    = 0x00010017
> +BASE_NAME                      = PeiDxeSmmPchDmiWithS3Lib
> +FILE_GUID                      = 32CCA047-6AF0-46FF-83DA-32BA62484075
> +VERSION_STRING                 = 1.0
> +MODULE_TYPE                    = BASE
> +LIBRARY_CLASS                  = PchDmiWithS3Lib
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[LibraryClasses]
> +  BaseLib
> +  IoLib
> +  DebugLib
> +  PchPcrLib
> +  PchInfoLib
> +  S3BootScriptLib
> +  PchDmiLib
> +
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  CoffeelakeSiliconPkg/SiPkg.dec
> +
> +
> +[Sources]
> +  PchDmiWithS3Lib.c
> +
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitC
> ommonLib/PeiDxeSmmPchInitCommonLib.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitC
> ommonLib/PeiDxeSmmPchInitCommonLib.inf
> new file mode 100644
> index 0000000000..d81c428a1c
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitC
> ommonLib/PeiDxeSmmPchInitCommonLib.inf
> @@ -0,0 +1,34 @@
> +## @file
> +#  Component description file for the PchInitCommonLib
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = PeiDxeSmmPchInitCommonLib
> +  FILE_GUID                      = E9C4FE04-8A79-43FA-B3E0-603359C31B43
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = PchInitCommonLib
> +
> +[Sources]
> +  PchInitCommon.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  CoffeelakeSiliconPkg/SiPkg.dec
> +
> +[LibraryClasses]
> +  IoLib
> +  DebugLib
> +  PciSegmentLib
> +  PchCycleDecodingLib
> +  PchPcieRpLib
> +  PchSbiAccessLib
> +  PchInfoLib
> +  SataLib
> +
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciEx
> pressHelpersLib/PeiDxeSmmPchPciExpressHelpersLib.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciEx
> pressHelpersLib/PeiDxeSmmPchPciExpressHelpersLib.inf
> new file mode 100644
> index 0000000000..16b1c019b8
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciEx
> pressHelpersLib/PeiDxeSmmPchPciExpressHelpersLib.inf
> @@ -0,0 +1,42 @@
> +## @file
> +# Component description file for the PeiDxeSmmPchPciExpressHelpersLib
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION = 0x00010017
> +BASE_NAME = PeiDxeSmmPchPciExpressHelpersLib
> +FILE_GUID = 07E3F76D-6D26-419d-9053-58696A15B519
> +VERSION_STRING = 1.0
> +MODULE_TYPE = BASE
> +LIBRARY_CLASS = PchPciExpressHelpersLib
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +# VALID_ARCHITECTURES = IA32 X64 IPF EBC
> +#
> +
> +
> +
> +[LibraryClasses]
> +IoLib
> +DebugLib
> +PchPcieRpLib
> +PchPcrLib
> +PchInfoLib
> +GpioLib
> +TimerLib
> +PchInitCommonLib
> +
> +[Packages]
> +MdePkg/MdePkg.dec
> +CoffeelakeSiliconPkg/SiPkg.dec
> +
> +
> +[Sources]
> +PchPciExpressHelpersLibrary.c
> +
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PeiDxeSmmPchPsfPrivateLibCnl.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PeiDxeSmmPchPsfPrivateLibCnl.inf
> new file mode 100644
> index 0000000000..0ed9f30dcc
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PeiDxeSmmPchPsfPrivateLibCnl.inf
> @@ -0,0 +1,41 @@
> +## @file
> +#  PEI/DXE/SMM PCH PSF Private Lib for Cannon Lake PCH
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION                    = 0x00010017
> +BASE_NAME                      = PeiDxeSmmPchPsfPrivateLibCnl
> +FILE_GUID                      = 7A6C18CA-0353-433E-885D-DD68BFAD38BE
> +VERSION_STRING                 = 1.0
> +MODULE_TYPE                    = BASE
> +LIBRARY_CLASS                  = PchPsfPrivateLib
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[LibraryClasses]
> +  BaseLib
> +  IoLib
> +  DebugLib
> +  PciSegmentLib
> +  PchInfoLib
> +  PchPcrLib
> +  SataLib
> +  SaPlatformLib
> +
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  CoffeelakeSiliconPkg/SiPkg.dec
> +
> +
> +[Sources]
> +  PchPsfPrivateLib.c
> +  PchPsfPrivateLibCnl.c
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiDxeSmmPmcPrivateLibCnl.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiDxeSmmPmcPrivateLibCnl.inf
> new file mode 100644
> index 0000000000..adb154dd14
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiDxeSmmPmcPrivateLibCnl.inf
> @@ -0,0 +1,48 @@
> +## @file
> +# PEI/DXE/SMM PCH PMC Private Lib for Cannon Lake PCH.
> +#
> +# All function in this library is available for PEI, DXE, and SMM,
> +# But do not support UEFI RUNTIME environment call.
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION = 0x00010017
> +BASE_NAME = PeiDxeSmmPmcPrivateLibCnl
> +FILE_GUID = A1CB52AD-4FAB-4214-94A0-323E3BE4E934
> +VERSION_STRING = 1.0
> +MODULE_TYPE = BASE
> +LIBRARY_CLASS = PmcPrivateLib
> +
> +
> +[LibraryClasses]
> +BaseLib
> +IoLib
> +DebugLib
> +TimerLib
> +PciSegmentLib
> +PchInfoLib
> +PchPcrLib
> +PmcLib
> +PchPsfPrivateLib
> +PchDmiLib
> +SataLib
> +BaseMemoryLib
> +
> +[Packages]
> +MdePkg/MdePkg.dec
> +CoffeelakeSiliconPkg/SiPkg.dec
> +
> +
> +[Pcd]
> +gSiPkgTokenSpaceGuid.PcdAcpiBaseAddress
> +
> +
> +[Sources]
> +PmcPrivateLib.c
> +PmcPrivateLibClient.c
> +PmcPrivateLibCnl.c
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiDxeSmmPmcPrivateLibWithS3.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiDxeSmmPmcPrivateLibWithS3.inf
> new file mode 100644
> index 0000000000..cd1380dc43
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiDxeSmmPmcPrivateLibWithS3.inf
> @@ -0,0 +1,39 @@
> +## @file
> +# PEI/DXE/SMM PCH private PMC Lib.
> +# This part of PMC lib includes S3BootScript support
> +#
> +# All function in this library is available for PEI, DXE, and SMM,
> +# But do not support UEFI RUNTIME environment call.
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION = 0x00010017
> +BASE_NAME = PeiDxeSmmPmcPrivateLibWithS3
> +FILE_GUID = 5890CA5A-1955-4A02-A09C-01E4150606CC
> +VERSION_STRING = 1.0
> +MODULE_TYPE = BASE
> +LIBRARY_CLASS = PmcPrivateLibWithS3
> +
> +
> +[LibraryClasses]
> +BaseLib
> +IoLib
> +DebugLib
> +PciSegmentLib
> +PmcLib
> +PcdLib
> +S3BootScriptLib
> +
> +
> +[Packages]
> +MdePkg/MdePkg.dec
> +CoffeelakeSiliconPkg/SiPkg.dec
> +
> +
> +[Sources]
> +PmcPrivateLibWithS3.c
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiPmcPrivateLibCnl.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiPmcPrivateLibCnl.inf
> new file mode 100644
> index 0000000000..ab3645c61d
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiPmcPrivateLibCnl.inf
> @@ -0,0 +1,40 @@
> +## @file
> +# PEI PCH PMC Private Lib for Cannon Lake PCH.
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION = 0x00010017
> +BASE_NAME = PeiPmcPrivateLibCnl
> +FILE_GUID = 1DD4EA23-12F2-4F05-93AF-535476106D8C
> +VERSION_STRING = 1.0
> +MODULE_TYPE = PEIM
> +LIBRARY_CLASS = PeiPmcPrivateLib
> +
> +
> +[LibraryClasses]
> +BaseLib
> +BaseMemoryLib
> +IoLib
> +DebugLib
> +PeiServicesLib
> +PciSegmentLib
> +ConfigBlockLib
> +PchInfoLib
> +PchPcrLib
> +PmcLib
> +PmcPrivateLib
> +PchEspiLib
> +GpioPrivateLib
> +PeiItssLib
> +
> +[Packages]
> +MdePkg/MdePkg.dec
> +CoffeelakeSiliconPkg/SiPkg.dec
> +
> +[Sources]
> +PeiPmcPrivateLib.c
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/
> PeiGpioHelpersLib.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/
> PeiGpioHelpersLib.inf
> new file mode 100644
> index 0000000000..b6f786d80b
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/
> PeiGpioHelpersLib.inf
> @@ -0,0 +1,42 @@
> +## @file
> +# Component description file for the PeiGpioHelpersLib
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION = 0x00010017
> +BASE_NAME = PeiGpioHelpersLib
> +FILE_GUID = 1838E1E7-3CC4-4A74-90D9-B421EF2A579F
> +VERSION_STRING = 1.0
> +MODULE_TYPE = PEIM
> +LIBRARY_CLASS = GpioHelpersLib
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +# VALID_ARCHITECTURES = IA32 X64 IPF EBC
> +#
> +
> +
> +[LibraryClasses]
> +BaseLib
> +IoLib
> +DebugLib
> +HobLib
> +GpioLib
> +
> +
> +[Packages]
> +MdePkg/MdePkg.dec
> +CoffeelakeSiliconPkg/SiPkg.dec
> +
> +
> +[Sources]
> +PeiGpioHelpersLib.c
> +
> +
> +[Guids]
> +gGpioLibUnlockHobGuid
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBuffer
> Lib/PeiGpioNameBufferLib.inf
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBuffer
> Lib/PeiGpioNameBufferLib.inf
> new file mode 100644
> index 0000000000..3619a2e6a7
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBuffer
> Lib/PeiGpioNameBufferLib.inf
> @@ -0,0 +1,35 @@
> +## @file
> +# Component description file for the PeiGpioMemLib
> +#
> +# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +INF_VERSION = 0x00010017
> +BASE_NAME = PeiGpioNameBufferLib
> +FILE_GUID = 16EC5CA8-8195-4847-B6CB-662CDAB863F2
> +VERSION_STRING = 1.0
> +MODULE_TYPE = PEIM
> +LIBRARY_CLASS = GpioNameBufferLib
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +# VALID_ARCHITECTURES = IA32
> +#
> +
> +[LibraryClasses]
> +HobLib
> +BaseLib
> +IoLib
> +DebugLib
> +
> +[Packages]
> +MdePkg/MdePkg.dec
> +CoffeelakeSiliconPkg/SiPkg.dec
> +
> +[Sources]
> +GpioNameBufferPei.c
> +
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNativePrivateLibInternal.h
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNativePrivateLibInternal.h
> new file mode 100644
> index 0000000000..e081027c40
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNativePrivateLibInternal.h
> @@ -0,0 +1,477 @@
> +/** @file
> +  Header file for GPIO Private Lib Internal functions.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _GPIO_NATIVE_PRIVATE_LIB_INTERNAL_H_
> +#define _GPIO_NATIVE_PRIVATE_LIB_INTERNAL_H_
> +
> +#include <Private/Library/GpioPrivateLib.h>
> +
> +#define GPIO_PAD_NONE 0
> +
> +/**
> +  This function provides SerialIo I2C controller pins
> +
> +  @param[in]  SerialIoI2cControllerNumber    I2C controller
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetSerialIoI2cPins (
> +  IN  UINT32                      SerialIoI2cControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  );
> +
> +/**
> +  This function provides SerialIo UART controller pins
> +
> +  @param[in]  SerialIoUartControllerNumber   UART controller
> +  @param[in]  HardwareFlowControl            Hardware Flow control
> +  @param[in]  PinMuxing                      UART controller pin muxing
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetSerialIoUartPins (
> +  IN  UINT32                      SerialIoUartControllerNumber,
> +  IN  BOOLEAN                     HardwareFlowControl,
> +  IN  UINT32                      PinMuxing,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  );
> +
> +/**
> +  This function provides SerialIo SPI controller pins
> +
> +  @param[in]  SerialIoSpiControllerNumber   SPI controller
> +
> +  @param[out] NativePinsTable               Table with pins
> +  @param[out] NoOfNativePins                Number of pins
> +**/
> +VOID
> +GpioGetSerialIoSpiPins (
> +  IN  UINT32                      SerialIoSpiControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  );
> +
> +/**
> +  This function provides ISH GP pin data
> +
> +  @param[in]  IshGpPinNumber        ISH GP pin number
> +
> +  @param[out] NativePin             ISH GP pin
> +**/
> +VOID
> +GpioGetIshGpPin (
> +  IN  UINT32                      IshGpPinNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    *NativePin
> +  );
> +
> +/**
> +  This function provides ISH UART controller pins
> +
> +  @param[in]  IshUartControllerNumber   ISH UART controller
> +
> +  @param[out] NativePinsTable           Table with pins
> +**/
> +VOID
> +GpioGetIshUartPins (
> +  IN  UINT32                      IshUartControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  );
> +
> +/**
> +  This function provides ISH I2C controller pins
> +
> +  @param[in]  IshI2cControllerNumber   ISH I2C controller
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetIshI2cPins (
> +  IN  UINT32                      IshI2cControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  );
> +
> +/**
> +  This function provides ISH SPI controller pins
> +
> +  @param[in]  IshSpiControllerNumber   SPI controller
> +  @param[out] NativePinsTable          Table with pins
> +  @param[out] NoOfNativePins           Number of pins
> +**/
> +VOID
> +GpioGetIshSpiPins (
> +  IN  UINT32                      IshSpiControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  );
> +
> +/**
> +  This function provides SCS SD CARD controller pins
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetScsSdCardPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  );
> +
> +/**
> +  This function provides SCS SD CARD detect pin
> +
> +  @retval GpioPin             SD CARD Detect pin
> +**/
> +GPIO_PAD
> +GpioGetScsSdCardDetectPin (
> +  VOID
> +  );
> +
> +/**
> +  This function provides SCS eMMC controller pins
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetScsEmmcPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  );
> +
> +/**
> +  This function provides HD Audio Link pins
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetHdAudioLinkPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  );
> +
> +/**
> +  This function provides DMIC interface pins
> +
> +  @param[in]  DmicNumber               DMIC interface
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetHdaDmicPins (
> +  IN  UINT32                      DmicNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  );
> +
> +/**
> +  This function provides SSP/I2S interface pins
> +
> +  @param[in]  SspInterfaceNumber       SSP/I2S interface
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetHdaSspPins (
> +  IN  UINT32                      SspInterfaceNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  );
> +
> +/**
> +  This function provides SNDW interface pins
> +
> +  @param[in]  SndwInterfaceNumber      SNDWx interface number
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetHdaSndwPins (
> +  IN  UINT32                      SndwInterfaceNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  );
> +
> +/**
> +  This function provides SMBUS interface pins
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetSmbusPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  );
> +
> +/**
> +  This function provides SATA DevSlp pin data
> +
> +  @param[in]  SataCtrlIndex       SATA controller index
> +  @param[in]  SataPort            SATA port number
> +  @param[out] NativePin           SATA DevSlp pin
> +**/
> +VOID
> +GpioGetSataDevSlpPin (
> +  IN  UINT32                    SataCtrlIndex,
> +  IN  UINTN                     SataPort,
> +  OUT GPIO_PAD_NATIVE_FUNCTION  *NativePin
> +  );
> +
> +/**
> +  This function provides PCIe CLKREQ pin data
> +
> +  @param[in]  ClkreqIndex        CLKREQ# number
> +  @param[out] NativePin          Native pin data
> +**/
> +VOID
> +GpioGetPcieClkReqPin (
> +  IN  UINT32                      ClkreqIndex,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    *NativePin
> +  );
> +
> +/**
> +  This function provides eDP pins
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetEdpPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  );
> +
> +/**
> +  This function provides DDPx interface pins
> +
> +  @param[in]  DdpInterface   DDPx interface
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetDdpPins (
> +  IN  GPIO_DDP                    DdpInterface,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  );
> +
> +/**
> +  This function provides CNVi BT UART pins
> +
> +  @param[in]  ConnectionType           CNVi BT UART connection type
> +  @param[out] VCnviBtUartPad           Table with vCNV_BT_UARTx pads
> +  @param[out] VCnviBtUartPadMode       vCNV_BT_UARTx pad mode
> +  @param[out] VUartForCnviBtPad        Table with vUART0 pads
> +  @param[out] VUartForCnviBtPadMode    vUART0 pad mode
> +**/
> +VOID
> +GpioGetCnviBtUartPins (
> +  IN  VGPIO_CNVI_BT_UART_CONNECTION_TYPE  ConnectionType,
> +  OUT GPIO_PAD                            **VCnviBtUartPad,
> +  OUT GPIO_PAD_MODE                       *VCnviBtUartPadMode,
> +  OUT GPIO_PAD                            **VUartForCnviBtPad,
> +  OUT GPIO_PAD_MODE                       *VUartForCnviBtPadMode
> +  );
> +
> +/**
> +  This function provides CNVi BT UART external pads
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetCnviBtUartExternalPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable
> +  );
> +
> +/**
> +  This function provides CNVi BT I2S pins
> +
> +  @param[in]  ConnectionType          CNVi BT I2S connection type
> +  @param[out] VCnviBtI2sPad           Table with vCNV_BT_I2Sx pads
> +  @param[out] VCnviBtI2sPadMode       vCNV_BT_I2Sx pad mode
> +  @param[out] VSspForCnviBtPad        Table with vSSP2 pads
> +  @param[out] VSspForCnviBtPadMode    vSSP2 pad mode
> +**/
> +VOID
> +GpioGetCnviBtI2sPins (
> +  IN  VGPIO_CNVI_BT_I2S_CONNECTION_TYPE  ConnectionType,
> +  OUT GPIO_PAD                 **VCnviBtI2sPad,
> +  OUT GPIO_PAD_MODE            *VCnviBtI2sPadMode,
> +  OUT GPIO_PAD                 **VSspForCnviBtPad,
> +  OUT GPIO_PAD_MODE            *VSspForCnviBtPadMode
> +  );
> +
> +/**
> +  This function provides CNVi BT I2S external pads
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetCnviBtI2sExternalPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable
> +  );
> +
> +/**
> +  This function provides CNVi MFUART1 pins
> +
> +  @param[in]  ConnectionType          CNVi MFUART1 connection type
> +  @param[out] VCnviBtI2sPad           Table with vCNV_MFUART1x pads
> +  @param[out] VCnviBtI2sPadMode       vCNV_MFUART1x pad mode
> +  @param[out] VSspForCnviBtPad        Table with vISH_UART0 pads
> +  @param[out] VSspForCnviBtPadMode    vISH_UART0 pad mode
> +**/
> +VOID
> +GpioGetCnviMfUart1Pins (
> +  IN  VGPIO_CNVI_MF_UART1_CONNECTION_TYPE  ConnectionType,
> +  OUT GPIO_PAD                 **VCnviMfUart1Pad,
> +  OUT GPIO_PAD_MODE            *VCnviMfUart1PadMode,
> +  OUT GPIO_PAD                 **VUartForCnviMfUart1Pad,
> +  OUT GPIO_PAD_MODE            *VUartForCnviMfUart1PadMode
> +  );
> +
> +/**
> +  This function provides CNVi MFUART1 external pads
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetCnviMfUart1ExternalPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable
> +  );
> +
> +/**
> +  This function provides CNVi Bluetooth Enable pad
> +
> +  @retval GpioPad           CNVi Bluetooth Enable pad
> +**/
> +GPIO_PAD
> +GpioGetCnviBtEnablePin (
> +  VOID
> +  );
> +
> +/**
> +  This function provides CNVi BRI RGI GPIO pads
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetCnvBriRgiPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable
> +  );
> +
> +/**
> +  This function provides CNVi MFUART2 external pins
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetCnvMfUart2ExternalPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable
> +  );
> +
> +/**
> +  This function provides CNVi BT interface select pin
> +
> +  @retval GpioPad          GPIO pad for CNVi BT interface select
> +**/
> +GPIO_PAD
> +GpioGetCnviBtIfSelectPin (
> +  VOID
> +  );
> +
> +/**
> +  This function provides CNVi BT Charging pin
> +
> +  @retval GpioPad          GPIO pad for CNVi BT Charging select
> +**/
> +GPIO_PAD
> +GpioGetCnviBtChargingPin (
> +  VOID
> +  );
> +
> +/**
> +  This function provides CNVi A4WP pin
> +
> +  @param[out] GpioNativePad       GPIO native pad for CNVi A4WP
> +**/
> +VOID
> +GpioGetCnviA4WpPin (
> +  OUT GPIO_PAD_NATIVE_FUNCTION  *GpioNativePad
> +  );
> +
> +/**
> +  This function provides CNVi BT host wake int pin
> +
> +  @retval GpioPad          GPIO pad BT host wake int
> +**/
> +GPIO_PAD
> +GpioGetCnviBtHostWakeIntPin (
> +  VOID
> +  );
> +
> +/**
> +  This function provides IMGCLKOUT pins
> +
> +  @param[out] NativePinsTable          Table with pins
> +  @param[out] NoOfNativePins            Number of pins
> +**/
> +VOID
> +GpioGetImgClkOutPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable,
> +  OUT UINT32                   *NoOfNativePins
> +  );
> +
> +/**
> +  This function provides PWRBTN pin
> +
> +  @retval GpioPad          PWRTBTN pin
> +**/
> +GPIO_PAD
> +GpioGetPwrBtnPin (
> +  VOID
> +  );
> +
> +/**
> +  This procedure enables debounce feature on a selected pad configured in
> input mode
> +  Debounce time can be specified in microseconds. GPIO HW supports only
> certain values
> +  according to below formula:
> +   DebounceTime = (2 ^ PADCFG_DW2.DEBOUNCE)*(glitch filter clock period).
> +  RTC clock with f = 32 KHz is used for glitch filter.
> +   DebounceTime = (2 ^ PADCFG_DW2.DEBOUNCE)*(31.25 us).
> +  Supported DebounceTime values are following:
> +   DebounceTime = 0 -> Debounce feature disabled
> +   DebounceTime > 0 && < 250us -> Not supported
> +   DebounceTime = 250us - 1024000us -> Supported range (DebounceTime =
> 250us * 2^n)
> +  For values not supported by GPIO HW, function will round down
> +  to closest supported
> +
> +  @param[in] GpioPad              GPIO pad
> +  @param[in, out] DebounceTime    Debounce Time in microseconds
> +                                  If Debounce Time = 0, Debouncer feature will be
> disabled
> +                                  Function will set DebounceTime argument to
> rounded supported value
> +
> +  @retval EFI_SUCCESS             The function completed successfully
> +  @retval EFI_INVALID_PARAMETER   Invalid GpioPad or unsupported
> DebounceDuration value
> +  @retval EFI_UNSUPPORTED         GpioPad is not owned by host
> +**/
> +EFI_STATUS
> +GpioSetDebounceTimer (
> +  IN GPIO_PAD                  GpioPad,
> +  IN OUT UINT32                *DebounceTime
> +  );
> +
> +/**
> +  This function provides LPC pin
> +
> +  @retval GpioPad          LPC pin
> +**/
> +GPIO_PAD
> +GpioGetLpcPin (
> +  VOID
> +  );
> +
> +#endif // _GPIO_NATIVE_PRIVATE_LIB_INTERNAL_H_
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi14.h
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi14.h
> new file mode 100644
> index 0000000000..1d50c04b0f
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi14.h
> @@ -0,0 +1,70 @@
> +/** @file
> +  Internal header file for PCH DMI library for SIP14
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef __PCH_DMI_14_H__
> +#define __PCH_DMI_14_H__
> +
> +#include <Private/Library/PchDmiLib.h>
> +#include <Private/Library/PeiPchDmiLib.h>
> +
> +/**
> +  This function checks if DMI SIP14 Secured Register Lock (SRL) is set
> +
> +  @retval SRL state
> +**/
> +BOOLEAN
> +IsPchDmi14Locked (
> +  VOID
> +  );
> +
> +/**
> +  Enable PCIe Relaxed Order for DMI SIP14
> +**/
> +VOID
> +PchDmi14EnablePcieRelaxedOrder (
> +  VOID
> +  );
> +
> +/**
> +  This function will switch SAI value to be driven to IOSF Primary Fabric
> +  for cycles with Core BDF from HOSTIA_BOOT_SAI to HOSTIA_POSTBOOT_SAI.
> +  To be used when PCH is paired with CFL CPU.
> +**/
> +VOID
> +PchDmi14EnablePostBootSai (
> +  VOID
> +  );
> +
> +/**
> + Secure Register Lock data
> +
> + @param[out] SrlRegOffset        Register offset holding Secure Register Lock
> setting
> + @param[out] SrlRegMask          Mask for Secure Register Lock setting
> +**/
> +VOID
> +PchDmi14SrlRegData (
> +  OUT UINT16  *SrlRegOffset,
> +  OUT UINT32  *SrlRegMask
> +  );
> +
> +/**
> +  Get PCH DMI SIP14 Virtual Channel Control and Status registers
> +
> +  @param[in]  Vc                   The virtual channel number for programing
> +  @param[out] DmiVcCtlAddress      DMI Virtual Channel Control register
> address
> +  @param[out] DmiVcStsAddress      DMI Virtual Channel Status register
> address
> +**/
> +VOID
> +PchDmi14VcRegs (
> +  IN   PCH_DMI_VC_TYPE  Vc,
> +  OUT  UINT16           *DmiVcCtlAddress,
> +  OUT  UINT16           *DmiVcStsAddress
> +  );
> +
> +
> +#endif
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi15.h
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi15.h
> new file mode 100644
> index 0000000000..744a96fe14
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi15.h
> @@ -0,0 +1,113 @@
> +/** @file
> +  Internal header file for PCH DMI library for SIP15
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef __PCH_DMI_15_H__
> +#define __PCH_DMI_15_H__
> +
> +#include <Private/Library/PchDmiLib.h>
> +#include <Private/Library/PeiPchDmiLib.h>
> +
> +/**
> +  This function checks if DMI SIP15 Secured Register Lock (SRL) is set
> +
> +  @retval SRL state
> +**/
> +BOOLEAN
> +IsPchDmi15Locked (
> +  VOID
> +  );
> +
> +/**
> +  Set DMI thermal throttling to recommended configuration.
> +  It's intended only for P-DMI SIP15.
> +**/
> +VOID
> +PchDmi15SetRecommendedThermalThrottling (
> +  VOID
> +  );
> +
> +/**
> +  Set DMI thermal throttling to custom configuration.
> +  This function will configure Thermal Sensor 0/1/2/3 TargetWidth and set
> +  DMI Thermal Sensor Autonomous Width Enable.
> +  It's intended only for P-DMI SIP15.
> +
> +  @param[in] DmiThermalThrottling        DMI Thermal Throttling structure.
> +**/
> +VOID
> +PchDmi15SetCustomThermalThrottling (
> +  IN DMI_THERMAL_THROTTLING      DmiThermalThrottling
> +  );
> +
> +/**
> +  Enable PCIe Relaxed Order for DMI SIP15
> +**/
> +VOID
> +PchDmi15EnablePcieRelaxedOrder (
> +  VOID
> +  );
> +
> +/**
> +  This function will switch SAI value to be driven to IOSF Primary Fabric
> +  for cycles with Core BDF from HOSTIA_BOOT_SAI to HOSTIA_POSTBOOT_SAI.
> +  To be used when PCH is paired with CFL CPU.
> +**/
> +VOID
> +PchDmi15EnablePostBootSai (
> +  VOID
> +  );
> +
> +/**
> +  This function will do necessary configuration after platform
> +  should have switched to POSTBOOT_SAI. It needs to be called even if
> +  POSTBOOT_SAI was not set.
> +**/
> +VOID
> +PchDmi15ConfigAfterPostBootSai (
> +  VOID
> +  );
> +
> +/**
> + Secure Register Lock data
> +
> + @param[out] SrlRegOffset        Register offset holding Secure Register Lock
> setting
> + @param[out] SrlRegMask          Mask for Secure Register Lock setting
> +**/
> +VOID
> +PchDmi15SrlRegData (
> +  OUT UINT16  *SrlRegOffset,
> +  OUT UINT32  *SrlRegMask
> +  );
> +
> +/**
> +  Get PCH DMI SIP15 Virtual Channel Control and Status registers
> +
> +  @param[in]  Vc                   The virtual channel number for programing
> +  @param[out] DmiVcCtlAddress      DMI Virtual Channel Control register
> address
> +  @param[out] DmiVcStsAddress      DMI Virtual Channel Status register
> address
> +**/
> +VOID
> +PchDmi15VcRegs (
> +  IN   PCH_DMI_VC_TYPE  Vc,
> +  OUT  UINT16           *DmiVcCtlAddress,
> +  OUT  UINT16           *DmiVcStsAddress
> +  );
> +
> +/**
> +  The function sets the Target Link Speed to GEN 3 in P-DMI SIP15.
> +
> +  @param[in] TargetLinkSpeed        Target Link Speed
> +                                    2: GEN2
> +                                    3: GEN3
> +**/
> +VOID
> +PchDmi15SetTargetLinkSpeed (
> +  IN  UINT8                 TargetLinkSpeed
> +  );
> +
> +#endif
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciEx
> pressHelpersLib/PchPciExpressHelpersLibrary.h
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciEx
> pressHelpersLib/PchPciExpressHelpersLibrary.h
> new file mode 100644
> index 0000000000..b14f24b18f
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciEx
> pressHelpersLib/PchPciExpressHelpersLibrary.h
> @@ -0,0 +1,42 @@
> +/** @file
> +  Header file for PCH Pci Express helps library implementation.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _PCH_PCI_EXPRESS_HELPERS_LIBRARY_H_
> +#define _PCH_PCI_EXPRESS_HELPERS_LIBRARY_H_
> +
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/BaseLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <IndustryStandard/Pci.h>
> +#include <PchPolicyCommon.h>
> +#include <Library/PchPcieRpLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/PciSegmentLib.h>
> +#include <Library/GpioNativeLib.h>
> +#include <Library/TimerLib.h>
> +#include <Private/Library/PchPciExpressHelpersLib.h>
> +#include <Private/Library/PchPsfPrivateLib.h>
> +#include <Private/Library/PchInitCommonLib.h>
> +#include <PcieRegs.h>
> +#include <Register/PchRegsPcie.h>
> +
> +#define LTR_VALUE_MASK (BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7
> + BIT8 + BIT9)
> +#define LTR_SCALE_MASK (BIT10 + BIT11 + BIT12)
> +
> +#define CONFIG_WRITE_LOOP_COUNT   100000
> +
> +//
> +// LTR related macros
> +//
> +#define LTR_LATENCY_VALUE(x)           ((x) & LTR_VALUE_MASK)
> +#define LTR_SCALE_VALUE(x)             (((x) & LTR_SCALE_MASK) >> 10)
> +#define LTR_LATENCY_NS(x)              (LTR_LATENCY_VALUE(x) * (1 << (5 *
> LTR_SCALE_VALUE(x))))
> +
> +#endif
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PchPsfPrivateLibInternal.h
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PchPsfPrivateLibInternal.h
> new file mode 100644
> index 0000000000..f633df0411
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PchPsfPrivateLibInternal.h
> @@ -0,0 +1,490 @@
> +/** @file
> +  This file contains internal header for PSF lib usage
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _PCH_PSF_PRIVATE_LIB_INTERNAL_H_
> +#define _PCH_PSF_PRIVATE_LIB_INTERNAL_H_
> +
> +#include <Private/Library/PchPsfPrivateLib.h>
> +#include <Register/PchRegsPcr.h>
> +
> +#define PSF_PORT_NULL ((PSF_PORT){0,0})
> +#define PSF_IS_PORT_NULL(PsfPort) ((PsfPort.PsfPid == 0) &&
> (PsfPort.RegBase == 0))
> +
> +/**
> +  Disable bridge (e.g. PCIe Root Port) at PSF level
> +
> +  @param[in] PsfPort  PSF PORT data structure
> +**/
> +VOID
> +PsfDisableBridge (
> +  IN PSF_PORT  PsfPort
> +  );
> +
> +/**
> +  Disable bridge (e.g. PCIe Root Port) at PSF level in RS3
> +
> +  @param[in] PsfPort  PSF PORT data structure
> +**/
> +VOID
> +PsfRs3DisableBridge (
> +  IN PSF_PORT  PsfPort
> +  );
> +
> +/**
> +  Check if bridge (e.g. PCIe Root Port) is enabled at PSF level
> +
> +  @param[in] PsfPort  PSF PORT data structure
> +
> +  @retval TRUE        Bridge behind PSF Port is enabled
> +          FALSE       Bridge behind PSF Port is disabled
> +**/
> +BOOLEAN
> +PsfIsBridgeEnabled (
> +  IN PSF_PORT  PsfPort
> +  );
> +
> +/**
> +  Disable device IOSpace at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +**/
> +VOID
> +PsfDisableDeviceIoSpace (
> +  IN PSF_PORT  PsfPort
> +  );
> +
> +/**
> +  Enable device IOSpace at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +**/
> +VOID
> +PsfEnableDeviceIoSpace (
> +  IN PSF_PORT  PsfPort
> +  );
> +
> +/**
> +  Disable device Memory Space at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +**/
> +VOID
> +PsfDisableDeviceMemSpace (
> +  IN PSF_PORT  PsfPort
> +  );
> +
> +/**
> +  Enable device Memory Space at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +**/
> +VOID
> +PsfEnableDeviceMemSpace (
> +  IN PSF_PORT  PsfPort
> +  );
> +
> +/**
> +  Set device BARx address at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +  @param[in] BarNum      BAR Number (0:BAR0, 1:BAR1, ...)
> +  @param[in] BarValue    32bit BAR value
> +**/
> +VOID
> +PsfSetDeviceBarValue (
> +  IN PSF_PORT  PsfPort,
> +  IN UINT8     BarNum,
> +  IN UINT32    BarValue
> +  );
> +
> +/**
> +  Return PSF_PORT for TraceHub device
> +
> +  @retval    PsfPort         PSF PORT structure for TraceHub device
> +**/
> +PSF_PORT
> +PsfTraceHubPort (
> +  VOID
> +  );
> +
> +/**
> +  This procedure will return PSF_PORT for TraceHub ACPI device
> +
> +  @retval    PsfPort         PSF PORT structure for TraceHub ACPI device
> +**/
> +PSF_PORT
> +PsfTraceHubAcpiDevPort (
> +  VOID
> +  );
> +
> +/**
> +  Return PSF_PORT for HECI device
> +
> +  @param[in] HeciDevice      HECIx Device (HECI1-4)
> +
> +  @retval    PsfPort         PSF PORT structure for HECI device
> +**/
> +PSF_PORT
> +PsfHeciPort (
> +  IN UINT8      HeciDevice
> +  );
> +
> +/**
> +  This procedure will return PSF_PORT for SOL device
> +
> +  @retval    PsfPort         PSF PORT structure for SOL device
> +**/
> +PSF_PORT
> +PsfSolPort (
> +  VOID
> +  );
> +
> +/**
> +  Return PSF_PORT for ISH device
> +
> +  @retval    PsfPort         PSF PORT structure for ISH device
> +**/
> +PSF_PORT
> +PsfIshPort (
> +  VOID
> +  );
> +
> +/**
> +  Return PSF_PORT for CNVi device
> +
> +  @retval    PsfPort         PSF PORT structure for CNVi device
> +**/
> +PSF_PORT
> +PsfCnviPort (
> +  VOID
> +  );
> +
> +/**
> +  Return PSF_PORT for PMC device
> +
> +  @retval    PsfPort         PSF PORT structure for PMC device
> +**/
> +PSF_PORT
> +PsfPmcPort (
> +  VOID
> +  );
> +
> +/**
> +  Return second level PSF_PORT to which PCIE Root Port device is connected
> (directly)
> +
> +  @param[in] RpIndex        PCIe Root Port Index (0 based)
> +
> +  @retval    PsfPort        PSF PORT structure for PCIe
> +**/
> +PSF_PORT
> +PsfPcieSecondLevelPort (
> +  IN UINT32  RpIndex
> +  );
> +
> +/**
> +  Return PSF_PORT at root PSF level to which PCIe Root Port device is
> connected
> +
> +  @param[in] RpIndex        PCIe Root Port Index (0 based)
> +
> +  @retval    PsfPort        PSF PORT structure for PCIe
> +
> +**/
> +PSF_PORT
> +PsfRootPciePort (
> +  IN UINT32  RpIndex
> +  );
> +
> +/**
> +  Return RS3 PSF_PORT at root PSF level to which PCIe Root Port device is
> connected
> +
> +  @param[in] RpIndex        PCIe Root Port Index (0 based)
> +
> +  @retval    PsfPort        PSF PORT structure for PCIe
> +**/
> +PSF_PORT
> +PsfRootRs3PciePort (
> +  IN UINT32  RpIndex
> +  );
> +
> +/**
> +  Check if PCIe Root Port is enabled
> +
> +  @param[in] RpIndex        PCIe Root Port Index (0 based)
> +
> +  @retval TRUE              PCIe Root Port is enabled
> +          FALSE             PCIe Root Port is disabled
> +**/
> +BOOLEAN
> +PsfIsPcieRootPortEnabled (
> +  IN UINT32  RpIndex
> +  );
> +
> +//
> +// Type of enpoint connected to PSF port.
> +// PsfNullPort is used for ports which do not exist
> +//
> +typedef enum {
> +  PsfNullPort,
> +  PsfToPsfPort,
> +  PsfPcieCtrlPort
> +} PSF_TOPO_PORT_TYPE;
> +
> +//
> +// Structure for storing information on location in PSF topology
> +// Every PSF node is identified by PsfID and PsfPortId
> +//
> +typedef struct {
> +  UINT8         PsfId;
> +  UINT8         PortId;
> +} PSF_TOPO_PORT;
> +
> +#define PSF_TOPO_PORT_NULL ((PSF_TOPO_PORT){0, 0})
> +#define PSF_IS_TOPO_PORT_NULL(PsfTopoPort) (((PsfTopoPort).PsfId == 0)
> && ((PsfTopoPort).PortId == 0))
> +
> +//
> +// This is optional field containing PSF port specific data
> +//
> +typedef union {
> +  UINT32  PcieCtrlIndex;
> +} PSF_TOPO_PORT_DATA;
> +
> +//
> +// Structure representing PSF port in PSF topology
> +// If port is of PsfToPsfPort type Child will point to the first
> +// port of sub PSF segment.
> +//
> +typedef struct PSF_TOPOLOGY {
> +  PSF_TOPO_PORT              PsfPort;
> +  PSF_TOPO_PORT_TYPE         PortType;
> +  CONST struct PSF_TOPOLOGY  *Child;
> +  PSF_TOPO_PORT_DATA         PortData;
> +} PSF_TOPOLOGY;
> +
> +//
> +// Tag for identifying last element of PSF_TOPOLOGY type array
> +//
> +#define PSF_TOPOLOGY_END   {{0, 0}, PsfNullPort, NULL}
> +
> +/**
> +  Get PSF Pcie Tree topology
> +
> +  @param[in] PsfTopology          PSF Port from PSF PCIe tree topology
> +
> +  @retval PsfTopology             PSF PCIe tree topology
> +**/
> +CONST PSF_TOPOLOGY*
> +PsfGetRootPciePsfTopology (
> +  VOID
> +  );
> +
> +//
> +// Structure for storing data on PCIe controller to PSF assignment and
> GrantCount register offsets
> +//
> +typedef struct {
> +  PCH_SBI_PID  PsfPid;
> +  UINT16       DevGntCnt0Base;
> +  UINT16       TargetGntCntPg1Tgt0Base;
> +} PSF_GRANT_COUNT_REG;
> +
> +/**
> +  Grant count regs data for PSF that is directly connected to PCIe Root Ports
> +
> +  @param[in]  Controller     PCIe Root Port Controller index (0 based)
> +  @param[out] GrantCountReg  Structure with PSF Grant Count register data
> +**/
> +VOID
> +PsfPcieGrantCountBaseReg (
> +  IN  UINT8                Controller,
> +  OUT PSF_GRANT_COUNT_REG  *GrantCountReg
> +  );
> +
> +/**
> +  Get Grant Count number (Device Grant Count and Target Grant Count)
> +  for PSF that is directly connected to PCIe Root Ports
> +
> +  @param[in]  Controller    PCIe Root Port Controller index
> +  @param[in]  Channel       PCIe Root Port Channel index
> +  @param[out] DgcrNo        Device Grant Count number
> +  @param[out] PgTgtNo       Target Grant Count number
> +**/
> +VOID
> +PsfPcieGrantCountNumber (
> +  IN  UINT8 Controller,
> +  IN  UINT8 Channel,
> +  OUT UINT8 *DgcrNo,
> +  OUT UINT8 *PgTgtNo
> +  );
> +
> +/**
> +  Grant count regs data for a given PSF-to-PSF port.
> +
> +  @param[in] PsfTopoPort         PSF-to-PSF port
> +
> +  @param[out] GrantCountReg      Structure with PSF Grant Count register
> data
> +**/
> +VOID
> +PsfSegmentGrantCountBaseReg (
> +  IN PSF_TOPO_PORT         PsfTopoPort,
> +  OUT PSF_GRANT_COUNT_REG  *GrantCountReg
> +  );
> +
> +/**
> +  Grant Count number (Device Grant Count and Target Grant Count) for a
> given PSF-to-PSF port.
> +
> +  @param[in] PsfTopoPort         PSF-to-PSF port
> +  @param[out] DgcrNo             Device Grant Count number
> +  @param[out] PgTgtNo            Target Grant Count number
> +**/
> +VOID
> +PsfSegmentGrantCountNumber (
> +  IN PSF_TOPO_PORT PsfTopoPort,
> +  OUT UINT8        *DgcrNo,
> +  OUT UINT8        *PgTgtNo
> +  );
> +
> +//
> +// Do not override PSF Grant Count value and leave HW default setting
> +//
> +#define DEFAULT_PCIE_GRANT_COUNT 0xFF
> +
> +typedef struct {
> +  UINT32       Id;
> +  PCH_SBI_PID  SbPid;
> +} PSF_SEGMENT;
> +
> +/**
> +  Get list of supported PSF segments.
> +
> +  @param[out] PsfTable        Array of supported PSF segments
> +  @param[out] PsfTableLength  Length of PsfTable
> +**/
> +VOID
> +PsfSegments (
> +  OUT PSF_SEGMENT  **PsfTable,
> +  OUT UINT32       *PsfTableLength
> +  );
> +
> +/**
> +  Get PSF SideBand Port ID from PSF ID (1 - PSF1, 2 - PSF2, ...)
> +
> +  @param[in] PsfId             PSF ID (1 - PSF1, 2 - PSF2, ...)
> +
> +  @retval PSF SideBand Port ID
> +**/
> +PCH_SBI_PID
> +PsfSbPortId (
> +  UINT32        PsfId
> +  );
> +
> +/**
> +  Get EOI register data for given PSF ID
> +
> +  @param[in]  PsfId           PSF ID (1 - PSF1, 2 - PSF2, ...)
> +  @param[out] EoiTargetBase   EOI Target register
> +  @param[out] EoiControlBase  EOI Control register
> +
> +  @retval MaxTargets          Number of supported targets
> +
> +**/
> +UINT8
> +PsfEoiRegData (
> +  UINT32        PsfId,
> +  UINT16        *EoiTargetBase,
> +  UINT16        *EoiControlBase
> +  );
> +
> +/**
> +  Get MCTP register data for given PSF ID
> +
> +  @param[in]  PsfId            PSF ID (1 - PSF1, 2 - PSF2, ...)
> +  @param[out] MctpTargetBase   MCTP Target register
> +  @param[out] MctpControlBase  MCTP Control register
> +
> +  @retval MaxTargets           Number of supported targets
> +
> +**/
> +UINT8
> +PsfMctpRegData (
> +  UINT32        PsfId,
> +  UINT16        *MctpTargetBase,
> +  UINT16        *MctpControlBase
> +  );
> +
> +/**
> +  P2SB PSF port Destination ID (psf_id:port_group_id:port_id:channel_id)
> +
> +  @retval P2SB Destination ID
> +**/
> +PSF_PORT_DEST_ID
> +PsfP2sbDestinationId (
> +  VOID
> +  );
> +
> +/**
> +  DMI PSF port Destination ID (psf_id:port_group_id:port_id:channel_id)
> +
> +  @retval DMI Destination ID
> +**/
> +PSF_PORT_DEST_ID
> +PsfDmiDestinationId (
> +  VOID
> +  );
> +
> +/**
> +  Check if MCTP is supported
> +
> +  @retval TRUE              MCTP is supported
> +          FALSE             MCTP is not supported
> +**/
> +BOOLEAN
> +PsfIsMctpSupported (
> +  VOID
> +  );
> +
> +/**
> +  Return the PSF (Root level) Function Config PSF_PORT for PCIe Root Port
> +
> +  @param[in] RpIndex        PCIe Root Port Index (0 based)
> +
> +  @retval    PsfPort        PSF PORT structure for PCIe Function Config
> +**/
> +PSF_PORT
> +PsfRootPcieFunctionConfigPort (
> +  IN UINT32  RpIndex
> +  );
> +
> +/**
> +  Return the PSF (Root level) RS3 Function Config PSF_PORT for PCIe Root Port
> +
> +  @param[in] RpIndex        PCIe Root Port Index (0 based)
> +
> +  @retval    PsfPort        PSF PORT structure for PCIe Function Config
> +**/
> +PSF_PORT
> +PsfRootRs3PcieFunctionConfigPort (
> +  IN UINT32  RpIndex
> +  );
> +
> +/**
> +  Return the PSF Function Config Second Level PSF_PORT for PCIe Root Port
> +
> +  @param[in] RpIndex        PCIe Root Port Index (0 based)
> +
> +  @retval    PsfPort        PSF PORT structure for PCIe Function Config
> +**/
> +PSF_PORT
> +PsfPcieFunctionConfigSecondLevelPort (
> +  IN UINT32  RpIndex
> +  );
> +
> +#endif
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibInternal.h
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibInternal.h
> new file mode 100644
> index 0000000000..c08d1cf10d
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibInternal.h
> @@ -0,0 +1,47 @@
> +/** @file
> +  Internal header file for PMC Private library
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef _PMC_PRIVATE_LIB_INTERNAL_H_
> +#define _PMC_PRIVATE_LIB_INTERNAL_H_
> +
> +/**
> +  Check if MODPHY SUS PG is supported
> +
> +  @retval  Status of MODPHY SUS PG support
> +**/
> +BOOLEAN
> +PmcIsModPhySusPgSupported (
> +  VOID
> +  );
> +
> +/**
> +  This function is part of PMC init and configures which clock wake signals
> should
> +  set the SLOW_RING, SA, FAST_RING_CF and SLOW_RING_CF indication sent
> up to the CPU/PCH
> +**/
> +VOID
> +PmcInitClockWakeEnable (
> +  VOID
> +  );
> +
> +/**
> +  This function configures PWRMBASE + 0x1E00 register
> +**/
> +VOID
> +PmcConfigureRegPwrm1E00 (
> +  VOID
> +  );
> +
> +/**
> +  This function configures Misc PM_SYNC events settings
> +**/
> +VOID
> +PmcConfigurePmSyncEventsSettings (
> +  VOID
> +  );
> +
> +#endif
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNamesCnl.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNamesCnl.c
> new file mode 100644
> index 0000000000..5a4876bfeb
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNamesCnl.c
> @@ -0,0 +1,166 @@
> +/** @file
> +  This file contains GPIO name library implementation
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Library/BaseLib.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/DebugLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Private/Library/GpioPrivateLib.h>
> +#include <GpioPinsCnlLp.h>
> +#include <GpioPinsCnlH.h>
> +
> +STATIC CONST CHAR8*  mGpioGppaNames[] = {
> +  "ESPI_CLK_LOOPBK"
> +};
> +
> +STATIC CONST CHAR8*  mGpioGppbNames[] = {
> +  "GSPI0_CLK_LOOPBK",
> +  "GSPI1_CLK_LOOPBK"
> +};
> +
> +STATIC CONST CHAR8*  mGpioGpdNames[] = {
> +  "SLP_LANB",
> +  "SLP_SUSB",
> +  "SLP_WAKEB",
> +  "SLP_DRAM_RESETB"
> +};
> +
> +STATIC CONST CHAR8*  mGpioGppiNames[] = {
> +  "SYS_PWROK",
> +  "SYS_RESETB",
> +  "MLK_RSTB"
> +};
> +
> +STATIC CONST CHAR8*  mGpioSpiNames[] = {
> +  "SPI0_IO_2",
> +  "SPI0_IO_3",
> +  "SPI0_MOSI_IO_0",
> +  "SPI0_MOSI_IO_1",
> +  "SPI0_TPM_CSB",
> +  "SPI0_FLASH_0_CSB",
> +  "SPI0_FLASH_1_CSB",
> +  "SPI0_CLK",
> +  "SPI0_CLK_LOOPBK"
> +};
> +
> +STATIC CONST CHAR8*  mGpioAzaNames[] = {
> +  "HDA_BCLK",
> +  "HDA_RSTB",
> +  "HDA_SYNC",
> +  "HDA_SDO",
> +  "HDA_SDI_0",
> +  "HDA_SDI_1",
> +  "SSP1_SFRM",
> +  "SSP1_TXD"
> +};
> +
> +STATIC CONST CHAR8*  mGpioJtagNames[] = {
> +  "JTAG_TDO",
> +  "JTAGX",
> +  "PRDYB",
> +  "PREQB",
> +  "CPU_TRSTB",
> +  "JTAG_TDI",
> +  "JTAG_TMS",
> +  "JTAG_TCK",
> +  "ITP_PMODE"
> +};
> +
> +STATIC CONST CHAR8*  mGpioHvmosNames[] = {
> +  "HVMOS_L_BKLTEN",
> +  "HVMOS_L_BKLCTL",
> +  "HVMOS_L_VDDEN",
> +  "HVMOS_SYS_PWROK",
> +  "HVMOS_SYS_RESETB",
> +  "HVMOS_MLK_RSTB"
> +};
> +
> +STATIC CONST CHAR8*  mGpioCpuNames[] = {
> +  "HDACPU_SDI",
> +  "HDACPU_SDO",
> +  "HDACPU_SCLK",
> +  "PM_SYNC",
> +  "PECI",
> +  "CPUPWRGD",
> +  "THRMTRIPB",
> +  "PLTRST_CPUB",
> +  "PM_DOWN",
> +  "TRIGGER_IN",
> +  "TRIGGER_OUT"
> +};
> +
> +STATIC CONST GPIO_GROUP_NAME_INFO  mPchLpGroupDescriptors[] = {
> +  GPIO_GROUP_NAME("GPP_A", GPIO_CNL_LP_ESPI_CLK_LOOPBK,
> mGpioGppaNames),
> +  GPIO_GROUP_NAME("GPP_B", GPIO_CNL_LP_GSPI0_CLK_LOOPBK,
> mGpioGppbNames),
> +  GPIO_GROUP_NAME_BASIC("GPP_C"),
> +  GPIO_GROUP_NAME_BASIC("GPP_D"),
> +  GPIO_GROUP_NAME_BASIC("GPP_E"),
> +  GPIO_GROUP_NAME_BASIC("GPP_F"),
> +  GPIO_GROUP_NAME_BASIC("GPP_G"),
> +  GPIO_GROUP_NAME_BASIC("GPP_H"),
> +  GPIO_GROUP_NAME("GPD", GPIO_CNL_LP_SLP_LANB, mGpioGpdNames),
> +  GPIO_GROUP_NAME_BASIC("VGPIO"),
> +  GPIO_GROUP_NAME("SPI", GPIO_CNL_LP_SPI0_IO_2, mGpioSpiNames),
> +  GPIO_GROUP_NAME("AZA", GPIO_CNL_LP_HDA_BCLK, mGpioAzaNames),
> +  GPIO_GROUP_NAME("CPU", GPIO_CNL_LP_HDACPU_SDI,
> mGpioCpuNames),
> +  GPIO_GROUP_NAME("JTAG", GPIO_CNL_LP_JTAG_TDO, mGpioJtagNames),
> +  GPIO_GROUP_NAME("HVMOS", GPIO_CNL_LP_HVMOS_L_BKLTEN,
> mGpioHvmosNames)
> +};
> +
> +STATIC CONST GPIO_GROUP_NAME_INFO  mPchHGroupDescriptors[] = {
> +  GPIO_GROUP_NAME("GPP_A", GPIO_CNL_H_ESPI_CLK_LOOPBK,
> mGpioGppaNames),
> +  GPIO_GROUP_NAME("GPP_B", GPIO_CNL_H_GSPI0_CLK_LOOPBK,
> mGpioGppbNames),
> +  GPIO_GROUP_NAME_BASIC("GPP_C"),
> +  GPIO_GROUP_NAME_BASIC("GPP_D"),
> +  GPIO_GROUP_NAME_BASIC("GPP_E"),
> +  GPIO_GROUP_NAME_BASIC("GPP_F"),
> +  GPIO_GROUP_NAME_BASIC("GPP_G"),
> +  GPIO_GROUP_NAME_BASIC("GPP_H"),
> +  GPIO_GROUP_NAME("GPP_I", GPIO_CNL_H_SYS_PWROK,
> mGpioGppiNames),
> +  GPIO_GROUP_NAME_BASIC("GPP_J"),
> +  GPIO_GROUP_NAME_BASIC("GPP_K"),
> +  GPIO_GROUP_NAME("GPD", GPIO_CNL_H_SLP_LANB, mGpioGpdNames),
> +  GPIO_GROUP_NAME_BASIC("VGPIO"),
> +  GPIO_GROUP_NAME("SPI", GPIO_CNL_H_SPI0_IO_2, mGpioSpiNames),
> +  GPIO_GROUP_NAME("AZA", GPIO_CNL_H_HDA_BCLK, mGpioAzaNames),
> +  GPIO_GROUP_NAME("CPU", GPIO_CNL_H_HDACPU_SDI,
> mGpioCpuNames),
> +  GPIO_GROUP_NAME("JTAG", GPIO_CNL_H_JTAG_TDO, mGpioJtagNames),
> +};
> +
> +/**
> +  Returns GPIO_GROUP_NAME_INFO corresponding to the given GpioPad
> +
> +  @param[in] GroupIndex  Group index
> +
> +  @retval GPIO_GROUP_NAME_INFO*  Pointer to the
> GPIO_GROUP_NAME_INFO
> +  @reval  NULL                   If no group descriptor was found
> +**/
> +CONST
> +GPIO_GROUP_NAME_INFO*
> +GpioGetGroupNameInfo (
> +  IN UINT32  GroupIndex
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (GroupIndex < ARRAY_SIZE (mPchLpGroupDescriptors)) {
> +      return &mPchLpGroupDescriptors[GroupIndex];
> +    } else {
> +      ASSERT (FALSE);
> +      return NULL;
> +    }
> +  } else {
> +    if (GroupIndex < ARRAY_SIZE (mPchHGroupDescriptors)) {
> +      return &mPchHGroupDescriptors[GroupIndex];
> +    } else {
> +      ASSERT (FALSE);
> +      return NULL;
> +    }
> +  }
> +}
> +
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNativePrivateLib.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNativePrivateLib.c
> new file mode 100644
> index 0000000000..affecf9ec0
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNativePrivateLib.c
> @@ -0,0 +1,1304 @@
> +/** @file
> +  This file contains routines for GPIO native and chipset specific purpose
> +  used by Reference Code only.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Library/BaseLib.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <SaAccess.h>
> +#include <Library/GpioLib.h>
> +#include <Library/GpioNativeLib.h>
> +#include <Private/Library/GpioPrivateLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/SataLib.h>
> +#include "GpioNativePrivateLibInternal.h"
> +#include <Register/PchRegsGpio.h>
> +#include <Register/PchRegsSerialIo.h>
> +#include <Register/PchRegsIsh.h>
> +
> +/**
> +  This function sets SerialIo I2C controller pins into native mode
> +
> +  @param[in]  SerialIoI2cControllerNumber   I2C controller
> +  @param[in]  GpioTermination               GPIO termination type
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableSerialIoI2c (
> +  IN  UINT32                  SerialIoI2cControllerNumber,
> +  IN  GPIO_ELECTRICAL_CONFIG  GpioTermination
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINT32                   Index;
> +  GPIO_PAD_NATIVE_FUNCTION *I2cGpio;
> +  GPIO_CONFIG              GpioConfig;
> +
> +  GpioGetSerialIoI2cPins (
> +    SerialIoI2cControllerNumber,
> +    &I2cGpio
> +    );
> +
> +  if (I2cGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  ZeroMem(&GpioConfig, sizeof(GPIO_CONFIG));
> +  GpioConfig.ElectricalConfig = GpioTermination;
> +
> +  for (Index = 0; Index < PCH_SERIAL_IO_PINS_PER_I2C_CONTROLLER; Index++)
> {
> +    GpioConfig.PadMode          = I2cGpio[Index].Mode;
> +
> +    Status = GpioSetPadConfig(I2cGpio[Index].Pad, &GpioConfig);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets SerialIo UART controller pins into native mode
> +
> +  @param[in]  SerialIoUartControllerNumber   UART controller
> +  @param[in]  HardwareFlowControl            Hardware Flow control
> +  @param[in]  PinMuxing                      UART controller pin muxing
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableSerialIoUart (
> +  IN  UINT32            SerialIoUartControllerNumber,
> +  IN  BOOLEAN           HardwareFlowControl,
> +  IN  UINT32            PinMuxing
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINT32                   Index;
> +  UINT32                   PinsUsed;
> +  GPIO_PAD_NATIVE_FUNCTION *UartGpio;
> +
> +  GpioGetSerialIoUartPins (
> +    SerialIoUartControllerNumber,
> +    HardwareFlowControl,
> +    PinMuxing,
> +    &UartGpio,
> +    &PinsUsed
> +    );
> +
> +  if (UartGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < PinsUsed; Index++) {
> +    Status = GpioSetPadMode (UartGpio[Index].Pad, UartGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +    GpioSetInputInversion (UartGpio[Index].Pad, 0);
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets SerialIo SPI controller pins into native mode
> +
> +  @param[in]  SerialIoSpiControllerNumber   SPI controller
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableSerialIoSpi (
> +  IN  UINT32            SerialIoSpiControllerNumber
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINTN                    Index;
> +  GPIO_PAD_NATIVE_FUNCTION *SpiGpio;
> +  UINT32                   NumOfSpiPins;
> +
> +  GpioGetSerialIoSpiPins (
> +    SerialIoSpiControllerNumber,
> +    &SpiGpio,
> +    &NumOfSpiPins
> +    );
> +
> +  if (SpiGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < NumOfSpiPins; Index++) {
> +    Status = GpioSetPadMode (SpiGpio[Index].Pad, SpiGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +    GpioSetInputInversion (SpiGpio[Index].Pad, 0);
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets ISH I2C controller pins into native mode
> +
> +  @param[in]  IshI2cControllerNumber   I2C controller
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableIshI2c (
> +  IN  UINT32            IshI2cControllerNumber
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINTN                    Index;
> +  GPIO_PAD_NATIVE_FUNCTION *I2cGpio;
> +
> +  GpioGetIshI2cPins (
> +    IshI2cControllerNumber,
> +    &I2cGpio
> +    );
> +
> +  if (I2cGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < PCH_ISH_PINS_PER_I2C_CONTROLLER; Index++) {
> +    Status = GpioSetPadMode (I2cGpio[Index].Pad, I2cGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets ISH UART controller pins into native mode
> +
> +  @param[in]  IshUartControllerNumber   UART controller
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableIshUart (
> +  IN  UINT32            IshUartControllerNumber
> +  )
> +{
> +  EFI_STATUS                Status;
> +  UINTN                     Index;
> +  GPIO_PAD_NATIVE_FUNCTION  *UartGpio;
> +
> +  GpioGetIshUartPins (
> +    IshUartControllerNumber,
> +    &UartGpio
> +    );
> +
> +  if (UartGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < PCH_ISH_PINS_PER_UART_CONTROLLER; Index++) {
> +    Status = GpioSetPadMode (UartGpio[Index].Pad, UartGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets ISH SPI controller pins into native mode
> +
> +  @param[in]  IshSpiControllerNumber   SPI controller
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableIshSpi (
> +  IN  UINT32            IshSpiControllerNumber
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINTN                    Index;
> +  GPIO_PAD_NATIVE_FUNCTION *SpiGpio;
> +  UINT32                   NumOfSpiPins;
> +
> +  GpioGetIshSpiPins (
> +    IshSpiControllerNumber,
> +    &SpiGpio,
> +    &NumOfSpiPins
> +    );
> +
> +  if (SpiGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < NumOfSpiPins; Index++) {
> +    Status = GpioSetPadMode (SpiGpio[Index].Pad, SpiGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets ISH GP pin into native mode
> +
> +  @param[in]  IshGpPinNumber   ISH GP pin number
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableIshGpPin (
> +  IN  UINT32            IshGpPinNumber
> +  )
> +{
> +  EFI_STATUS               Status;
> +  GPIO_PAD_NATIVE_FUNCTION IshGp;
> +
> +  GpioGetIshGpPin (
> +    IshGpPinNumber,
> +    &IshGp
> +    );
> +
> +  Status = GpioSetPadMode (IshGp.Pad, IshGp.Mode);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets SCS SD card controller pins into native mode
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableScsSdCard (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                Status;
> +  UINTN                     Index;
> +  GPIO_PAD_NATIVE_FUNCTION  *SdCardGpio;
> +  UINT32                    NumOfSdCardPins;
> +  GPIO_CONFIG               PwrEnConfig;
> +
> +  GpioGetScsSdCardPins (
> +    &SdCardGpio,
> +    &NumOfSdCardPins
> +    );
> +
> +  if (SdCardGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // We need to leave the PWREN#
> +  // GPIO pad unlocked since it is controlled at runtime
> +  // by ACPI code. It is a work around for our SD card
> +  // controller not respecting PWREN# invertion settings
> +  // during D3. Since this pad will be in GPIO mode when
> +  // SD controller is in D3 we need to set correct pad config.
> +  //
> +  GpioUnlockPadCfg (SdCardGpio[0].Pad);
> +  GpioGetPadConfig (SdCardGpio[0].Pad, &PwrEnConfig);
> +  PwrEnConfig.PadMode = SdCardGpio[0].Mode;
> +  PwrEnConfig.Direction = GpioDirOut;
> +  PwrEnConfig.HostSoftPadOwn = GpioHostOwnAcpi;
> +  PwrEnConfig.InterruptConfig = GpioIntDis;
> +  PwrEnConfig.PowerConfig = GpioHostDeepReset;
> +  PwrEnConfig.LockConfig = GpioPadUnlock;
> +  GpioSetPadConfig (SdCardGpio[0].Pad, &PwrEnConfig);
> +
> +  for (Index = 1; Index < NumOfSdCardPins; Index++) {
> +    Status = GpioSetPadMode (SdCardGpio[Index].Pad,
> SdCardGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +    //
> +    // SD Card Pins GPP_G0 - G4 require Native Termination
> +    // Index in mPch[Lp/H]ScsSdCardGpio (depends on
> mPch[Lp/H]ScsSdCardGpio internal organization):
> +    // GPP_G0 = 1
> +    // GPP_G4 = 5
> +    //
> +    if (Index >= 1 && Index <= 5) {
> +      Status = GpioSetPadElectricalConfig (SdCardGpio[Index].Pad,
> GpioTermNative);
> +      ASSERT_EFI_ERROR (Status);
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function enables SCS Sd Card controller card detect pin
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableScsSdCardDetect (
> +  VOID
> +  )
> +{
> +  GPIO_CONFIG   PadConfig;
> +  GPIO_PAD      GpioPad;
> +
> +  ZeroMem (&PadConfig, sizeof (PadConfig));
> +
> +  ///
> +  /// vSD3_CD_B line is driven by GPPC_G_5_SD3_CDB
> +  /// and is used for interrupt for card detect event.
> +  /// GPPC_G_5_SD3_CDB cannot be used for interrupt because this pin
> +  /// is in native mode.
> +  ///
> +  GpioPad = GpioGetScsSdCardDetectPin ();
> +  PadConfig.PadMode         = GpioPadModeGpio;
> +  PadConfig.Direction       = GpioDirIn;
> +  PadConfig.HostSoftPadOwn  = GpioHostOwnGpio;
> +  PadConfig.InterruptConfig = GpioIntBothEdge;
> +  PadConfig.PowerConfig     = GpioHostDeepReset;
> +
> +  // Unlock GPIO pad due to Host Software Pad Ownership is GPIO Driver
> mode.
> +  GpioUnlockPadCfg (GpioPad);
> +
> +  return GpioSetPadConfig (GpioPad, &PadConfig);
> +}
> +
> +/**
> +  This function sets SCS eMMC controller pins into native mode
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableScsEmmc (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                Status;
> +  UINTN                     Index;
> +  GPIO_PAD_NATIVE_FUNCTION  *EmmcGpio;
> +  UINT32                    NumOfEmmcPins;
> +
> +  GpioGetScsEmmcPins (
> +    &EmmcGpio,
> +    &NumOfEmmcPins
> +    );
> +
> +  if (EmmcGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < NumOfEmmcPins; Index++) {
> +    Status = GpioSetPadMode (EmmcGpio[Index].Pad,
> EmmcGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets HDA Link pins into native mode
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableHdaLink (
> +  VOID
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINTN                    Index;
> +  GPIO_PAD_NATIVE_FUNCTION *HdaLinkGpio;
> +  UINT32                    NumOfHdaLinkPins;
> +
> +  GpioGetHdAudioLinkPins (
> +    &HdaLinkGpio,
> +    &NumOfHdaLinkPins
> +    );
> +
> +  if (HdaLinkGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < NumOfHdaLinkPins; Index++) {
> +    Status = GpioSetPadMode (HdaLinkGpio[Index].Pad,
> HdaLinkGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets HDA DMIC pins into native mode
> +
> +  @param[in]  DmicNumber   DMIC number
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableHdaDmic (
> +  IN  UINT32            DmicNumber
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINTN                    Index;
> +  GPIO_PAD_NATIVE_FUNCTION *DmicGpio;
> +
> +  GpioGetHdaDmicPins (
> +    DmicNumber,
> +    &DmicGpio
> +    );
> +
> +  if (DmicGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < PCH_GPIO_HDA_DMIC_NUMBER_OF_PINS; Index++)
> {
> +    Status = GpioSetPadMode (DmicGpio[Index].Pad,
> DmicGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets HDA SSP interface pins into native mode
> +
> +  @param[in]  SspInterfaceNumber   SSPx interface number
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableHdaSsp (
> +  IN  UINT32            SspInterfaceNumber
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINTN                    Index;
> +  GPIO_PAD_NATIVE_FUNCTION *SspGpio;
> +
> +  GpioGetHdaSspPins (
> +    SspInterfaceNumber,
> +    &SspGpio
> +    );
> +
> +  if (SspGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < PCH_GPIO_HDA_SSP_NUMBER_OF_PINS; Index++) {
> +    Status = GpioSetPadMode (SspGpio[Index].Pad, SspGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets HDA SoundWire interface pins into native mode
> +
> +  @param[in]  SndwInterfaceNumber   SNDWx interface number
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableHdaSndw (
> +  IN  UINT32            SndwInterfaceNumber
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINTN                    Index;
> +  GPIO_PAD_NATIVE_FUNCTION *SndwGpio;
> +
> +  GpioGetHdaSndwPins (
> +    SndwInterfaceNumber,
> +    &SndwGpio
> +    );
> +
> +  if (SndwGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < PCH_GPIO_HDA_SNDW_NUMBER_OF_PINS; Index++)
> {
> +    Status = GpioSetPadMode (SndwGpio[Index].Pad,
> SndwGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets SMBUS controller pins into native mode
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableSmbus (
> +  VOID
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINTN                    Index;
> +  GPIO_PAD_NATIVE_FUNCTION *SmbusGpio;
> +
> +  GpioGetSmbusPins (&SmbusGpio);
> +
> +  if (SmbusGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < PCH_GPIO_SMBUS_NUMBER_OF_PINS; Index++) {
> +    Status = GpioSetPadMode (SmbusGpio[Index].Pad,
> SmbusGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets SATA DevSlp pins into native mode
> +
> +  @param[in]  SataCtrlIndex       SATA controller index
> +  @param[in]  SataPort            SATA port number
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableSataDevSlpPin (
> +  IN  UINT32  SataCtrlIndex,
> +  IN  UINTN   SataPort
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION  DevSlpGpio;
> +
> +  GpioGetSataDevSlpPin (
> +    SataCtrlIndex,
> +    SataPort,
> +    &DevSlpGpio
> +    );
> +
> +  GpioSetPadResetConfig (DevSlpGpio.Pad, GpioResumeReset);
> +
> +  return GpioSetPadMode (DevSlpGpio.Pad, DevSlpGpio.Mode);
> +}
> +
> +/**
> +  This function checks if SataDevSlp pin is in native mode
> +
> +  @param[in]  SataCtrlIndex       SATA controller index
> +  @param[in]  SataPort            SATA port
> +  @param[out] DevSlpPad           DevSlpPad
> +                                  This is an optional parameter and may be NULL.
> +
> +  @retval TRUE                    DevSlp is in native mode
> +          FALSE                   DevSlp is not in native mode
> +**/
> +BOOLEAN
> +GpioIsSataDevSlpPinEnabled (
> +  IN  UINT32          SataCtrlIndex,
> +  IN  UINTN           SataPort,
> +  OUT GPIO_PAD        *DevSlpPad  OPTIONAL
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION  DevSlpNativePad;
> +  GPIO_PAD_MODE             GpioMode;
> +  EFI_STATUS                Status;
> +
> +  ASSERT (SataCtrlIndex < GetPchMaxSataControllerNum ());
> +
> +  GpioGetSataDevSlpPin (
> +    SataCtrlIndex,
> +    SataPort,
> +    &DevSlpNativePad
> +    );
> +
> +  Status = GpioGetPadMode (DevSlpNativePad.Pad, &GpioMode);
> +
> +  if (EFI_ERROR (Status) || (GpioMode != DevSlpNativePad.Mode)) {
> +    if (DevSlpPad != NULL) {
> +      *DevSlpPad = GPIO_PAD_NONE;
> +    }
> +    return FALSE;
> +  } else {
> +    if (DevSlpPad != NULL) {
> +      *DevSlpPad = DevSlpNativePad.Pad;
> +    }
> +    return TRUE;
> +  }
> +}
> +
> +/**
> +  This function sets SATAGPx pin into native mode
> +
> +  @param[in]  SataCtrlIndex       SATA controller index
> +  @param[in]  SataPort            SATA port number
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableSataGpPin (
> +  IN  UINT32  SataCtrlIndex,
> +  IN  UINTN   SataPort
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION  SataGpGpio;
> +
> +  GpioGetSataGpPin (
> +    SataCtrlIndex,
> +    SataPort,
> +    &SataGpGpio
> +    );
> +
> +  DEBUG_CODE_BEGIN ();
> +  GPIO_PAD_MODE  PadMode;
> +  GpioGetPadMode (SataGpGpio.Pad, &PadMode);
> +  if (PadMode == GpioPadModeNative1) {
> +    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Cannot enable SATAGP%d, %a
> already used for SATAXPCIE_%d\n",
> +        SataPort,
> +        GpioName (SataGpGpio.Pad),
> +        SataPort));
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +  DEBUG_CODE_END ();
> +
> +  return GpioSetPadMode (SataGpGpio.Pad, SataGpGpio.Mode);
> +}
> +
> +/**
> +  Returns a pad for given CLKREQ# index.
> +
> +  @param[in]  ClkreqIndex       CLKREQ# number
> +
> +  @return CLKREQ# pad.
> +**/
> +GPIO_PAD
> +GpioGetClkreqPad (
> +  IN     UINT32   ClkreqIndex
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION  ClkReqGpio;
> +
> +  GpioGetPcieClkReqPin (
> +    ClkreqIndex,
> +    &ClkReqGpio
> +    );
> +
> +  return ClkReqGpio.Pad;
> +}
> +
> +/**
> +  Enables CLKREQ# pad in native mode.
> +
> +  @param[in]  ClkreqIndex       CLKREQ# number
> +
> +  @return none
> +**/
> +VOID
> +GpioEnableClkreq (
> +  IN     UINT32   ClkreqIndex
> +  )
> +{
> +  GPIO_CONFIG               PadConfig;
> +  GPIO_PAD_NATIVE_FUNCTION  ClkReqGpio;
> +
> +  ZeroMem (&PadConfig, sizeof (PadConfig));
> +
> +  GpioGetPcieClkReqPin (
> +    ClkreqIndex,
> +    &ClkReqGpio
> +    );
> +
> +  PadConfig.PadMode      = ClkReqGpio.Mode;
> +  PadConfig.Direction    = GpioDirNone;
> +  PadConfig.PowerConfig  = GpioHostDeepReset;
> +  DEBUG ((DEBUG_INFO, "Enabling CLKREQ%d\n", ClkreqIndex));
> +  GpioSetPadConfig (ClkReqGpio.Pad, &PadConfig);
> +}
> +
> +
> +/**
> +  This function sets HPD, VDDEN, BKLTEN and BKLTCTL pins into native mode
> for eDP Panel
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableEdpPins (
> +  VOID
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINT32                   Index;
> +  GPIO_PAD_NATIVE_FUNCTION *EdpPins;
> +  UINT32                   EdpPinsNumber;
> +
> +  GpioGetEdpPins (
> +    &EdpPins,
> +    &EdpPinsNumber
> +    );
> +
> +  if (EdpPins == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Configure HPD, VDD and BKLT Pins for eDP panel
> +  //
> +  for (Index = 0; Index < EdpPinsNumber; Index++) {
> +    Status = GpioSetPadMode (EdpPins[Index].Pad, EdpPins[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets DDP pins into native mode
> +
> +  @param[in]  DdpInterface   DDPx interface
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableDpInterface (
> +  IN  GPIO_DDP            DdpInterface
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINTN                    Index;
> +  GPIO_PAD_NATIVE_FUNCTION *DdpGpio;
> +
> +  GpioGetDdpPins (
> +    DdpInterface,
> +    &DdpGpio
> +    );
> +
> +  if (DdpGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < PCH_GPIO_DDP_NUMBER_OF_PINS; Index++) {
> +    Status = GpioSetPadMode (DdpGpio[Index].Pad, DdpGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function configures GPIO connection between CNVi and CRF
> +  @param[in]  None
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioConfigureCnviCrfConnection (
> +  VOID
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINT32                   Index;
> +  GPIO_PAD_NATIVE_FUNCTION *CnviBriRgiExternalPad;
> +
> +  GpioGetCnvBriRgiPins (&CnviBriRgiExternalPad);
> +
> +  if (CnviBriRgiExternalPad == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Configure CNVi BRI and RGI buses for high speed communication with CRF
> +  //
> +  for (Index = 0; Index < PCH_GPIO_CNVI_BRI_RGI_NUMBER_OF_PINS;
> Index++) {
> +    Status = GpioSetPadMode (CnviBriRgiExternalPad[Index].Pad,
> CnviBriRgiExternalPad[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function configures virtual GPIO connection for CNVi Bluetooth UART
> +
> +  @param[in]  ConnectionType
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioConfigureCnviBtUartConnection (
> +  IN  VGPIO_CNVI_BT_UART_CONNECTION_TYPE  ConnectionType
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINT32                   Index;
> +  GPIO_PAD                 *VCnviBtUartPad;
> +  GPIO_PAD_MODE            VCnviBtUartPadMode;
> +  GPIO_PAD                 *VUartForCnviBtPad;
> +  GPIO_PAD_MODE            VUartForCnviBtPadMode;
> +  GPIO_PAD_NATIVE_FUNCTION *CnviBtUartExternalPad;
> +
> +  GpioGetCnviBtUartPins (
> +    ConnectionType,
> +    &VCnviBtUartPad,
> +    &VCnviBtUartPadMode,
> +    &VUartForCnviBtPad,
> +    &VUartForCnviBtPadMode
> +    );
> +
> +  if ((VCnviBtUartPad == NULL) ||
> +      (VUartForCnviBtPad == NULL)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Configure CNVi Bluetooth UART for certain connection
> +  //
> +  for (Index = 0; Index < PCH_GPIO_CNVI_UART_NUMBER_OF_PINS; Index++)
> {
> +    Status = GpioSetPadMode (VCnviBtUartPad[Index],
> VCnviBtUartPadMode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // Enable virtual connection for UART for Bluetooth
> +  //
> +  for (Index = 0; Index < PCH_GPIO_CNVI_UART_NUMBER_OF_PINS; Index++)
> {
> +    Status = GpioSetPadMode (VUartForCnviBtPad[Index],
> VUartForCnviBtPadMode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // Enable CNVi BT UART on external pads
> +  //
> +  if (ConnectionType == GpioCnviBtUartToExternalPads) {
> +
> +    GpioGetCnviBtUartExternalPins (&CnviBtUartExternalPad);
> +
> +    if (CnviBtUartExternalPad == NULL) {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +    for (Index = 0; Index < PCH_GPIO_CNVI_UART_NUMBER_OF_PINS; Index++)
> {
> +      Status = GpioSetPadMode (CnviBtUartExternalPad[Index].Pad,
> CnviBtUartExternalPad[Index].Mode);
> +      if (EFI_ERROR (Status)) {
> +        ASSERT_EFI_ERROR (Status);
> +        return EFI_UNSUPPORTED;
> +      }
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function configures virtual GPIO connection for CNVi Bluetooth I2S
> +
> +  @param[in]  ConnectionType
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioConfigureCnviBtI2sConnection (
> +  IN  VGPIO_CNVI_BT_I2S_CONNECTION_TYPE  ConnectionType
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINT32                   Index;
> +  GPIO_PAD                 *VCnviBtI2sPad;
> +  GPIO_PAD_MODE            VCnviBtI2sPadMode;
> +  GPIO_PAD                 *VSspForCnviBtPad;
> +  GPIO_PAD_MODE            VSspForCnviBtPadMode;
> +  GPIO_PAD_NATIVE_FUNCTION *CnviBtI2sExternalPad;
> +
> +  GpioGetCnviBtI2sPins (
> +    ConnectionType,
> +    &VCnviBtI2sPad,
> +    &VCnviBtI2sPadMode,
> +    &VSspForCnviBtPad,
> +    &VSspForCnviBtPadMode
> +    );
> +
> +  if ((VCnviBtI2sPad == NULL) ||
> +      (VSspForCnviBtPad == NULL)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Configure CNVi Bluetooth I2S for certain connection
> +  //
> +  for (Index = 0; Index < PCH_GPIO_CNVI_SSP_NUMBER_OF_PINS; Index++) {
> +    Status = GpioSetPadMode (VCnviBtI2sPad[Index], VCnviBtI2sPadMode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // Enable virtual connection for SSP for Bluetooth
> +  //
> +  for (Index = 0; Index < PCH_GPIO_CNVI_SSP_NUMBER_OF_PINS; Index++) {
> +    Status = GpioSetPadMode (VSspForCnviBtPad[Index],
> VSspForCnviBtPadMode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // Enable CNV BT I2S on external pads
> +  //
> +  if (ConnectionType == (VGPIO_CNVI_BT_I2S_CONNECTION_TYPE)
> GpioCnviBtI2sToExternalPads) {
> +
> +    GpioGetCnviBtI2sExternalPins (&CnviBtI2sExternalPad);
> +
> +    if (CnviBtI2sExternalPad == NULL) {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +    for (Index = 0; Index < PCH_GPIO_CNVI_SSP_NUMBER_OF_PINS; Index++) {
> +      Status = GpioSetPadMode (CnviBtI2sExternalPad[Index].Pad,
> CnviBtI2sExternalPad[Index].Mode);
> +      if (EFI_ERROR (Status)) {
> +        ASSERT_EFI_ERROR (Status);
> +        return EFI_UNSUPPORTED;
> +      }
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function configures virtual GPIO connection for CNVi MFUART1
> +
> +  @param[in]  ConnectionType
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioConfigureCnviMfUart1Connection (
> +  IN  VGPIO_CNVI_MF_UART1_CONNECTION_TYPE  ConnectionType
> +  )
> +{
> +  EFI_STATUS               Status;
> +  UINT32                   Index;
> +  GPIO_PAD                 *VCnviMfUart1Pad;
> +  GPIO_PAD_MODE            VCnviMfUart1PadMode;
> +  GPIO_PAD                 *VUartForCnviMfUart1Pad;
> +  GPIO_PAD_MODE            VUartForCnviMfUart1PadMode;
> +  GPIO_PAD_NATIVE_FUNCTION *CnviMfUart1ExternalPad;
> +
> +  GpioGetCnviMfUart1Pins (
> +    ConnectionType,
> +    &VCnviMfUart1Pad,
> +    &VCnviMfUart1PadMode,
> +    &VUartForCnviMfUart1Pad,
> +    &VUartForCnviMfUart1PadMode
> +    );
> +
> +  if ((VCnviMfUart1Pad == NULL) ||
> +      (VUartForCnviMfUart1Pad == NULL)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Configure CNVi MFUART1 for certain connection
> +  //
> +  for (Index = 0; Index < PCH_GPIO_CNVI_UART_NUMBER_OF_PINS; Index++)
> {
> +    Status = GpioSetPadMode (VCnviMfUart1Pad[Index],
> VCnviMfUart1PadMode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // Enable virtual connection for MFUART1
> +  //
> +  for (Index = 0; Index < PCH_GPIO_CNVI_UART_NUMBER_OF_PINS; Index++)
> {
> +    Status = GpioSetPadMode (VUartForCnviMfUart1Pad[Index],
> VUartForCnviMfUart1PadMode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT_EFI_ERROR (Status);
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +
> +  //
> +  // Enable CNV MFUART1 on external pads
> +  //
> +  if (ConnectionType == GpioCnviMfUart1ToExternalPads) {
> +
> +    GpioGetCnviMfUart1ExternalPins (&CnviMfUart1ExternalPad);
> +
> +    if (CnviMfUart1ExternalPad == NULL) {
> +      return EFI_UNSUPPORTED;
> +    }
> +
> +    for (Index = 0; Index < PCH_GPIO_CNVI_UART_NUMBER_OF_PINS; Index++)
> {
> +      Status = GpioSetPadMode (CnviMfUart1ExternalPad[Index].Pad,
> CnviMfUart1ExternalPad[Index].Mode);
> +      if (EFI_ERROR (Status)) {
> +        ASSERT_EFI_ERROR (Status);
> +        return EFI_UNSUPPORTED;
> +      }
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +  This function sets CNVi Bluetooth Enable value
> +
> +  @param[in] Value                CNVi BT enable value
> +                                  0: Disable, 1: Enable
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioSetCnviBtEnState (
> +  IN  UINT32  Value
> +  )
> +{
> +  EFI_STATUS  Status;
> +  GPIO_PAD    CnviBtEnPad;
> +  GPIO_CONFIG PadConfig;
> +
> +  ZeroMem (&PadConfig, sizeof (PadConfig));
> +
> +  PadConfig.PadMode        = GpioPadModeGpio;
> +  PadConfig.HostSoftPadOwn = GpioHostOwnGpio;
> +  PadConfig.Direction      = GpioDirOut;
> +  if (Value == 1) {
> +    PadConfig.OutputState  = GpioOutHigh;
> +  } else {
> +    PadConfig.OutputState  = GpioOutLow;
> +  }
> +  CnviBtEnPad = GpioGetCnviBtEnablePin ();
> +
> +  // Unlock GPIO pad due to Host Software Pad Ownership is GPIO Driver
> mode and it is GPO
> +  GpioUnlockPadCfg (CnviBtEnPad);
> +  GpioUnlockPadCfgTx (CnviBtEnPad);
> +  Status = GpioSetPadConfig (CnviBtEnPad, &PadConfig);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return Status;
> +}
> +
> +/**
> +  This function sets CNVi Bluetooth main host interface
> +
> +  @param[in] BtInterface          CNVi BT Interface Select value
> +                                  GpioCnviBtIfUart: UART, GpioCnviBtIfUsb: USB
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioSetCnviBtInterface (
> +  IN  VGPIO_CNVI_BT_INTERFACE  BtInterface
> +  )
> +{
> +  EFI_STATUS  Status;
> +  GPIO_CONFIG PadConfig;
> +
> +  ZeroMem (&PadConfig, sizeof (PadConfig));
> +
> +  PadConfig.PadMode        = GpioPadModeGpio;
> +  PadConfig.Direction      = GpioDirOut;
> +  if (BtInterface == GpioCnviBtIfUsb) {
> +    PadConfig.OutputState  = GpioOutHigh;
> +  } else {
> +    PadConfig.OutputState  = GpioOutLow;
> +  }
> +
> +  Status = GpioSetPadConfig (GpioGetCnviBtIfSelectPin (), &PadConfig);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function sets CNVi Bluetooth Wireless Charging support
> +
> +  @param[in] BtWirelessCharging   CNVi BT Wireless Charging support
> +                                  0: Normal BT operation (no Wireless Charging
> support)
> +                                  1: Enable BT Wireless Charging
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioSetCnviBtWirelessCharging (
> +  IN  UINT32  BtWirelessCharging
> +  )
> +{
> +  EFI_STATUS                Status;
> +  GPIO_CONFIG               CnviBtChargingPadConfig;
> +  GPIO_PAD_NATIVE_FUNCTION  A4WpPad;
> +
> +  ZeroMem (&CnviBtChargingPadConfig, sizeof (CnviBtChargingPadConfig));
> +
> +  CnviBtChargingPadConfig.PadMode        = GpioPadModeGpio;
> +  CnviBtChargingPadConfig.Direction      = GpioDirOut;
> +
> +  if (BtWirelessCharging == 1) {
> +    CnviBtChargingPadConfig.OutputState  = GpioOutHigh;
> +
> +    GpioGetCnviA4WpPin (&A4WpPad);
> +
> +    Status = GpioSetPadMode (A4WpPad.Pad, A4WpPad.Mode);
> +    ASSERT_EFI_ERROR (Status);
> +
> +  } else {
> +    CnviBtChargingPadConfig.OutputState  = GpioOutLow;
> +  }
> +
> +  Status = GpioSetPadConfig (GpioGetCnviBtChargingPin (),
> &CnviBtChargingPadConfig);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function enables and configures CNVi Bluetooth Host wake-up
> interrupt
> +
> +  @param[in] None
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioConfigureCnviBtHostWakeInt (
> +  VOID
> +  )
> +{
> +  EFI_STATUS  Status;
> +  GPIO_PAD    CnviBtHostWakeIntPad;
> +  GPIO_CONFIG PadConfig;
> +
> +  ZeroMem (&PadConfig, sizeof (PadConfig));
> +
> +  PadConfig.PadMode = GpioPadModeGpio;
> +  PadConfig.Direction = GpioDirIn;
> +  PadConfig.HostSoftPadOwn = GpioHostOwnGpio;
> +  PadConfig.InterruptConfig = GpioIntEdge;
> +  PadConfig.PowerConfig  = GpioHostDeepReset;
> +  CnviBtHostWakeIntPad = GpioGetCnviBtHostWakeIntPin ();
> +
> +  // Unlock GPIO pad due to Host Software Pad Ownership is GPIO Driver
> mode.
> +  GpioUnlockPadCfg (CnviBtHostWakeIntPad);
> +  Status = GpioSetPadConfig (CnviBtHostWakeIntPad, &PadConfig);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function enables IMGU CLKOUT native pin
> +
> +  @param[in] None
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableImguClkOut (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                Status;
> +  UINTN                     Index;
> +  GPIO_PAD_NATIVE_FUNCTION  *ImguClkOutGpio;
> +  UINT32                    NoOfNativePins;
> +
> +  GpioGetImgClkOutPins (
> +    &ImguClkOutGpio,
> +    &NoOfNativePins
> +    );
> +
> +  if (ImguClkOutGpio == NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0; Index < NoOfNativePins; Index++) {
> +    Status = GpioSetPadMode (ImguClkOutGpio[Index].Pad,
> ImguClkOutGpio[Index].Mode);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_UNSUPPORTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Power button debounce configuration
> +  Debounce time can be specified in microseconds. Only certain values
> according
> +  to below formula are supported:
> +   DebounceTime = (2 ^ PADCFG_DW2.DEBOUNCE)*(glitch filter clock period).
> +  RTC clock with f = 32 KHz is used for glitch filter.
> +   DebounceTime = (2 ^ PADCFG_DW2.DEBOUNCE)*(31.25 us).
> +  Supported DebounceTime values are following:
> +   DebounceTime = 0 -> Debounce feature disabled
> +   DebounceTime > 0 && < 250us -> Not supported
> +   DebounceTime = 250us - 1024000us -> Supported range (DebounceTime =
> 250us * 2^n)
> +  For values not supported by HW, they will be rounded down to closest
> supported one
> +
> +  @param[in] DebounceTime    Debounce Time in microseconds
> +                             If Debounce Time = 0, Debouncer feature will be
> disabled
> +                             Function will set DebounceTime argument to rounded
> supported value
> +**/
> +VOID
> +GpioSetPwrBtnDebounceTimer (
> +  IN UINT32                DebounceTime
> +  )
> +{
> +  GpioSetDebounceTimer (GpioGetPwrBtnPin (), &DebounceTime);
> +}
> +
> +/**
> +  Configure LPC GPIO
> +**/
> +VOID
> +LpcConfigureGpio (
> +  VOID
> +  )
> +{
> +  GPIO_PAD      GpioPad;
> +  GpioPad = GpioGetLpcPin();
> +
> +  if (GpioPad == 0) {
> +    return;
> +  } else {
> +    GpioSetPadElectricalConfig (GpioPad, GpioTermWpu20K);
> +  }
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNativePrivateLibCnl.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNativePrivateLibCnl.c
> new file mode 100644
> index 0000000000..4cff00c27b
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioNativePrivateLibCnl.c
> @@ -0,0 +1,2275 @@
> +/** @file
> +  This file contains specific GPIO information
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <SaAccess.h>
> +#include <Library/GpioLib.h>
> +#include <Library/GpioNativeLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/SataLib.h>
> +#include <Private/Library/GpioPrivateLib.h>
> +#include <GpioPinsCnlLp.h>
> +#include <GpioPinsCnlH.h>
> +#include <Register/PchRegsGpio.h>
> +#include <Register/PchRegsGpioCnl.h>
> +#include <Register/PchRegsSerialIo.h>
> +#include <Register/PchRegsIsh.h>
> +#include <Register/PchRegsScs.h>
> +#include <Register/PchRegsLpcCnl.h>
> +
> +#include "GpioNativePrivateLibInternal.h"
> +
> +//
> +// I2C controller pins
> +// I2C[controller number][pin: SDA/SCL]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpI2cGpio [][PCH_SERIAL_IO_PINS_PER_I2C_CONTROLLER]=
> +{
> +  {{GPIO_CNL_LP_GPP_C16, GpioPadModeNative1}, {GPIO_CNL_LP_GPP_C17,
> GpioPadModeNative1}},
> +  {{GPIO_CNL_LP_GPP_C18, GpioPadModeNative1}, {GPIO_CNL_LP_GPP_C19,
> GpioPadModeNative1}},
> +  {{GPIO_CNL_LP_GPP_H4,  GpioPadModeNative1}, {GPIO_CNL_LP_GPP_H5 ,
> GpioPadModeNative1}},
> +  {{GPIO_CNL_LP_GPP_H6,  GpioPadModeNative1}, {GPIO_CNL_LP_GPP_H7 ,
> GpioPadModeNative1}},
> +  {{GPIO_CNL_LP_GPP_H8,  GpioPadModeNative1}, {GPIO_CNL_LP_GPP_H9 ,
> GpioPadModeNative1}},
> +  {{GPIO_CNL_LP_GPP_H10, GpioPadModeNative1}, {GPIO_CNL_LP_GPP_H11,
> GpioPadModeNative1}}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHI2cGpio [][PCH_SERIAL_IO_PINS_PER_I2C_CONTROLLER]=
> +{
> +  {{GPIO_CNL_H_GPP_C16, GpioPadModeNative1}, {GPIO_CNL_H_GPP_C17,
> GpioPadModeNative1}}, // I2C0
> +  {{GPIO_CNL_H_GPP_C18, GpioPadModeNative1}, {GPIO_CNL_H_GPP_C19,
> GpioPadModeNative1}}, // I2C1
> +  {{GPIO_CNL_H_GPP_D13, GpioPadModeNative3}, {GPIO_CNL_H_GPP_D14,
> GpioPadModeNative3}}, // I2C2
> +  {{GPIO_CNL_H_GPP_D4,  GpioPadModeNative2}, {GPIO_CNL_H_GPP_D23,
> GpioPadModeNative2}}  // I2C3
> +};
> +
> +
> +/**
> +  This function provides SerialIo I2C controller pins
> +
> +  @param[in]  SerialIoI2cControllerNumber    I2C controller
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetSerialIoI2cPins (
> +  IN  UINT32                      SerialIoI2cControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (SerialIoI2cControllerNumber < ARRAY_SIZE (mPchLpI2cGpio)) {
> +      *NativePinsTable = mPchLpI2cGpio[SerialIoI2cControllerNumber];
> +      return;
> +    }
> +  } else {
> +    if (SerialIoI2cControllerNumber < ARRAY_SIZE (mPchHI2cGpio)) {
> +      *NativePinsTable = mPchHI2cGpio[SerialIoI2cControllerNumber];
> +      return;
> +    }
> +  }
> +  *NativePinsTable = NULL;
> +  ASSERT (FALSE);
> +}
> +//
> +// UART controller pins
> +// UART[controller number][pin: RXD/TXD/RTSB/CTSB]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpUartGpio [][PCH_SERIAL_IO_PINS_PER_UART_CONTROLLER]=
> +{
> +  { // UART0
> +    {GPIO_CNL_LP_GPP_C8,  GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_C9,  GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_C10, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_C11, GpioPadModeNative1}
> +  },
> +  { // UART1
> +    {GPIO_CNL_LP_GPP_C12, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_C13, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_C14, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_C15, GpioPadModeNative1}
> +  },
> +  { // UART2
> +    {GPIO_CNL_LP_GPP_C20, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_C21, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_C22, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_C23, GpioPadModeNative1},
> +  },
> +  { // UART0 (2nd pin set)
> +    {GPIO_CNL_LP_GPP_F5, GpioPadModeNative2},
> +    {GPIO_CNL_LP_GPP_F6, GpioPadModeNative2},
> +    {GPIO_CNL_LP_GPP_F4, GpioPadModeNative2},
> +    {GPIO_CNL_LP_GPP_F7, GpioPadModeNative2}
> +  }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHUartGpio [][PCH_SERIAL_IO_PINS_PER_UART_CONTROLLER]=
> +{
> +  { // UART0
> +    {GPIO_CNL_H_GPP_C8,  GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_C9,  GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_C10, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_C11, GpioPadModeNative1}
> +  },
> +  { // UART1
> +    {GPIO_CNL_H_GPP_C12, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_C13, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_C14, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_C15, GpioPadModeNative1}
> +  },
> +  { // UART2
> +    {GPIO_CNL_H_GPP_C20, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_C21, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_C22, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_C23, GpioPadModeNative1}
> +  },
> +  { // UART0 (2nd pin set)
> +    {GPIO_CNL_H_GPP_J5, GpioPadModeNative2},
> +    {GPIO_CNL_H_GPP_J6, GpioPadModeNative2},
> +    {GPIO_CNL_H_GPP_J4, GpioPadModeNative2},
> +    {GPIO_CNL_H_GPP_J7, GpioPadModeNative2}
> +  }
> +};
> +
> +/**
> +  This function provides SerialIo UART controller pins
> +
> +  @param[in]  SerialIoUartControllerNumber   UART controller
> +  @param[in]  HardwareFlowControl            Hardware Flow control
> +  @param[in]  PinMuxing                      UART controller pin muxing
> +   @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetSerialIoUartPins (
> +  IN  UINT32                      SerialIoUartControllerNumber,
> +  IN  BOOLEAN                     HardwareFlowControl,
> +  IN  UINT32                      PinMuxing,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  )
> +{
> +  UINTN                    UartGpioIndex;
> +
> +  UartGpioIndex = SerialIoUartControllerNumber;
> +
> +  if ((SerialIoUartControllerNumber == 0) && (PinMuxing == 1)) {
> +    // Last record is for UART0 second pin set
> +    if (IsPchLp ()) {
> +      UartGpioIndex = ARRAY_SIZE (mPchLpUartGpio) - 1;
> +    } else {
> +      UartGpioIndex = ARRAY_SIZE (mPchHUartGpio) - 1;
> +    }
> +  }
> +
> +  if (HardwareFlowControl) {
> +    *NoOfNativePins = PCH_SERIAL_IO_PINS_PER_UART_CONTROLLER;
> +  } else {
> +    *NoOfNativePins =
> PCH_SERIAL_IO_PINS_PER_UART_CONTROLLER_NO_FLOW_CTRL;
> +  }
> +
> +  if (IsPchLp ()) {
> +    if (UartGpioIndex < ARRAY_SIZE (mPchLpUartGpio)) {
> +      *NativePinsTable = mPchLpUartGpio[UartGpioIndex];
> +      return;
> +    }
> +  } else {
> +    if (UartGpioIndex < ARRAY_SIZE (mPchHUartGpio)) {
> +      *NativePinsTable = mPchHUartGpio[UartGpioIndex];
> +      return;
> +    }
> +  }
> +
> +  *NativePinsTable = NULL;
> +  *NoOfNativePins = 0;
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// SPI controller pins
> +// SPI[controller number][pin: CSB/CLK/MISO/MOSI]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpSpiGpio [][PCH_SERIAL_IO_PINS_PER_SPI_CONTROLLER]=
> +{
> +  { // SPI0
> +    {GPIO_CNL_LP_GPP_B15, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_B16, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_B17, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_B18, GpioPadModeNative1}
> +  },
> +  { // SPI1
> +    {GPIO_CNL_LP_GPP_B19, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_B20, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_B21, GpioPadModeNative1},
> +    {GPIO_CNL_LP_GPP_B22, GpioPadModeNative1}
> +  },
> +  { // SPI2
> +    {GPIO_CNL_LP_GPP_D9,  GpioPadModeNative3},
> +    {GPIO_CNL_LP_GPP_D10, GpioPadModeNative3},
> +    {GPIO_CNL_LP_GPP_D11, GpioPadModeNative3},
> +    {GPIO_CNL_LP_GPP_D12, GpioPadModeNative3}
> +  }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHSpiGpio [][PCH_SERIAL_IO_PINS_PER_SPI_CONTROLLER]=
> +{
> +  { // SPI0
> +    {GPIO_CNL_H_GPP_B15, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_B16, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_B17, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_B18, GpioPadModeNative1}
> +  },
> +  { // SPI1
> +    {GPIO_CNL_H_GPP_B19, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_B20, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_B21, GpioPadModeNative1},
> +    {GPIO_CNL_H_GPP_B22, GpioPadModeNative1}
> +  },
> +  { // SPI2
> +    {GPIO_CNL_H_GPP_D9,  GpioPadModeNative3},
> +    {GPIO_CNL_H_GPP_D10, GpioPadModeNative3},
> +    {GPIO_CNL_H_GPP_D11, GpioPadModeNative3},
> +    {GPIO_CNL_H_GPP_D12, GpioPadModeNative3}
> +  }
> +};
> +
> +/**
> +  This function provides SerialIo SPI controller pins
> +
> +  @param[in]  SerialIoSpiControllerNumber   SPI controller
> +
> +  @param[out] NativePinsTable               Table with pins
> +  @param[out] NoOfNativePins                Number of pins
> +**/
> +VOID
> +GpioGetSerialIoSpiPins (
> +  IN  UINT32                      SerialIoSpiControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (SerialIoSpiControllerNumber < ARRAY_SIZE (mPchLpSpiGpio)) {
> +      *NativePinsTable = mPchLpSpiGpio[SerialIoSpiControllerNumber];
> +      *NoOfNativePins =  ARRAY_SIZE
> (mPchLpSpiGpio[SerialIoSpiControllerNumber]);
> +      return;
> +    }
> +  } else {
> +    if (SerialIoSpiControllerNumber < ARRAY_SIZE (mPchHSpiGpio)) {
> +      *NativePinsTable = mPchHSpiGpio[SerialIoSpiControllerNumber];
> +      *NoOfNativePins =  ARRAY_SIZE
> (mPchHSpiGpio[SerialIoSpiControllerNumber]);
> +      return;
> +    }
> +  }
> +  *NativePinsTable = NULL;
> +  *NoOfNativePins = 0;
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// ISH GP pin
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpIshGPGpio[] =
> +{
> +  {GPIO_CNL_LP_GPP_A18, GpioPadModeNative1},// ISH_GP_0
> +  {GPIO_CNL_LP_GPP_A19, GpioPadModeNative1},// ISH_GP_1
> +  {GPIO_CNL_LP_GPP_A20, GpioPadModeNative1},// ISH_GP_2
> +  {GPIO_CNL_LP_GPP_A21, GpioPadModeNative1},// ISH_GP_3
> +  {GPIO_CNL_LP_GPP_A22, GpioPadModeNative1},// ISH_GP_4
> +  {GPIO_CNL_LP_GPP_A23, GpioPadModeNative1},// ISH_GP_5
> +  {GPIO_CNL_LP_GPP_A12, GpioPadModeNative2},// ISH_GP_6
> +  {GPIO_CNL_LP_GPP_A17, GpioPadModeNative2} // ISH_GP_7
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHIshGPGpio[] =
> +{
> +  {GPIO_CNL_H_GPP_A18, GpioPadModeNative1},// ISH_GP_0
> +  {GPIO_CNL_H_GPP_A19, GpioPadModeNative1},// ISH_GP_1
> +  {GPIO_CNL_H_GPP_A20, GpioPadModeNative1},// ISH_GP_2
> +  {GPIO_CNL_H_GPP_A21, GpioPadModeNative1},// ISH_GP_3
> +  {GPIO_CNL_H_GPP_A22, GpioPadModeNative1},// ISH_GP_4
> +  {GPIO_CNL_H_GPP_A23, GpioPadModeNative1},// ISH_GP_5
> +  {GPIO_CNL_H_GPP_A12, GpioPadModeNative2},// ISH_GP_6
> +  {GPIO_CNL_H_GPP_A17, GpioPadModeNative2} // ISH_GP_7
> +};
> +
> +/**
> +  This function provides ISH GP pin data
> +
> +  @param[in]  IshGpPinNumber        ISH GP pin number
> +  @param[out] NativePin             ISH GP pin
> +**/
> +VOID
> +GpioGetIshGpPin (
> +  IN  UINT32                      IshGpPinNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    *NativePin
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (IshGpPinNumber < ARRAY_SIZE (mPchLpIshGPGpio)) {
> +      *NativePin = mPchLpIshGPGpio[IshGpPinNumber];
> +      return;
> +    }
> +  } else {
> +    if (IshGpPinNumber < ARRAY_SIZE (mPchHIshGPGpio)) {
> +      *NativePin = mPchHIshGPGpio[IshGpPinNumber];
> +      return;
> +    }
> +  }
> +  *NativePin = (GPIO_PAD_NATIVE_FUNCTION){0};
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// ISH UART controller pins
> +// ISH UART[controller number][pin: RXD/TXD/RTSB/CTSB]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpIshUartGpio[][PCH_ISH_PINS_PER_UART_CONTROLLER] =
> +{
> +  { // UART0
> +    {GPIO_CNL_LP_GPP_D13, GpioPadModeNative1},// ISH_UART0_RXD
> +    {GPIO_CNL_LP_GPP_D14, GpioPadModeNative1},// ISH_UART0_TXD
> +    {GPIO_CNL_LP_GPP_D15, GpioPadModeNative1},// ISH_UART0_RTS
> +    {GPIO_CNL_LP_GPP_D16, GpioPadModeNative1} // ISH_UART0_CTS
> +  },
> +  { // UART1
> +    {GPIO_CNL_LP_GPP_C12, GpioPadModeNative2},// ISH_UART1_RXD
> +    {GPIO_CNL_LP_GPP_C13, GpioPadModeNative2},// ISH_UART1_TXD
> +    {GPIO_CNL_LP_GPP_C14, GpioPadModeNative2},// ISH_UART1_RTSB
> +    {GPIO_CNL_LP_GPP_C15, GpioPadModeNative2} // ISH_UART1_CTSB
> +  }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHIshUartGpio[][PCH_ISH_PINS_PER_UART_CONTROLLER] =
> +{
> +  { // UART0
> +    {GPIO_CNL_H_GPP_D13, GpioPadModeNative1},// ISH_UART0_RXD
> +    {GPIO_CNL_H_GPP_D14, GpioPadModeNative1},// ISH_UART0_TXD
> +    {GPIO_CNL_H_GPP_D15, GpioPadModeNative1},// ISH_UART0_RTS
> +    {GPIO_CNL_H_GPP_D16, GpioPadModeNative1} // ISH_UART0_CTS
> +  },
> +  { // UART1
> +    {GPIO_CNL_H_GPP_C12, GpioPadModeNative2},// ISH_UART1_RXD
> +    {GPIO_CNL_H_GPP_C13, GpioPadModeNative2},// ISH_UART1_TXD
> +    {GPIO_CNL_H_GPP_C14, GpioPadModeNative2},// ISH_UART1_RTS
> +    {GPIO_CNL_H_GPP_C15, GpioPadModeNative2} // ISH_UART1_CTS
> +  }
> +};
> +
> +/**
> +  This function provides ISH UART controller pins
> +
> +  @param[in]  IshUartControllerNumber   ISH UART controller
> +
> +  @param[out] NativePinsTable           Table with pins
> +**/
> +VOID
> +GpioGetIshUartPins (
> +  IN  UINT32                      IshUartControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (IshUartControllerNumber < ARRAY_SIZE (mPchLpIshUartGpio)) {
> +      *NativePinsTable = mPchLpIshUartGpio[IshUartControllerNumber];
> +      return;
> +    }
> +  } else {
> +    if (IshUartControllerNumber < ARRAY_SIZE (mPchHIshUartGpio)) {
> +      *NativePinsTable = mPchHIshUartGpio[IshUartControllerNumber];
> +      return;
> +    }
> +  }
> +  *NativePinsTable = NULL;
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// ISH I2C controller pins
> +// ISH I2C[controller number][pin: SDA/SCL]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpIshI2cGpio[][PCH_ISH_PINS_PER_I2C_CONTROLLER] =
> +{
> +  { // I2C0
> +    {GPIO_CNL_LP_GPP_D5,  GpioPadModeNative1},// ISH_I2C0_SDA
> +    {GPIO_CNL_LP_GPP_D6,  GpioPadModeNative1} // ISH_I2C0_SCL
> +  },
> +  { // I2C1
> +    {GPIO_CNL_LP_GPP_D7,  GpioPadModeNative1},// ISH_I2C1_SDA
> +    {GPIO_CNL_LP_GPP_D8,  GpioPadModeNative1} // ISH_I2C1_SCL
> +  },
> +  { // I2C2
> +    {GPIO_CNL_LP_GPP_H10, GpioPadModeNative2},// ISH_I2C2_SDA
> +    {GPIO_CNL_LP_GPP_H11, GpioPadModeNative2} // ISH_I2C2_SCL
> +  },
> +  { // I2C3
> +    {GPIO_CNL_LP_GPP_H4,  GpioPadModeNative2},// ISH_I2C3_SDA
> +    {GPIO_CNL_LP_GPP_H5,  GpioPadModeNative2} // ISH_I2C3_SCL
> +  },
> +  { // I2C4
> +    {GPIO_CNL_LP_GPP_H6,  GpioPadModeNative2},// ISH_I2C4_SDA
> +    {GPIO_CNL_LP_GPP_H7,  GpioPadModeNative2} // ISH_I2C4_SCL
> +  },
> +  { // I2C5
> +    {GPIO_CNL_LP_GPP_H8,  GpioPadModeNative2},// ISH_I2C5_SDA
> +    {GPIO_CNL_LP_GPP_H9,  GpioPadModeNative2} // ISH_I2C5_SCL
> +  }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHIshI2cGpio[][PCH_ISH_PINS_PER_I2C_CONTROLLER] =
> +{
> +  { // I2C0
> +    {GPIO_CNL_H_GPP_H19, GpioPadModeNative1},// ISH_I2C0_SDA
> +    {GPIO_CNL_H_GPP_H20, GpioPadModeNative1} // ISH_I2C0_SCL
> +  },
> +  { // I2C1
> +    {GPIO_CNL_H_GPP_H21, GpioPadModeNative1},// ISH_I2C1_SDA
> +    {GPIO_CNL_H_GPP_H22, GpioPadModeNative1} // ISH_I2C1_SCL
> +  },
> +  { // I2C2
> +    {GPIO_CNL_H_GPP_D4,  GpioPadModeNative1},// ISH_I2C2_SDA
> +    {GPIO_CNL_H_GPP_D23, GpioPadModeNative1} // ISH_I2C2_SCL
> +  }
> +};
> +
> +/**
> +  This function provides ISH I2C controller pins
> +
> +  @param[in]  IshI2cControllerNumber   ISH I2C controller
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetIshI2cPins (
> +  IN  UINT32                      IshI2cControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (IshI2cControllerNumber < ARRAY_SIZE (mPchLpIshI2cGpio)) {
> +      *NativePinsTable = mPchLpIshI2cGpio[IshI2cControllerNumber];
> +      return;
> +    }
> +  } else {
> +    if (IshI2cControllerNumber < ARRAY_SIZE (mPchHIshI2cGpio)) {
> +      *NativePinsTable = mPchHIshI2cGpio[IshI2cControllerNumber];
> +      return;
> +    }
> +  }
> +  *NativePinsTable = NULL;
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// ISH SPI controller pins
> +// ISH SPI[pin: CSB/CLK/MISO/MOSI]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpIshSpiGpio[PCH_ISH_PINS_PER_SPI_CONTROLLER] =
> +{
> +  {GPIO_CNL_LP_GPP_D9,  GpioPadModeNative1},// ISH_SPI_CSB
> +  {GPIO_CNL_LP_GPP_D10, GpioPadModeNative1},// ISH_SPI_CLK
> +  {GPIO_CNL_LP_GPP_D11, GpioPadModeNative1},// ISH_SPI_MISO
> +  {GPIO_CNL_LP_GPP_D12, GpioPadModeNative1} // ISH_SPI_MOSI
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHIshSpiGpio[PCH_ISH_PINS_PER_SPI_CONTROLLER] =
> +{
> +  {GPIO_CNL_H_GPP_D9,  GpioPadModeNative1},// ISH_SPI_CSB
> +  {GPIO_CNL_H_GPP_D10, GpioPadModeNative1},// ISH_SPI_CLK
> +  {GPIO_CNL_H_GPP_D11, GpioPadModeNative1},// ISH_SPI_MISO
> +  {GPIO_CNL_H_GPP_D12, GpioPadModeNative1} // ISH_SPI_MOSI
> +};
> +
> +/**
> +  This function provides ISH SPI controller pins
> +
> +  @param[in]  IshSpiControllerNumber   SPI controller
> +  @param[out] NativePinsTable          Table with pins
> +  @param[out] NoOfNativePins           Number of pins
> +**/
> +VOID
> +GpioGetIshSpiPins (
> +  IN  UINT32                      IshSpiControllerNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (IshSpiControllerNumber < ARRAY_SIZE (mPchLpIshSpiGpio)) {
> +      *NativePinsTable = mPchLpIshSpiGpio;
> +      *NoOfNativePins = ARRAY_SIZE (mPchLpIshSpiGpio);
> +      return;
> +    }
> +  } else {
> +    if (IshSpiControllerNumber < ARRAY_SIZE (mPchHIshSpiGpio)) {
> +      *NativePinsTable = mPchHIshSpiGpio;
> +      *NoOfNativePins = ARRAY_SIZE (mPchHIshSpiGpio);
> +      return;
> +    }
> +  }
> +
> +  *NoOfNativePins = 0;
> +  *NativePinsTable = NULL;
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// GPIO pins for SD controller
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpScsSdCardGpio[9] =
> +{
> +  {GPIO_CNL_LP_GPP_A17, GpioPadModeNative1},// SD_PWR_EN_B
> +  {GPIO_CNL_LP_GPP_G0,  GpioPadModeNative1},// SD_CMD
> +  {GPIO_CNL_LP_GPP_G1,  GpioPadModeNative1},// SD_DATA_0
> +  {GPIO_CNL_LP_GPP_G2,  GpioPadModeNative1},// SD_DATA_1
> +  {GPIO_CNL_LP_GPP_G3,  GpioPadModeNative1},// SD_DATA_2
> +  {GPIO_CNL_LP_GPP_G4,  GpioPadModeNative1},// SD_DATA_3
> +  {GPIO_CNL_LP_GPP_G5,  GpioPadModeNative1},// SD_CDB
> +  {GPIO_CNL_LP_GPP_G6,  GpioPadModeNative1},// SD_CLK
> +  {GPIO_CNL_LP_GPP_G7,  GpioPadModeNative1} // SD_WP
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHScsSdCardGpio[9] =
> +{
> +  {GPIO_CNL_H_GPP_A17, GpioPadModeNative1},// SD_PWR_EN_B
> +  {GPIO_CNL_H_GPP_G0,  GpioPadModeNative1},// SD_CMD
> +  {GPIO_CNL_H_GPP_G1,  GpioPadModeNative1},// SD_DATA_0
> +  {GPIO_CNL_H_GPP_G2,  GpioPadModeNative1},// SD_DATA_1
> +  {GPIO_CNL_H_GPP_G3,  GpioPadModeNative1},// SD_DATA_2
> +  {GPIO_CNL_H_GPP_G4,  GpioPadModeNative1},// SD_DATA_3
> +  {GPIO_CNL_H_GPP_G5,  GpioPadModeNative1},// SD_CDB
> +  {GPIO_CNL_H_GPP_G6,  GpioPadModeNative1},// SD_CLK
> +  {GPIO_CNL_H_GPP_G7,  GpioPadModeNative1} // SD_WP
> +};
> +
> +/**
> +  This function provides SCS SD CARD controller pins
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetScsSdCardPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpScsSdCardGpio;
> +    *NoOfNativePins = ARRAY_SIZE (mPchLpScsSdCardGpio);
> +  } else {
> +    *NativePinsTable = mPchHScsSdCardGpio;
> +    *NoOfNativePins = ARRAY_SIZE (mPchHScsSdCardGpio);
> +  }
> +}
> +
> +/**
> +  This function provides SCS SD CARD detect pin
> +
> +  @retval GpioPin             SD CARD Detect pin
> +**/
> +GPIO_PAD
> +GpioGetScsSdCardDetectPin (
> +  VOID
> +  )
> +{
> +  if (IsPchLp ()) {
> +    return GPIO_CNL_LP_VGPIO39;
> +  } else {
> +    return GPIO_CNL_H_VGPIO6;
> +  }
> +}
> +
> +//
> +// GPIO pins for eMMC controller
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpScsEmmcGpio[12] =
> +{
> +  {GPIO_CNL_LP_GPP_F11, GpioPadModeNative1},// EMMC_CMD
> +  {GPIO_CNL_LP_GPP_F12, GpioPadModeNative1},// EMMC_DATA_0
> +  {GPIO_CNL_LP_GPP_F13, GpioPadModeNative1},// EMMC_DATA_1
> +  {GPIO_CNL_LP_GPP_F14, GpioPadModeNative1},// EMMC_DATA_2
> +  {GPIO_CNL_LP_GPP_F15, GpioPadModeNative1},// EMMC_DATA_3
> +  {GPIO_CNL_LP_GPP_F16, GpioPadModeNative1},// EMMC_DATA_4
> +  {GPIO_CNL_LP_GPP_F17, GpioPadModeNative1},// EMMC_DATA_5
> +  {GPIO_CNL_LP_GPP_F18, GpioPadModeNative1},// EMMC_DATA_6
> +  {GPIO_CNL_LP_GPP_F19, GpioPadModeNative1},// EMMC_DATA_7
> +  {GPIO_CNL_LP_GPP_F20, GpioPadModeNative1},// EMMC_RCLK
> +  {GPIO_CNL_LP_GPP_F21, GpioPadModeNative1},// EMMC_CLK
> +  {GPIO_CNL_LP_GPP_F22, GpioPadModeNative1} // EMMC_RESETB
> +};
> +
> +/**
> +  This function provides SCS eMMC controller pins
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetScsEmmcPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpScsEmmcGpio;
> +    *NoOfNativePins = ARRAY_SIZE (mPchLpScsEmmcGpio);
> +  } else {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +}
> +
> +//
> +// GPIO pins for HD Audio Link [pin: BCLK/RSTB/SYNC/SDO/SDIx]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpHdaLinkGpio[PCH_GPIO_HDA_LINK_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_LP_HDA_BCLK,  GpioPadModeNative1},// HDA_BCLK
> +  {GPIO_CNL_LP_HDA_RSTB,  GpioPadModeNative1},// HDA_RSTB
> +  {GPIO_CNL_LP_HDA_SYNC,  GpioPadModeNative1},// HDA_SYNC
> +  {GPIO_CNL_LP_HDA_SDO,   GpioPadModeNative1},// HDA_SDO
> +  {GPIO_CNL_LP_HDA_SDI_0, GpioPadModeNative1},// HDA_SDI_0
> +  {GPIO_CNL_LP_HDA_SDI_1, GpioPadModeNative1} // HDA_SDI_1
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHHdaLinkGpio[PCH_GPIO_HDA_LINK_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_H_HDA_BCLK,  GpioPadModeNative1},// HDA_BCLK
> +  {GPIO_CNL_H_HDA_RSTB,  GpioPadModeNative1},// HDA_RSTB
> +  {GPIO_CNL_H_HDA_SYNC,  GpioPadModeNative1},// HDA_SYNC
> +  {GPIO_CNL_H_HDA_SDO,   GpioPadModeNative1},// HDA_SDO
> +  {GPIO_CNL_H_HDA_SDI_0, GpioPadModeNative1},// HDA_SDI_0
> +  {GPIO_CNL_H_HDA_SDI_1, GpioPadModeNative1} // HDA_SDI_1
> +};
> +
> +/**
> +  This function provides HD Audio Link pins
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetHdAudioLinkPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpHdaLinkGpio;
> +    *NoOfNativePins = ARRAY_SIZE (mPchLpHdaLinkGpio);
> +  } else {
> +    *NativePinsTable = mPchHHdaLinkGpio;
> +    *NoOfNativePins = ARRAY_SIZE (mPchHHdaLinkGpio);
> +  }
> +}
> +
> +//
> +// GPIO pins for HD Audio DMIC [DMIC number][pin: CLK/DATA]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpHdaDmicGpio[][PCH_GPIO_HDA_DMIC_NUMBER_OF_PINS] =
> +{
> +  { // DMIC0
> +    {GPIO_CNL_LP_GPP_D19, GpioPadModeNative1},// DMIC_CLK_0
> +    {GPIO_CNL_LP_GPP_D20, GpioPadModeNative1} // DMIC_DATA_0
> +  },
> +  { // DMIC1
> +    {GPIO_CNL_LP_GPP_D17, GpioPadModeNative1},// DMIC_CLK_1
> +    {GPIO_CNL_LP_GPP_D18, GpioPadModeNative1} // DMIC_DATA_1
> +  }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHHdaDmicGpio[][PCH_GPIO_HDA_DMIC_NUMBER_OF_PINS] =
> +{
> +  { // DMIC0
> +    {GPIO_CNL_H_GPP_D19, GpioPadModeNative1},// DMIC_CLK_0
> +    {GPIO_CNL_H_GPP_D20, GpioPadModeNative1} // DMIC_DATA_0
> +  },
> +  { // DMIC1
> +    {GPIO_CNL_H_GPP_D17, GpioPadModeNative1},// DMIC_CLK_1
> +    {GPIO_CNL_H_GPP_D18, GpioPadModeNative1} // DMIC_DATA_1
> +  }
> +};
> +
> +/**
> +  This function provides DMIC interface pins
> +
> +  @param[in]  DmicNumber               DMIC interface
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetHdaDmicPins (
> +  IN  UINT32                      DmicNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (DmicNumber < ARRAY_SIZE (mPchLpHdaDmicGpio)) {
> +      *NativePinsTable = mPchLpHdaDmicGpio[DmicNumber];
> +      return;
> +    }
> +  } else {
> +    if (DmicNumber < ARRAY_SIZE (mPchHHdaDmicGpio)) {
> +      *NativePinsTable = mPchHHdaDmicGpio[DmicNumber];
> +      return;
> +    }
> +  }
> +  *NativePinsTable = NULL;
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// GPIO pins for HD Audio SSPx/I2Sx interface [SSP number][pin:
> SCLK/SFRM/TXD/RXD]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpHdaSspInterfaceGpio[][PCH_GPIO_HDA_SSP_NUMBER_OF_PINS] =
> +{
> +  { // SSP0/I2S0
> +    {GPIO_CNL_LP_HDA_BCLK,  GpioPadModeNative2},// SSP0_SCLK
> +    {GPIO_CNL_LP_HDA_SYNC,  GpioPadModeNative2},// SSP0_SFRM
> +    {GPIO_CNL_LP_HDA_SDO,   GpioPadModeNative2},// SSP0_TXD
> +    {GPIO_CNL_LP_HDA_SDI_0, GpioPadModeNative2} // SSP0_RXD
> +  },
> +  { // SSP1/I2S1
> +    {GPIO_CNL_LP_HDA_RSTB,  GpioPadModeNative2},// SSP1_SCLK
> +    {GPIO_CNL_LP_SSP1_SFRM, GpioPadModeNative1},// SSP1_SFRM
> +    {GPIO_CNL_LP_SSP1_TXD,  GpioPadModeNative1},// SSP1_TXD
> +    {GPIO_CNL_LP_HDA_SDI_1, GpioPadModeNative2} // SSP1_RXD
> +  },
> +  { // SSP2/I2S2
> +    {GPIO_CNL_LP_GPP_H0, GpioPadModeNative1},// SSP2_SCLK
> +    {GPIO_CNL_LP_GPP_H1, GpioPadModeNative1},// SSP2_SFRM
> +    {GPIO_CNL_LP_GPP_H2, GpioPadModeNative1},// SSP2_TXD
> +    {GPIO_CNL_LP_GPP_H3, GpioPadModeNative1} // SSP2_RXD
> +  }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHHdaSspInterfaceGpio[][PCH_GPIO_HDA_SSP_NUMBER_OF_PINS] =
> +{
> +  { // SSP0/I2S0
> +    {GPIO_CNL_H_HDA_BCLK,  GpioPadModeNative2},// SSP0_SCLK
> +    {GPIO_CNL_H_HDA_SYNC,  GpioPadModeNative2},// SSP0_SFRM
> +    {GPIO_CNL_H_HDA_SDO,   GpioPadModeNative2},// SSP0_TXD
> +    {GPIO_CNL_H_HDA_SDI_0, GpioPadModeNative2} // SSP0_RXD
> +  },
> +  { // SSP1/I2S1
> +    {GPIO_CNL_H_HDA_RSTB,  GpioPadModeNative2},// SSP1_SCLK
> +    {GPIO_CNL_H_SSP1_SFRM, GpioPadModeNative1},// SSP1_SFRM
> +    {GPIO_CNL_H_SSP1_TXD,  GpioPadModeNative1},// SSP1_TXD
> +    {GPIO_CNL_H_HDA_SDI_1, GpioPadModeNative2} // SSP1_RXD
> +  },
> +  { // SSP2/I2S2
> +    {GPIO_CNL_H_GPP_D5, GpioPadModeNative1}, // SSP2_SFRM
> +    {GPIO_CNL_H_GPP_D6, GpioPadModeNative1}, // SSP2_TXD
> +    {GPIO_CNL_H_GPP_D7, GpioPadModeNative1}, // SSP2_RXD
> +    {GPIO_CNL_H_GPP_D8, GpioPadModeNative1}  // SSP2_SCLK
> +  }
> +};
> +
> +/**
> +  This function provides SSP/I2S interface pins
> +
> +  @param[in]  SspInterfaceNumber       SSP/I2S interface
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetHdaSspPins (
> +  IN  UINT32                      SspInterfaceNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (SspInterfaceNumber < ARRAY_SIZE (mPchLpHdaSspInterfaceGpio)) {
> +      *NativePinsTable = mPchLpHdaSspInterfaceGpio[SspInterfaceNumber];
> +      return;
> +    }
> +  } else {
> +    if (SspInterfaceNumber < ARRAY_SIZE (mPchHHdaSspInterfaceGpio)) {
> +      *NativePinsTable = mPchHHdaSspInterfaceGpio[SspInterfaceNumber];
> +      return;
> +    }
> +  }
> +  *NativePinsTable = NULL;
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// GPIO Pin for HD Audio SSP_MCLK/I2S_MCLK
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpHdaSspMasterClockGpio = {GPIO_CNL_LP_GPP_D23,
> GpioPadModeNative1};
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHHdaSspMasterClockGpio = {GPIO_CNL_H_GPP_B11,
> GpioPadModeNative1};
> +
> +/**
> +  This function sets HDA SSP Master Clock into native mode
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableHdaSspMasterClock (
> +  VOID
> +  )
> +{
> +  if (IsPchLp ()) {
> +    return GpioSetPadMode (mPchLpHdaSspMasterClockGpio.Pad,
> mPchLpHdaSspMasterClockGpio.Mode);
> +  } else {
> +    return GpioSetPadMode (mPchHHdaSspMasterClockGpio.Pad,
> mPchHHdaSspMasterClockGpio.Mode);
> +  }
> +}
> +
> +//
> +// GPIO pins for HD Audio SoundWire interface [SNDW number][pin:
> CLK/DATA]
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpHdaSndwGpio[][PCH_GPIO_HDA_SNDW_NUMBER_OF_PINS] =
> +{
> +  { // SNDW1
> +    {GPIO_CNL_LP_HDA_RSTB,  GpioPadModeNative3},// SNDW1_CLK
> +    {GPIO_CNL_LP_HDA_SDI_1, GpioPadModeNative3} // SNDW1_DATA
> +  },
> +  { // SNDW2
> +    {GPIO_CNL_LP_SSP1_SFRM, GpioPadModeNative2},// SNDW2_CLK
> +    {GPIO_CNL_LP_SSP1_TXD,  GpioPadModeNative2} // SNDW2_DATA
> +  },
> +  { // SNDW3
> +    {GPIO_CNL_LP_GPP_D17,   GpioPadModeNative2},// SNDW3_CLK
> +    {GPIO_CNL_LP_GPP_D18,   GpioPadModeNative2} // SNDW3_DATA
> +  },
> +  { // SNDW4
> +    {GPIO_CNL_LP_GPP_D19,   GpioPadModeNative2},// SNDW4_CLK
> +    {GPIO_CNL_LP_GPP_D20,   GpioPadModeNative2} // SNDW4_DATA
> +  }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHHdaSndwGpio[][PCH_GPIO_HDA_SNDW_NUMBER_OF_PINS] =
> +{
> +  { // SNDW1
> +    {GPIO_CNL_H_HDA_RSTB,  GpioPadModeNative3},// SNDW1_CLK
> +    {GPIO_CNL_H_HDA_SDI_1, GpioPadModeNative3} // SNDW1_DATA
> +  },
> +  { // SNDW2
> +    {GPIO_CNL_H_SSP1_SFRM, GpioPadModeNative2},// SNDW2_CLK
> +    {GPIO_CNL_H_SSP1_TXD,  GpioPadModeNative2} // SNDW2_DATA
> +  },
> +  { // SNDW3
> +    {GPIO_CNL_H_GPP_D17,   GpioPadModeNative2},// SNDW3_CLK
> +    {GPIO_CNL_H_GPP_D18,   GpioPadModeNative2} // SNDW3_DATA
> +  },
> +  { // SNDW4
> +    {GPIO_CNL_H_GPP_D19,   GpioPadModeNative2},// SNDW4_CLK
> +    {GPIO_CNL_H_GPP_D20,   GpioPadModeNative2} // SNDW4_DATA
> +  }
> +};
> +
> +/**
> +  This function provides SNDW interface pins
> +
> +  @param[in]  SndwInterfaceNumber      SNDWx interface number
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetHdaSndwPins (
> +  IN  UINT32                      SndwInterfaceNumber,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (SndwInterfaceNumber < ARRAY_SIZE (mPchLpHdaSndwGpio)) {
> +      *NativePinsTable = mPchLpHdaSndwGpio[SndwInterfaceNumber];
> +      return;
> +    }
> +  } else {
> +    if (SndwInterfaceNumber < ARRAY_SIZE (mPchHHdaSndwGpio)) {
> +      *NativePinsTable = mPchHHdaSndwGpio[SndwInterfaceNumber];
> +      return;
> +    }
> +  }
> +  *NativePinsTable = NULL;
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// GPIO pins for SMBUS
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpSmbusGpio[PCH_GPIO_SMBUS_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_LP_GPP_C0, GpioPadModeNative1},// SMB_CLK
> +  {GPIO_CNL_LP_GPP_C1, GpioPadModeNative1} // SMB_DATA
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHSmbusGpio[PCH_GPIO_SMBUS_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_H_GPP_C0, GpioPadModeNative1}, // SMB_CLK
> +  {GPIO_CNL_H_GPP_C1, GpioPadModeNative1}  // SMB_DATA
> +};
> +
> +/**
> +  This function provides SMBUS interface pins
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetSmbusPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpSmbusGpio;
> +  } else {
> +    *NativePinsTable = mPchHSmbusGpio;
> +  }
> +}
> +
> +//
> +// SMBUS Alert pin
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpSmbusAlertGpio = {GPIO_CNL_LP_GPP_C2,  GpioPadModeNative1};
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHSmbusAlertGpio = {GPIO_CNL_H_GPP_C2,  GpioPadModeNative1};
> +
> +/**
> +  This function sets SMBUS ALERT pin into native mode
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableSmbusAlert (
> +  VOID
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION SmbusAlertGpio;
> +
> +  if (IsPchLp ()) {
> +    SmbusAlertGpio = mPchLpSmbusAlertGpio;
> +  } else {
> +    SmbusAlertGpio = mPchHSmbusAlertGpio;
> +  }
> +
> +  return GpioSetPadMode (SmbusAlertGpio.Pad, SmbusAlertGpio.Mode);
> +}
> +
> +//
> +// SATADevSlpPin to GPIO pin mapping
> +// SATA_DEVSLP_x -> GPIO pin y
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpSataDevSlpPinToGpioMap[] =
> +{
> +  {GPIO_CNL_LP_GPP_E4, GpioPadModeNative1},
> +  {GPIO_CNL_LP_GPP_E5, GpioPadModeNative1},
> +  {GPIO_CNL_LP_GPP_E6, GpioPadModeNative1}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHSataDevSlpPinToGpioMap[] =
> +{
> +  {GPIO_CNL_H_GPP_E4, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_E5, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_E6, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F5, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F6, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F7, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F8, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F9, GpioPadModeNative1}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mCdfPchSata1DevSlpPinToGpioMap[] =
> +{
> +/// @todo SERVER- update for SATA 1
> +  {GPIO_CNL_H_GPP_E4, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_E5, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_E6, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F5, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F6, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F7, GpioPadModeNative1}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mCdfPchSata2DevSlpPinToGpioMap[] =
> +{
> +/// @todo SERVER- update for SATA 2
> +  {GPIO_CNL_H_GPP_E4, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_E5, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_E6, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F5, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F6, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F7, GpioPadModeNative1}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mCdfPchSata3DevSlpPinToGpioMap[] =
> +{
> +/// @todo SERVER- update for SATA 3
> +  {GPIO_CNL_H_GPP_E4, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_E5, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_E6, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F5, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F6, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_F7, GpioPadModeNative1}
> +};
> +
> +/**
> +  This function provides SATA DevSlp pin data
> +
> +  @param[in]  SataCtrlIndex       SATA controller index
> +  @param[in]  SataPort            SATA port number
> +  @param[out] NativePin           SATA DevSlp pin
> +**/
> +VOID
> +GpioGetSataDevSlpPin (
> +  IN  UINT32                    SataCtrlIndex,
> +  IN  UINTN                     SataPort,
> +  OUT GPIO_PAD_NATIVE_FUNCTION  *NativePin
> +  )
> +{
> +  if (IsCdfPch ()) {
> +    if (SataCtrlIndex == SATA_1_CONTROLLER_INDEX) {
> +      if (SataPort < ARRAY_SIZE (mCdfPchSata1DevSlpPinToGpioMap)) {
> +        *NativePin = mCdfPchSata1DevSlpPinToGpioMap[SataPort];
> +        return;
> +      }
> +    } else if (SataCtrlIndex == SATA_2_CONTROLLER_INDEX) {
> +      if (SataPort < ARRAY_SIZE (mCdfPchSata2DevSlpPinToGpioMap)) {
> +        *NativePin = mCdfPchSata2DevSlpPinToGpioMap[SataPort];
> +        return;
> +      }
> +    } else if (SataCtrlIndex == SATA_3_CONTROLLER_INDEX) {
> +      if (SataPort < ARRAY_SIZE (mCdfPchSata3DevSlpPinToGpioMap)) {
> +        *NativePin = mCdfPchSata3DevSlpPinToGpioMap[SataPort];
> +        return;
> +      }
> +    }
> +  } else {
> +    if (IsPchLp ()) {
> +      if (SataPort < ARRAY_SIZE (mPchLpSataDevSlpPinToGpioMap)) {
> +        *NativePin = mPchLpSataDevSlpPinToGpioMap[SataPort];
> +        return;
> +      }
> +    } else {
> +      if (SataPort < ARRAY_SIZE (mPchHSataDevSlpPinToGpioMap)) {
> +        *NativePin = mPchHSataDevSlpPinToGpioMap[SataPort];
> +        return;
> +      }
> +    }
> +  }
> +  *NativePin = (GPIO_PAD_NATIVE_FUNCTION){0};
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// SATA reset port to GPIO pin mapping
> +// SATAGP_x -> GPIO pin y
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpSataGpToGpioMap[] =
> +{
> +  {GPIO_CNL_LP_GPP_E0, GpioPadModeNative2},
> +  {GPIO_CNL_LP_GPP_E1, GpioPadModeNative2},
> +  {GPIO_CNL_LP_GPP_E2, GpioPadModeNative2}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHSataGpToGpioMap[]  =
> +{
> +  {GPIO_CNL_H_GPP_E0, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_E1, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_E2, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F0, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F1, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F2, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F3, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F4, GpioPadModeNative2}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mCdfPchSata1GpToGpioMap[]  =
> +{
> +/// @todo SERVER- update for SATA 1
> +  {GPIO_CNL_H_GPP_E0, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_E1, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_E2, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F0, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F1, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F2, GpioPadModeNative2}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mCdfPchSata2GpToGpioMap[]  =
> +{
> +/// @todo SERVER- update for SATA 2
> +  {GPIO_CNL_H_GPP_E0, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_E1, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_E2, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F0, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F1, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F2, GpioPadModeNative2}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mCdfPchSata3GpToGpioMap[]  =
> +{
> +/// @todo SERVER- update for SATA 3
> +  {GPIO_CNL_H_GPP_E0, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_E1, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_E2, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F0, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F1, GpioPadModeNative2},
> +  {GPIO_CNL_H_GPP_F2, GpioPadModeNative2}
> +};
> +
> +/**
> +  This function provides SATA GP pin data
> +
> +  @param[in]  SataCtrlIndex       SATA controller index
> +  @param[in]  SataPort            SATA port number
> +  @param[out] NativePin           SATA GP pin
> +**/
> +VOID
> +GpioGetSataGpPin (
> +  IN  UINT32                    SataCtrlIndex,
> +  IN  UINTN                     SataPort,
> +  OUT GPIO_PAD_NATIVE_FUNCTION  *NativePin
> +  )
> +{
> +  if (IsCdfPch ()) {
> +    if (SataCtrlIndex == SATA_1_CONTROLLER_INDEX) {
> +      if (SataPort < ARRAY_SIZE (mCdfPchSata1GpToGpioMap)) {
> +        *NativePin = mCdfPchSata1GpToGpioMap[SataPort];
> +        return;
> +      }
> +    } else if (SataCtrlIndex == SATA_2_CONTROLLER_INDEX) {
> +      if (SataPort < ARRAY_SIZE (mCdfPchSata2GpToGpioMap)) {
> +        *NativePin = mCdfPchSata2GpToGpioMap[SataPort];
> +        return;
> +      }
> +    } else if (SataCtrlIndex == SATA_3_CONTROLLER_INDEX) {
> +      if (SataPort < ARRAY_SIZE (mCdfPchSata3GpToGpioMap)) {
> +        *NativePin = mCdfPchSata3GpToGpioMap[SataPort];
> +        return;
> +      }
> +    }
> +  } else {
> +    if (IsPchLp ()) {
> +      if (SataPort < ARRAY_SIZE (mPchLpSataGpToGpioMap)) {
> +        *NativePin = mPchLpSataGpToGpioMap[SataPort];
> +        return;
> +      }
> +    } else {
> +      if (SataPort < ARRAY_SIZE (mPchHSataGpToGpioMap)) {
> +        *NativePin = mPchHSataGpToGpioMap[SataPort];
> +        return;
> +      }
> +    }
> +  }
> +  *NativePin = (GPIO_PAD_NATIVE_FUNCTION){0};
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// SATA LED pin
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpSataLedGpio = {GPIO_CNL_LP_GPP_E8, GpioPadModeNative1};
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHSataLedGpio = {GPIO_CNL_H_GPP_E8, GpioPadModeNative1};
> +
> +/**
> +  This function sets SATA LED pin into native mode. SATA LED indicates
> +  SATA controller activity
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableSataLed (
> +  VOID
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION  SataLedGpio;
> +
> +  if (IsPchLp ()) {
> +    SataLedGpio = mPchLpSataLedGpio;
> +  } else {
> +    SataLedGpio = mPchHSataLedGpio;
> +  }
> +
> +  return GpioSetPadMode (SataLedGpio.Pad, SataLedGpio.Mode);
> +}
> +
> +//
> +// USB2 OC pins
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpUsbOcGpioPins[] =
> +{
> +  {GPIO_CNL_LP_GPP_E9,  GpioPadModeNative1},// USB_OC_0
> +  {GPIO_CNL_LP_GPP_E10, GpioPadModeNative1},// USB_OC_1
> +  {GPIO_CNL_LP_GPP_E11, GpioPadModeNative1},// USB_OC_2
> +  {GPIO_CNL_LP_GPP_E12, GpioPadModeNative1} // USB_OC_3
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHUsbOcGpioPins[] =
> +{
> +  {GPIO_CNL_H_GPP_E9,  GpioPadModeNative1},// USB_OC_0
> +  {GPIO_CNL_H_GPP_E10, GpioPadModeNative1},// USB_OC_1
> +  {GPIO_CNL_H_GPP_E11, GpioPadModeNative1},// USB_OC_2
> +  {GPIO_CNL_H_GPP_E12, GpioPadModeNative1},// USB_OC_3
> +  {GPIO_CNL_H_GPP_F15, GpioPadModeNative1},// USB_OC_4
> +  {GPIO_CNL_H_GPP_F16, GpioPadModeNative1},// USB_OC_5
> +  {GPIO_CNL_H_GPP_F17, GpioPadModeNative1},// USB_OC_6
> +  {GPIO_CNL_H_GPP_F18, GpioPadModeNative1} // USB_OC_7
> +};
> +
> +/**
> +  This function enables USB OverCurrent pins by setting
> +  USB2 OCB pins into native mode
> +
> +  @param[in]  OcPinNumber            USB OC pin number
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableUsbOverCurrent (
> +  IN  UINTN   OcPinNumber
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION  OcGpio;
> +
> +  if (IsPchLp ()) {
> +    if (OcPinNumber >= ARRAY_SIZE (mPchLpUsbOcGpioPins)) {
> +      ASSERT(FALSE);
> +      return EFI_UNSUPPORTED;
> +    }
> +    OcGpio = mPchLpUsbOcGpioPins[OcPinNumber];
> +  } else {
> +    if (OcPinNumber >= ARRAY_SIZE (mPchHUsbOcGpioPins)) {
> +      ASSERT (FALSE);
> +      return EFI_UNSUPPORTED;
> +    }
> +    OcGpio = mPchHUsbOcGpioPins[OcPinNumber];
> +  }
> +
> +  return GpioSetPadMode (OcGpio.Pad, OcGpio.Mode);
> +}
> +
> +//
> +// GPIO pin for PCIE SCRCLKREQB
> +// SCRCLKREQB_x -> GPIO pin y
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpPcieSrcClkReqbPinToGpioMap[] =
> +{
> +  {GPIO_CNL_LP_GPP_B5,  GpioPadModeNative1},
> +  {GPIO_CNL_LP_GPP_B6,  GpioPadModeNative1},
> +  {GPIO_CNL_LP_GPP_B7,  GpioPadModeNative1},
> +  {GPIO_CNL_LP_GPP_B8,  GpioPadModeNative1},
> +  {GPIO_CNL_LP_GPP_B9,  GpioPadModeNative1},
> +  {GPIO_CNL_LP_GPP_B10, GpioPadModeNative1}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHPcieSrcClkReqbPinToGpioMap[]  =
> +{
> +  {GPIO_CNL_H_GPP_B5,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_B6,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_B7,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_B8,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_B9,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_B10, GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H0,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H1,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H2,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H3,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H4,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H5,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H6,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H7,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H8,  GpioPadModeNative1},
> +  {GPIO_CNL_H_GPP_H9,  GpioPadModeNative1}
> +};
> +
> +/**
> +  This function provides PCIe CLKREQ pin data
> +
> +  @param[in]  ClkreqIndex        CLKREQ# number
> +  @param[out] NativePin          Native pin data
> +**/
> +VOID
> +GpioGetPcieClkReqPin (
> +  IN  UINT32                      ClkreqIndex,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    *NativePin
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (ClkreqIndex < ARRAY_SIZE (mPchLpPcieSrcClkReqbPinToGpioMap)) {
> +      *NativePin = mPchLpPcieSrcClkReqbPinToGpioMap[ClkreqIndex];
> +      return;
> +    }
> +  } else {
> +    if (ClkreqIndex < ARRAY_SIZE (mPchHPcieSrcClkReqbPinToGpioMap)) {
> +      *NativePin = mPchHPcieSrcClkReqbPinToGpioMap[ClkreqIndex];
> +      return;
> +    }
> +  }
> +  *NativePin = (GPIO_PAD_NATIVE_FUNCTION){0};
> +  ASSERT (FALSE);
> +}
> +
> +//
> +// PCHHOTB pin
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpPchHotbPin = {GPIO_CNL_LP_GPP_B23,  GpioPadModeNative2};
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHPchHotbPin = {GPIO_CNL_H_GPP_B23,  GpioPadModeNative2};
> +
> +/**
> +  This function sets PCHHOT pin into native mode
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnablePchHot (
> +  VOID
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION PchHotbPin;
> +
> +  if (IsPchLp ()) {
> +    PchHotbPin = mPchLpPchHotbPin;
> +  } else {
> +    PchHotbPin = mPchHPchHotbPin;
> +  }
> +
> +  return GpioSetPadMode (PchHotbPin.Pad, PchHotbPin.Mode);
> +}
> +
> +//
> +// VRALERTB pin
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpVrAlertbPin = {GPIO_CNL_LP_GPP_B2, GpioPadModeNative1};
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHVrAlertbPin = {GPIO_CNL_H_GPP_B2, GpioPadModeNative1};
> +
> +//
> +// CPU_C10_GATE pin
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpCpuC10GatePin = {GPIO_CNL_LP_GPP_H18, GpioPadModeNative1};
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHCpuC10GatePin = {GPIO_CNL_H_GPP_J1, GpioPadModeNative2};
> +
> +/**
> +  This function sets VRALERTB pin into native mode
> +
> +  @param[in]  none
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableVrAlert (
> +  VOID
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION  VrAlertGpio;
> +
> +  if (IsPchLp ()) {
> +    VrAlertGpio = mPchLpVrAlertbPin;
> +  } else {
> +    VrAlertGpio = mPchHVrAlertbPin;
> +  }
> +
> +  return GpioSetPadMode (VrAlertGpio.Pad, VrAlertGpio.Mode);
> +}
> +
> +/**
> +This function sets CPU C10 Gate pins into native mode
> +
> +@retval Status
> +**/
> +EFI_STATUS
> +GpioEnableCpuC10GatePin (
> +  VOID
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION  CpuC10GateGpio;
> +
> +  if (IsPchLp ()) {
> +    CpuC10GateGpio = mPchLpCpuC10GatePin;
> +  } else {
> +    CpuC10GateGpio = mPchHCpuC10GatePin;
> +  }
> +
> +  return GpioSetPadMode (CpuC10GateGpio.Pad, CpuC10GateGpio.Mode);
> +}
> +
> +//
> +// CPU GP pins
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpCpuGpPinMap[PCH_GPIO_CPU_GP_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_LP_GPP_E3, GpioPadModeNative1}, // CPU_GP_0
> +  {GPIO_CNL_LP_GPP_E7, GpioPadModeNative1}, // CPU_GP_1
> +  {GPIO_CNL_LP_GPP_B3, GpioPadModeNative1}, // CPU_GP_2
> +  {GPIO_CNL_LP_GPP_B4, GpioPadModeNative1}, // CPU_GP_3
> +};
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHCpuGpPinMap[PCH_GPIO_CPU_GP_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_H_GPP_E3, GpioPadModeNative1}, // CPU_GP_0
> +  {GPIO_CNL_H_GPP_E7, GpioPadModeNative1}, // CPU_GP_1
> +  {GPIO_CNL_H_GPP_B3, GpioPadModeNative1}, // CPU_GP_2
> +  {GPIO_CNL_H_GPP_B4, GpioPadModeNative1}, // CPU_GP_3
> +};
> +
> +/**
> +  This function sets CPU GP pins into native mode
> +
> +  @param[in]  CpuGpPinNum               CPU GP pin number
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableCpuGpPin (
> +  IN  UINT32                            CpuGpPinNum
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION CpuGpPin;
> +
> +  if (IsPchLp ()) {
> +    if (CpuGpPinNum >= ARRAY_SIZE (mPchLpCpuGpPinMap)) {
> +      ASSERT (FALSE);
> +      return EFI_UNSUPPORTED;
> +    }
> +    CpuGpPin = mPchLpCpuGpPinMap[CpuGpPinNum];
> +  } else {
> +    if (CpuGpPinNum >= ARRAY_SIZE (mPchHCpuGpPinMap)) {
> +      ASSERT(FALSE);
> +      return EFI_UNSUPPORTED;
> +    }
> +    CpuGpPin = mPchHCpuGpPinMap[CpuGpPinNum];
> +  }
> +
> +  return GpioSetPadMode (CpuGpPin.Pad, CpuGpPin.Mode);
> +}
> +
> +//
> +// DDSP_HPD pins
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpDdspHpdPins[] =
> +{
> +  {GPIO_CNL_LP_GPP_E13, GpioPadModeNative1},// DDSP_HPD_0
> +  {GPIO_CNL_LP_GPP_E14, GpioPadModeNative1},// DDSP_HPD_1
> +  {GPIO_CNL_LP_GPP_E15, GpioPadModeNative1},// DDSP_HPD_2
> +  {GPIO_CNL_LP_GPP_E16, GpioPadModeNative1} // DDSP_HPD_3
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHDdspHpdPins[] =
> +{
> +  {GPIO_CNL_H_GPP_I0, GpioPadModeNative1},// DDSP_HPD_0
> +  {GPIO_CNL_H_GPP_I1, GpioPadModeNative1},// DDSP_HPD_1
> +  {GPIO_CNL_H_GPP_I2, GpioPadModeNative1},// DDSP_HPD_2
> +  {GPIO_CNL_H_GPP_I3, GpioPadModeNative1} // DDSP_HPD_3
> +};
> +
> +/**
> +  This function sets DDSP_HPDx pin into native mode
> +
> +  @param[in]  DdspHpdPin     DDSP_HPDx pin
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioEnableDpHotPlugDetect (
> +  IN GPIO_DDSP_HPD  DdspHpdPin
> +  )
> +{
> +  GPIO_PAD_NATIVE_FUNCTION  DdspHpdGpio;
> +  UINT32                    DdspHpdPinIndex;
> +
> +  if (DdspHpdPin > GpioDdspHpd3) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  DdspHpdPinIndex = DdspHpdPin - GpioDdspHpd0;
> +
> +  if (IsPchLp ()) {
> +    if (DdspHpdPinIndex >= ARRAY_SIZE (mPchLpDdspHpdPins)) {
> +      goto Error;
> +    }
> +    DdspHpdGpio = mPchLpDdspHpdPins[DdspHpdPinIndex];
> +  } else {
> +    if (DdspHpdPinIndex >= ARRAY_SIZE (mPchHDdspHpdPins)) {
> +      goto Error;
> +    }
> +    DdspHpdGpio = mPchHDdspHpdPins[DdspHpdPinIndex];
> +  }
> +
> +  return GpioSetPadMode (DdspHpdGpio.Pad, DdspHpdGpio.Mode);
> +Error:
> +  ASSERT (FALSE);
> +  return EFI_UNSUPPORTED;
> +}
> +
> +//
> +// EDP HPD, VDD and BKLT pins
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpEdpPins[PCH_GPIO_EDP_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_LP_GPP_E17,         GpioPadModeNative1},// EDP_HPD
> +  {GPIO_CNL_LP_HVMOS_L_VDDEN,   GpioPadModeNative1},// VDDEN
> +  {GPIO_CNL_LP_HVMOS_L_BKLTEN,  GpioPadModeNative1},// BKLTEN
> +  {GPIO_CNL_LP_HVMOS_L_BKLTCTL, GpioPadModeNative1} // BKLTCTL
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHEdpPins[PCH_GPIO_EDP_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_H_GPP_I4,  GpioPadModeNative1},// EDP_HPD
> +  {GPIO_CNL_H_GPP_F19, GpioPadModeNative1},// VDDEN
> +  {GPIO_CNL_H_GPP_F20, GpioPadModeNative1},// BKLTEN
> +  {GPIO_CNL_H_GPP_F21, GpioPadModeNative1} // BKLTCTL
> +};
> +
> +/**
> +  This function provides eDP pins
> +
> +  @param[out] NativePinsTable                Table with pins
> +  @param[out] NoOfNativePins                 Number of pins
> +**/
> +VOID
> +GpioGetEdpPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable,
> +  OUT UINT32                      *NoOfNativePins
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpEdpPins;
> +    *NoOfNativePins = ARRAY_SIZE (mPchLpEdpPins);
> +  } else {
> +    *NativePinsTable = mPchHEdpPins;
> +    *NoOfNativePins = ARRAY_SIZE (mPchHEdpPins);
> +  }
> +}
> +
> +//
> +// DDPB/C/D/F  CTRLCLK and CTRLDATA pins
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpDdpInterfacePins[PCH_GPIO_DDP_NUMBER_OF_INTERFACES][PCH_G
> PIO_DDP_NUMBER_OF_PINS] =
> +{
> +  {// DDPB
> +    {GPIO_CNL_LP_GPP_E18, GpioPadModeNative1},// DDPB_CTRLCLK
> +    {GPIO_CNL_LP_GPP_E19, GpioPadModeNative1} // DDPB_CTRLDATA
> +  },
> +  {// DDPC
> +    {GPIO_CNL_LP_GPP_E20, GpioPadModeNative1},// DDPC_CTRLCLK
> +    {GPIO_CNL_LP_GPP_E21, GpioPadModeNative1} // DDPC_CTRLDATA
> +  },
> +  {// DDPD
> +    {GPIO_CNL_LP_GPP_E22, GpioPadModeNative1},// DDPD_CTRLCLK
> +    {GPIO_CNL_LP_GPP_E23, GpioPadModeNative1} // DDPD_CTRLDATA
> +  },
> +  {// DDPF
> +    {GPIO_CNL_LP_GPP_H16, GpioPadModeNative1},// DDPF_CTRLCLK
> +    {GPIO_CNL_LP_GPP_H17, GpioPadModeNative1} // DDPF_CTRLDATA
> +  }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHDdpInterfacePins[PCH_GPIO_DDP_NUMBER_OF_INTERFACES][PCH_GP
> IO_DDP_NUMBER_OF_PINS] =
> +{
> +  {// DDPB
> +    {GPIO_CNL_H_GPP_I5,  GpioPadModeNative1}, // DDPB_CTRLCLK
> +    {GPIO_CNL_H_GPP_I6,  GpioPadModeNative1}, // DDPB_CTRLDATA
> +  },
> +  {// DDPC
> +    {GPIO_CNL_H_GPP_I7,  GpioPadModeNative1}, // DDPC_CTRLCLK
> +    {GPIO_CNL_H_GPP_I8,  GpioPadModeNative1}, // DDPC_CTRLDATA
> +  },
> +  {// DDPD
> +    {GPIO_CNL_H_GPP_I9,  GpioPadModeNative1}, // DDPD_CTRLCLK
> +    {GPIO_CNL_H_GPP_I10, GpioPadModeNative1}, // DDPD_CTRLDATA
> +  },
> +  {// DDPF
> +    {GPIO_CNL_H_GPP_F22, GpioPadModeNative1}, // DDPF_CTRLCLK
> +    {GPIO_CNL_H_GPP_F23, GpioPadModeNative1}, // DDPF_CTRLDATA
> +  }
> +};
> +
> +/**
> +  This function provides DDPx interface pins
> +
> +  @param[in]  DdpInterface   DDPx interface
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetDdpPins (
> +  IN  GPIO_DDP                    DdpInterface,
> +  OUT GPIO_PAD_NATIVE_FUNCTION    **NativePinsTable
> +  )
> +{
> +  UINT32  DdpInterfaceIndex;
> +
> +  switch (DdpInterface) {
> +    case GpioDdpB:
> +    case GpioDdpC:
> +    case GpioDdpD:
> +      DdpInterfaceIndex = DdpInterface - GpioDdpB;
> +      break;
> +    case GpioDdpF:
> +      DdpInterfaceIndex = 3;
> +      break;
> +    default:
> +      goto Error;
> +  }
> +
> +  if (IsPchLp ()) {
> +    if (DdpInterfaceIndex < ARRAY_SIZE (mPchLpDdpInterfacePins)) {
> +      *NativePinsTable = mPchLpDdpInterfacePins[DdpInterfaceIndex];
> +      return;
> +    }
> +  } else {
> +    if (DdpInterfaceIndex < ARRAY_SIZE (mPchHDdpInterfacePins)) {
> +      *NativePinsTable = mPchHDdpInterfacePins[DdpInterfaceIndex];
> +      return;
> +    }
> +  }
> +Error:
> +  *NativePinsTable = NULL;
> +  ASSERT(FALSE);
> +}
> +
> +/**
> +  This function enables CNVi RF Reset pin
> +**/
> +VOID
> +GpioEnableCnviRfResetPin (
> +  VOID
> +  )
> +{
> +  EFI_STATUS      Status;
> +  GPIO_PAD        GpioPad;
> +  GPIO_PAD_MODE   PadMode;
> +
> +  if (IsPchLp ()) {
> +    GpioPad = GPIO_CNL_LP_GPP_H1;
> +    PadMode = GpioPadModeNative3;
> +  } else {
> +    GpioPad = GPIO_CNL_H_GPP_D5;
> +    PadMode = GpioPadModeNative3;
> +  }
> +
> +  Status = GpioSetPadMode (GpioPad, PadMode);
> +  ASSERT_EFI_ERROR (Status);
> +}
> +
> +/**
> +  This function enables CNVi MODEM CLKREQ pin
> +**/
> +VOID
> +GpioEnableCnviModemClkReqPin (
> +  VOID
> +  )
> +{
> +  EFI_STATUS      Status;
> +  GPIO_PAD        GpioPad;
> +  GPIO_PAD_MODE   PadMode;
> +
> +  if (IsPchLp ()) {
> +    GpioPad = GPIO_CNL_LP_GPP_H2;
> +    PadMode = GpioPadModeNative3;
> +  } else {
> +    GpioPad = GPIO_CNL_H_GPP_D6;
> +    PadMode = GpioPadModeNative3;
> +  }
> +
> +  Status = GpioSetPadMode (GpioPad, PadMode);
> +  ASSERT_EFI_ERROR (Status);
> +}
> +
> +
> +/**
> +  This function provides CNVi BT interface select pin
> +
> +  @retval GpioPad          GPIO pad for CNVi BT interface select
> +**/
> +GPIO_PAD
> +GpioGetCnviBtIfSelectPin (
> +  VOID
> +  )
> +{
> +  if (IsPchLp ()) {
> +    return GPIO_CNL_LP_VGPIO5;
> +  } else {
> +    return GPIO_CNL_H_VGPIO7;
> +  }
> +}
> +
> +/**
> +  This function provides CNVi BT Charging pin
> +
> +  @retval GpioPad          GPIO pad for CNVi BT Charging select
> +**/
> +GPIO_PAD
> +GpioGetCnviBtChargingPin (
> +  VOID
> +  )
> +{
> +  if (IsPchLp ()) {
> +    return GPIO_CNL_LP_VGPIO3;
> +  } else {
> +    return GPIO_CNL_H_VGPIO3;
> +  }
> +}
> +
> +/**
> +  This function provides CNVi A4WP pin
> +
> +  @param[out] GpioNativePad       GPIO native pad for CNVi A4WP
> +**/
> +VOID
> +GpioGetCnviA4WpPin (
> +  OUT GPIO_PAD_NATIVE_FUNCTION  *GpioNativePad
> +  )
> +{
> +  GpioNativePad->Mode = GpioPadModeNative1;
> +  if (IsPchLp ()) {
> +    GpioNativePad->Pad = GPIO_CNL_LP_GPP_F23;
> +  } else {
> +    GpioNativePad->Pad = GPIO_CNL_H_GPP_J11;
> +  }
> +}
> +
> +/**
> +  This function provides CNVi BT host wake int pin
> +
> +  @retval GpioPad          GPIO pad BT host wake int
> +**/
> +GPIO_PAD
> +GpioGetCnviBtHostWakeIntPin (
> +  VOID
> +  )
> +{
> +  if (IsPchLp ()) {
> +    return GPIO_CNL_LP_VGPIO4;
> +  } else {
> +    return GPIO_CNL_H_VGPIO4;
> +  }
> +}
> +
> +//
> +// CNVi Bluetooth UART pads
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchLpVCnviBtUartGpioPad[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS] =
> +{
> +  GPIO_CNL_LP_VGPIO6, // vCNV_BT_UART_TXD
> +  GPIO_CNL_LP_VGPIO7, // vCNV_BT_UART_RXD
> +  GPIO_CNL_LP_VGPIO8, // vCNV_BT_UART_CTS_B
> +  GPIO_CNL_LP_VGPIO9  // vCNV_BT_UART_RTS_B
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchHVCnviBtUartGpioPad[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS] =
> +{
> +  GPIO_CNL_H_VGPIO8, // vCNV_BT_UART_TXD
> +  GPIO_CNL_H_VGPIO9, // vCNV_BT_UART_RXD
> +  GPIO_CNL_H_VGPIO10,// vCNV_BT_UART_CTS_B
> +  GPIO_CNL_H_VGPIO11 // vCNV_BT_UART_RTS_B
> +};
> +
> +//
> +// vUART for Bluetooth
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchLpVUartForCnviBtGpioPad[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS]
> =
> +{
> +  GPIO_CNL_LP_VGPIO18, // vUART0_TXD
> +  GPIO_CNL_LP_VGPIO19, // vUART0_RXD
> +  GPIO_CNL_LP_VGPIO20, // vUART0_CTS_B
> +  GPIO_CNL_LP_VGPIO21  // vUART0_RTS_B
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchHVUartForCnviBtGpioPad[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS] =
> +{
> +  GPIO_CNL_H_VGPIO20, // vUART0_TXD
> +  GPIO_CNL_H_VGPIO21, // vUART0_RXD
> +  GPIO_CNL_H_VGPIO22, // vUART0_CTS_B
> +  GPIO_CNL_H_VGPIO23  // vUART0_RTS_B
> +};
> +
> +/**
> +  This function provides CNVi BT UART pins
> +
> +  @param[in]  ConnectionType           CNVi BT UART connection type
> +  @param[out] VCnviBtUartPad           Table with vCNV_BT_UARTx pads
> +  @param[out] VCnviBtUartPadMode       vCNV_BT_UARTx pad mode
> +  @param[out] VUartForCnviBtPad        Table with vUART0 pads
> +  @param[out] VUartForCnviBtPadMode    vUART0 pad mode
> +**/
> +VOID
> +GpioGetCnviBtUartPins (
> +  IN  VGPIO_CNVI_BT_UART_CONNECTION_TYPE  ConnectionType,
> +  OUT GPIO_PAD                            **VCnviBtUartPad,
> +  OUT GPIO_PAD_MODE                       *VCnviBtUartPadMode,
> +  OUT GPIO_PAD                            **VUartForCnviBtPad,
> +  OUT GPIO_PAD_MODE                       *VUartForCnviBtPadMode
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *VCnviBtUartPad = mPchLpVCnviBtUartGpioPad;
> +    *VUartForCnviBtPad = mPchLpVUartForCnviBtGpioPad;
> +  } else {
> +    *VCnviBtUartPad = mPchHVCnviBtUartGpioPad;
> +    *VUartForCnviBtPad = mPchHVUartForCnviBtGpioPad;
> +  }
> +
> +  switch (ConnectionType) {
> +    case GpioCnviBtUartToSerialIoUart0:
> +      *VCnviBtUartPadMode = GpioPadModeNative1;
> +      *VUartForCnviBtPadMode = GpioPadModeNative1;
> +      break;
> +    case GpioCnviBtUartToIshUart0:
> +      *VCnviBtUartPadMode = GpioPadModeNative2;
> +      *VUartForCnviBtPadMode = GpioPadModeNative1;
> +      break;
> +    case GpioCnviBtUartNotConnected:
> +    case GpioCnviBtUartToExternalPads:
> +      *VCnviBtUartPadMode = GpioPadModeGpio;
> +      *VUartForCnviBtPadMode = GpioPadModeGpio;
> +      break;
> +    default:
> +      ASSERT (FALSE);
> +      return;
> +  }
> +}
> +
> +//
> +// CNVi Bluetooth UART external pads
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpCnviBtUartExternalPads[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS]
> =
> +{
> +  {GPIO_CNL_LP_GPP_C8,  GpioPadModeNative2}, // CNV_BT_UART_0_RXD
> +  {GPIO_CNL_LP_GPP_C9,  GpioPadModeNative2}, // CNV_BT_UART_0_TXD
> +  {GPIO_CNL_LP_GPP_C10, GpioPadModeNative2}, // CNV_BT_UART_0_RTS
> +  {GPIO_CNL_LP_GPP_C11, GpioPadModeNative2}  // CNV_BT_UART_0_CTS
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHCnviBtUartExternalPads[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_H_GPP_C8,  GpioPadModeNative2}, // CNV_BT_UART_0_RXD
> +  {GPIO_CNL_H_GPP_C9,  GpioPadModeNative2}, // CNV_BT_UART_0_TXD
> +  {GPIO_CNL_H_GPP_C10, GpioPadModeNative2}, // CNV_BT_UART_0_RTS
> +  {GPIO_CNL_H_GPP_C11, GpioPadModeNative2}  // CNV_BT_UART_0_CTS
> +};
> +
> +/**
> +  This function provides CNVi BT UART external pads
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetCnviBtUartExternalPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpCnviBtUartExternalPads;
> +  } else {
> +    *NativePinsTable = mPchHCnviBtUartExternalPads;
> +  }
> +}
> +
> +//
> +// CNVi Bluetooth I2S pads
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchLpVCnviBtI2sGpioPad[PCH_GPIO_CNVI_SSP_NUMBER_OF_PINS] =
> +{
> +  GPIO_CNL_LP_VGPIO30, // vCNV_BT_I2S_BCLK
> +  GPIO_CNL_LP_VGPIO31, // vCNV_BT_I2S_WS_SYNC
> +  GPIO_CNL_LP_VGPIO32, // vCNV_BT_I2S_SDO
> +  GPIO_CNL_LP_VGPIO33  // vCNV_BT_I2S_SDI
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchHVCnviBtI2sGpioPad[PCH_GPIO_CNVI_SSP_NUMBER_OF_PINS] =
> +{
> +  GPIO_CNL_H_VGPIO32, // vCNV_BT_I2S_BCLK
> +  GPIO_CNL_H_VGPIO33, // vCNV_BT_I2S_WS_SYNC
> +  GPIO_CNL_H_VGPIO34, // vCNV_BT_I2S_SDO
> +  GPIO_CNL_H_VGPIO35  // vCNV_BT_I2S_SDI
> +};
> +
> +//
> +// vSSP for Bluetooth
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchLpVSspForCnviBtGpioPad[PCH_GPIO_CNVI_SSP_NUMBER_OF_PINS] =
> +{
> +  GPIO_CNL_LP_VGPIO34, // vSSP2_SCLK
> +  GPIO_CNL_LP_VGPIO35, // vSSP2_SFRM
> +  GPIO_CNL_LP_VGPIO36, // vSSP2_TXD
> +  GPIO_CNL_LP_VGPIO37  // vSSP2_RXD
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchHVSspForCnviBtGpioPad[PCH_GPIO_CNVI_SSP_NUMBER_OF_PINS] =
> +{
> +  GPIO_CNL_H_VGPIO36, // vSSP2_SCLK
> +  GPIO_CNL_H_VGPIO37, // vSSP2_SFRM
> +  GPIO_CNL_H_VGPIO38, // vSSP2_TXD
> +  GPIO_CNL_H_VGPIO39  // vSSP2_RXD
> +};
> +
> +/**
> +  This function provides CNVi BT I2S pins
> +
> +  @param[in]  ConnectionType          CNVi BT I2S connection type
> +  @param[out] VCnviBtI2sPad           Table with vCNV_BT_I2Sx pads
> +  @param[out] VCnviBtI2sPadMode       vCNV_BT_I2Sx pad mode
> +  @param[out] VSspForCnviBtPad        Table with vSSP2 pads
> +  @param[out] VSspForCnviBtPadMode    vSSP2 pad mode
> +**/
> +VOID
> +GpioGetCnviBtI2sPins (
> +  IN  VGPIO_CNVI_BT_I2S_CONNECTION_TYPE  ConnectionType,
> +  OUT GPIO_PAD                 **VCnviBtI2sPad,
> +  OUT GPIO_PAD_MODE            *VCnviBtI2sPadMode,
> +  OUT GPIO_PAD                 **VSspForCnviBtPad,
> +  OUT GPIO_PAD_MODE            *VSspForCnviBtPadMode
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *VCnviBtI2sPad = mPchLpVCnviBtI2sGpioPad;
> +    *VSspForCnviBtPad = mPchLpVSspForCnviBtGpioPad;
> +  } else {
> +    *VCnviBtI2sPad = mPchHVCnviBtI2sGpioPad;
> +    *VSspForCnviBtPad = mPchHVSspForCnviBtGpioPad;
> +  }
> +
> +  switch (ConnectionType) {
> +    case GpioCnviBtI2sToSsp0:
> +      *VCnviBtI2sPadMode = GpioPadModeNative1;
> +      *VSspForCnviBtPadMode = GpioPadModeNative1;
> +      break;
> +    case GpioCnviBtI2sToSsp1:
> +      *VCnviBtI2sPadMode = GpioPadModeNative2;
> +      *VSspForCnviBtPadMode = GpioPadModeNative1;
> +      break;
> +    case GpioCnviBtI2sToSsp2:
> +      *VCnviBtI2sPadMode = GpioPadModeNative3;
> +      *VSspForCnviBtPadMode = GpioPadModeNative1;
> +      break;
> +    case GpioCnviBtI2sNotConnected:
> +    case GpioCnviBtI2sToExternalPads:
> +      *VCnviBtI2sPadMode = GpioPadModeGpio;
> +      *VSspForCnviBtPadMode = GpioPadModeGpio;
> +      break;
> +    default:
> +      ASSERT (FALSE);
> +      return;
> +  }
> +}
> +
> +//
> +// CNVi Bluetooth I2S external pads
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpCnviBtI2sExternalPads[PCH_GPIO_CNVI_SSP_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_LP_GPP_H0, GpioPadModeNative2}, // CNV_BT_I2S_WS_SYNC
> +  {GPIO_CNL_LP_GPP_H1, GpioPadModeNative2}, // CNV_BT_I2S_BCLK
> +  {GPIO_CNL_LP_GPP_H2, GpioPadModeNative2}, // CNV_BT_I2S_SDI
> +  {GPIO_CNL_LP_GPP_H3, GpioPadModeNative2}  // CNV_BT_I2S_SDO
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHCnviBtI2sExternalPads[PCH_GPIO_CNVI_SSP_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_H_GPP_D8, GpioPadModeNative2}, // CNV_BT_I2S_WS_SYNC
> +  {GPIO_CNL_H_GPP_D5, GpioPadModeNative2}, // CNV_BT_I2S_BCLK
> +  {GPIO_CNL_H_GPP_D6, GpioPadModeNative2}, // CNV_BT_I2S_SDI
> +  {GPIO_CNL_H_GPP_D7, GpioPadModeNative2}  // CNV_BT_I2S_SDO
> +};
> +
> +/**
> +  This function provides CNVi BT I2S external pads
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetCnviBtI2sExternalPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpCnviBtI2sExternalPads;
> +  } else {
> +    *NativePinsTable = mPchHCnviBtI2sExternalPads;
> +  }
> +}
> +
> +//
> +// CNVi MFUART1 pads
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchLpVCnviMfUart1GpioPad[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS] =
> +{
> +  GPIO_CNL_LP_VGPIO10, // vCNV_MFUART1_TXD
> +  GPIO_CNL_LP_VGPIO11, // vCNV_MFUART1_RXD
> +  GPIO_CNL_LP_VGPIO12, // vCNV_MFUART1_CTS_B
> +  GPIO_CNL_LP_VGPIO13  // vCNV_MFUART1_RTS_B
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchHVCnviMfUart1GpioPad[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS] =
> +{
> +  GPIO_CNL_H_VGPIO12, // vCNV_MFUART1_TXD
> +  GPIO_CNL_H_VGPIO13, // vCNV_MFUART1_RXD
> +  GPIO_CNL_H_VGPIO14, // vCNV_MFUART1_CTS_B
> +  GPIO_CNL_H_VGPIO15  // vCNV_MFUART1_RTS_B
> +};
> +
> +//
> +// vUART for MFUART1
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchLpVUartForCnviMfUart1GpioPad[PCH_GPIO_CNVI_UART_NUMBER_OF_
> PINS] =
> +{
> +  GPIO_CNL_LP_VGPIO22, // vISH_UART0_TXD
> +  GPIO_CNL_LP_VGPIO23, // vISH_UART0_RXD
> +  GPIO_CNL_LP_VGPIO24, // vISH_UART0_CTS_B
> +  GPIO_CNL_LP_VGPIO25  // vISH_UART0_RTS_B
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD
> mPchHVUartForCnviMfUart1GpioPad[PCH_GPIO_CNVI_UART_NUMBER_OF_
> PINS] =
> +{
> +  GPIO_CNL_H_VGPIO24, // vISH_UART0_TXD
> +  GPIO_CNL_H_VGPIO25, // vISH_UART0_RXD
> +  GPIO_CNL_H_VGPIO26, // vISH_UART0_CTS_B
> +  GPIO_CNL_H_VGPIO27  // vISH_UART0_RTS_B
> +};
> +
> +/**
> +  This function provides CNVi MFUART1 pins
> +
> +  @param[in]  ConnectionType          CNVi MFUART1 connection type
> +  @param[out] VCnviBtI2sPad           Table with vCNV_MFUART1x pads
> +  @param[out] VCnviBtI2sPadMode       vCNV_MFUART1x pad mode
> +  @param[out] VSspForCnviBtPad        Table with vISH_UART0 pads
> +  @param[out] VSspForCnviBtPadMode    vISH_UART0 pad mode
> +**/
> +VOID
> +GpioGetCnviMfUart1Pins (
> +  IN  VGPIO_CNVI_MF_UART1_CONNECTION_TYPE  ConnectionType,
> +  OUT GPIO_PAD                 **VCnviMfUart1Pad,
> +  OUT GPIO_PAD_MODE            *VCnviMfUart1PadMode,
> +  OUT GPIO_PAD                 **VUartForCnviMfUart1Pad,
> +  OUT GPIO_PAD_MODE            *VUartForCnviMfUart1PadMode
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *VCnviMfUart1Pad = mPchLpVCnviMfUart1GpioPad;
> +    *VUartForCnviMfUart1Pad = mPchLpVUartForCnviMfUart1GpioPad;
> +  } else {
> +    *VCnviMfUart1Pad = mPchHVCnviMfUart1GpioPad;
> +    *VUartForCnviMfUart1Pad = mPchHVUartForCnviMfUart1GpioPad;
> +  }
> +
> +  switch (ConnectionType) {
> +    case GpioCnviMfUart1ToSerialIoUart2:
> +      *VCnviMfUart1PadMode = GpioPadModeNative2;
> +      *VUartForCnviMfUart1PadMode = GpioPadModeNative1;
> +      break;
> +    case GpioCnviMfUart1ToIshUart0:
> +      *VCnviMfUart1PadMode = GpioPadModeNative1;
> +      *VUartForCnviMfUart1PadMode = GpioPadModeNative1;
> +      break;
> +    case GpioCnviMfUart1NotConnected:
> +    case GpioCnviMfUart1ToExternalPads:
> +      *VCnviMfUart1PadMode = GpioPadModeGpio;
> +      *VUartForCnviMfUart1PadMode = GpioPadModeGpio;
> +      break;
> +    default:
> +      ASSERT (FALSE);
> +      return;
> +  }
> +}
> +
> +//
> +// CNVi MFUART1 external pads
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpCnviMfUart1ExternalPads[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS]
> =
> +{
> +  {GPIO_CNL_LP_GPP_C12, GpioPadModeNative3}, // CNV_MFUART1_RXD
> +  {GPIO_CNL_LP_GPP_C13, GpioPadModeNative3}, // CNV_MFUART1_TXD
> +  {GPIO_CNL_LP_GPP_C14, GpioPadModeNative3}, // CNV_MFUART1_RTS
> +  {GPIO_CNL_LP_GPP_C15, GpioPadModeNative3}  // CNV_MFUART1_CTS
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHCnviMfUart1ExternalPads[PCH_GPIO_CNVI_UART_NUMBER_OF_PINS]
> =
> +{
> +  {GPIO_CNL_H_GPP_C12, GpioPadModeNative3}, // CNV_MFUART1_RXD
> +  {GPIO_CNL_H_GPP_C13, GpioPadModeNative3}, // CNV_MFUART1_TXD
> +  {GPIO_CNL_H_GPP_C14, GpioPadModeNative3}, // CNV_MFUART1_RTS
> +  {GPIO_CNL_H_GPP_C15, GpioPadModeNative3}  // CNV_MFUART1_CTS
> +};
> +
> +/**
> +  This function provides CNVi MFUART1 external pads
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetCnviMfUart1ExternalPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpCnviMfUart1ExternalPads;
> +  } else {
> +    *NativePinsTable = mPchHCnviMfUart1ExternalPads;
> +  }
> +}
> +
> +/**
> +  This function provides CNVi Bluetooth Enable pad
> +
> +  @retval GpioPad           CNVi Bluetooth Enable pad
> +**/
> +GPIO_PAD
> +GpioGetCnviBtEnablePin (
> +  VOID
> +  )
> +{
> +  if (IsPchLp ()) {
> +    return GPIO_CNL_LP_VGPIO0;
> +  } else {
> +    return GPIO_CNL_H_VGPIO0;
> +  }
> +}
> +
> +//
> +// CNVi BRI (Bluetooth Radio Interface) and RGI (Radio Generic Interface)
> buses from Pulsar to CRF (Companion RF)
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpCnviBriRgiGpioPad[PCH_GPIO_CNVI_BRI_RGI_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_LP_GPP_F4, GpioPadModeNative1}, // CNV_BRI_DT
> +  {GPIO_CNL_LP_GPP_F5, GpioPadModeNative1}, // CNV_BRI_RSP
> +  {GPIO_CNL_LP_GPP_F6, GpioPadModeNative1}, // CNV_RGI_DT
> +  {GPIO_CNL_LP_GPP_F7, GpioPadModeNative1}  // CNV_RGI_RSP
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHCnviBriRgiGpioPad[PCH_GPIO_CNVI_BRI_RGI_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_H_GPP_J4, GpioPadModeNative1}, // CNV_BRI_DT
> +  {GPIO_CNL_H_GPP_J5, GpioPadModeNative1}, // CNV_BRI_RSP
> +  {GPIO_CNL_H_GPP_J6, GpioPadModeNative1}, // CNV_RGI_DT
> +  {GPIO_CNL_H_GPP_J7, GpioPadModeNative1}  // CNV_RGI_RSP
> +};
> +
> +/**
> +  This function provides CNVi BRI RGI GPIO pads
> +
> +  @param[out] NativePinsTable          Table with pins
> +**/
> +VOID
> +GpioGetCnvBriRgiPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpCnviBriRgiGpioPad;
> +  } else {
> +    *NativePinsTable = mPchHCnviBriRgiGpioPad;
> +  }
> +}
> +
> +
> +/**
> +  This function sets CNVi WiFi mode
> +
> +  @param[in] Value                CNVi WiFi Mode value
> +                                  GpioCnviWiFiAuto: WiFi is automatically
> enabled/disabled by WiFi core
> +                                  GpioCnviWiFiEnabled: WiFi is enabled regardless of
> WiFi core decision
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioSetCnviWifiMode (
> +  IN  VGPIO_CNVI_WIFI_MODE  WiFiMode
> +  )
> +{
> +  EFI_STATUS  Status;
> +  GPIO_PAD    CnviWifiModePad;
> +  GPIO_CONFIG PadConfig;
> +
> +  ZeroMem (&PadConfig, sizeof (PadConfig));
> +
> +  PadConfig.PadMode = GpioPadModeGpio;
> +  PadConfig.Direction = GpioDirOut;
> +  if (WiFiMode == GpioCnviWiFiEnabled) {
> +    PadConfig.OutputState = GpioOutHigh;
> +  } else {
> +    PadConfig.OutputState = GpioOutLow;
> +  }
> +
> +  if (IsPchLp ()) {
> +    CnviWifiModePad = GPIO_CNL_LP_VGPIO2;
> +  } else {
> +    CnviWifiModePad = GPIO_CNL_H_VGPIO2;
> +  }
> +
> +  Status = GpioSetPadConfig (CnviWifiModePad, &PadConfig);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchLpImguClkOutGpioPad[SA_GPIO_IMGUCLK_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_LP_GPP_D4,  GpioPadModeNative1}, // IMGCLKOUT_0
> +  {GPIO_CNL_LP_GPP_H20, GpioPadModeNative1}, // IMGCLKOUT_1
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_PAD_NATIVE_FUNCTION
> mPchHImguClkOutGpioPad[SA_GPIO_IMGUCLK_NUMBER_OF_PINS] =
> +{
> +  {GPIO_CNL_H_GPP_K22, GpioPadModeNative1}, // IMGCLKOUT_0
> +  {GPIO_CNL_H_GPP_K23, GpioPadModeNative1}, // IMGCLKOUT_1
> +};
> +
> +/**
> +  This function provides IMGCLKOUT pins
> +
> +  @param[out] NativePinsTable          Table with pins
> +  @param[out] NoOfNativePins            Number of pins
> +**/
> +VOID
> +GpioGetImgClkOutPins (
> +  OUT GPIO_PAD_NATIVE_FUNCTION **NativePinsTable,
> +  OUT UINT32                   *NoOfNativePins
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *NativePinsTable = mPchLpImguClkOutGpioPad;
> +    *NoOfNativePins = ARRAY_SIZE (mPchLpImguClkOutGpioPad);
> +  } else {
> +    *NativePinsTable = mPchHImguClkOutGpioPad;
> +    *NoOfNativePins = ARRAY_SIZE (mPchHImguClkOutGpioPad);
> +  }
> +}
> +
> +/**
> +  This function provides PWRBTN pin
> +
> +  @retval GpioPad          PWRTBTN pin
> +**/
> +GPIO_PAD
> +GpioGetPwrBtnPin (
> +  VOID
> +  )
> +{
> +  if (IsPchLp ()) {
> +    return GPIO_CNL_LP_GPD3;
> +  } else {
> +    return GPIO_CNL_H_GPD3;
> +  }
> +}
> +
> +/**
> +  This function provides LPC pin
> +
> +  @retval GpioPad          LPC pin
> +**/
> +GPIO_PAD
> +GpioGetLpcPin (
> +  VOID
> +  )
> +{
> +  if (PchGetLpcDid () == V_CNL_PCH_H_LPC_CFG_DEVICE_ID_A305_SKU) {
> +    return GPIO_CNL_H_GPP_A8;
> +  } else {
> +    return 0;
> +  }
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioPrivateLib.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioPrivateLib.c
> new file mode 100644
> index 0000000000..2cf11c6da2
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioPrivateLib.c
> @@ -0,0 +1,752 @@
> +/** @file
> +  This file contains GPIO routines for RC usage
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/GpioLib.h>
> +#include <Library/GpioNativeLib.h>
> +#include <Private/Library/GpioPrivateLib.h>
> +#include <Pch/Library/PeiDxeSmmGpioLib/GpioLibrary.h>
> +#include <Private/Library/GpioNameBufferLib.h>
> +#include <Register/PchRegsPcr.h>
> +
> +#include "GpioNativePrivateLibInternal.h"
> +
> +/**
> +  This procedure is used to check if GpioPad is valid for certain chipset
> +
> +  @param[in]  GpioPad             GPIO pad
> +
> +  @retval TRUE                    This pin is valid on this chipset
> +          FALSE                   Incorrect pin
> +**/
> +BOOLEAN
> +GpioIsCorrectPadForThisChipset (
> +  IN  GPIO_PAD        GpioPad
> +  )
> +{
> +  return ((GPIO_GET_CHIPSET_ID (GpioPad) == GpioGetThisChipsetId ()) &&
> +         (GpioGetGroupIndexFromGpioPad (GpioPad) <
> GpioGetNumberOfGroups ()));
> +}
> +
> +/**
> +  This procedure will get value of selected gpio register
> +
> +  @param[in]  Group               GPIO group number
> +  @param[in]  Offset              GPIO register offset
> +  @param[out] RegVal              Value of gpio register
> +
> +  @retval EFI_SUCCESS             The function completed successfully
> +  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
> +**/
> +EFI_STATUS
> +GpioGetReg (
> +  IN  GPIO_GROUP              Group,
> +  IN  UINT32                  Offset,
> +  OUT UINT32                  *RegVal
> +  )
> +{
> +  CONST GPIO_GROUP_INFO  *GpioGroupInfo;
> +  UINT32                 GpioGroupInfoLength;
> +  UINT32                 GroupIndex;
> +
> +  GroupIndex = GpioGetGroupIndexFromGroup (Group);
> +  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
> +  //
> +  // Check if group argument exceeds GPIO GROUP INFO array
> +  //
> +  if ((UINTN) GroupIndex >= GpioGroupInfoLength) {
> +    ASSERT (FALSE);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *RegVal = MmioRead32 (PCH_PCR_ADDRESS
> (GpioGroupInfo[GroupIndex].Community, Offset));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This procedure will set value of selected gpio register
> +
> +  @param[in] Group               GPIO group number
> +  @param[in] Offset              GPIO register offset
> +  @param[in] RegVal              Value of gpio register
> +
> +  @retval EFI_SUCCESS            The function completed successfully
> +  @retval EFI_INVALID_PARAMETER  Invalid group or pad number
> +**/
> +EFI_STATUS
> +GpioSetReg (
> +  IN GPIO_GROUP              Group,
> +  IN UINT32                  Offset,
> +  IN UINT32                  RegVal
> +  )
> +{
> +  CONST GPIO_GROUP_INFO  *GpioGroupInfo;
> +  UINT32                 GpioGroupInfoLength;
> +  UINT32                 GroupIndex;
> +
> +  GroupIndex = GpioGetGroupIndexFromGroup (Group);
> +  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
> +  //
> +  // Check if group argument exceeds GPIO GROUP INFO array
> +  //
> +  if ((UINTN) GroupIndex >= GpioGroupInfoLength) {
> +    ASSERT (FALSE);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  MmioWrite32 (PCH_PCR_ADDRESS
> (GpioGroupInfo[GroupIndex].Community, Offset), RegVal);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This procedure is used by PchSmiDispatcher and will return information
> +  needed to register GPI SMI.
> +
> +  @param[in]  Index                   GPI SMI number
> +  @param[out] GpioPin                 GPIO pin
> +  @param[out] GpiSmiBitOffset         GPI SMI bit position within GpiSmi
> Registers
> +  @param[out] GpiHostSwOwnRegAddress  Address of HOSTSW_OWN
> register
> +  @param[out] GpiSmiStsRegAddress     Address of GPI SMI status register
> +
> +  @retval EFI_SUCCESS             The function completed successfully
> +  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
> +**/
> +EFI_STATUS
> +GpioGetPadAndSmiRegs (
> +  IN UINT32            Index,
> +  OUT GPIO_PAD         *GpioPin,
> +  OUT UINT8            *GpiSmiBitOffset,
> +  OUT UINT32           *GpiHostSwOwnRegAddress,
> +  OUT UINT32           *GpiSmiStsRegAddress
> +  )
> +{
> +  UINT32                 GroupIndex;
> +  UINT32                 PadNumber;
> +  CONST GPIO_GROUP_INFO  *GpioGroupInfo;
> +  GPIO_GROUP             GpioGroup;
> +  UINT32                 GpioGroupInfoLength;
> +  UINT32                 SmiStsRegOffset;
> +  UINT32                 HostSwOwnRegOffset;
> +  GPIO_PAD_OWN           PadOwnVal;
> +
> +  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
> +
> +  PadNumber = 0;
> +  GroupIndex = 0;
> +  for (GroupIndex = 0; GroupIndex < GpioGroupInfoLength; GroupIndex++) {
> +    PadNumber = Index;
> +    if (PadNumber < GpioGroupInfo[GroupIndex].PadPerGroup) {
> +      //
> +      // Found group and pad number
> +      //
> +      break;
> +    }
> +    Index = Index - GpioGroupInfo[GroupIndex].PadPerGroup;
> +  }
> +
> +  //
> +  // Check if legal pad number
> +  //
> +  if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Check if selected group has GPI SMI Enable and Status registers
> +  //
> +  if (GpioGroupInfo[GroupIndex].SmiEnOffset ==
> NO_REGISTER_FOR_PROPERTY) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  GpioGroup = GpioGetGroupFromGroupIndex (GroupIndex);
> +  *GpioPin = GpioGetGpioPadFromGroupAndPadNumber (GpioGroup,
> PadNumber);
> +
> +  DEBUG_CODE_BEGIN ();
> +  //
> +  // Check if selected GPIO Pad is not owned by CSME/ISH/IE
> +  //
> +  GpioGetPadOwnership (*GpioPin, &PadOwnVal);
> +  if (PadOwnVal != GpioPadOwnHost) {
> +    DEBUG ((DEBUG_ERROR, "GPIO ERROR: %a not owned by host!\n",
> GpioName (*GpioPin)));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  DEBUG_CODE_END ();
> +
> +  *GpiSmiBitOffset = (UINT8)(PadNumber % 32);
> +
> +  HostSwOwnRegOffset = GpioGroupInfo[GroupIndex].HostOwnOffset +
> (PadNumber / 32) * 0x4;
> +  *GpiHostSwOwnRegAddress = PCH_PCR_ADDRESS
> (GpioGroupInfo[GroupIndex].Community, HostSwOwnRegOffset);
> +
> +  SmiStsRegOffset = GpioGroupInfo[GroupIndex].SmiStsOffset + (PadNumber
> / 32) * 0x4;
> +  *GpiSmiStsRegAddress = PCH_PCR_ADDRESS
> (GpioGroupInfo[GroupIndex].Community, SmiStsRegOffset);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This procedure will set GPIO Driver IRQ number
> +
> +  @param[in]  Irq                 Irq number
> +
> +  @retval EFI_SUCCESS             The function completed successfully
> +  @retval EFI_INVALID_PARAMETER   Invalid IRQ number
> +**/
> +EFI_STATUS
> +GpioSetIrq (
> +  IN  UINT8          Irq
> +  )
> +{
> +  UINT32       Data32And;
> +  UINT32       Data32Or;
> +  PCH_SBI_PID  *GpioComSbiIds;
> +  UINT32       NoOfGpioComs;
> +  UINT32       GpioComIndex;
> +
> +  Data32And = (UINT32)~(B_GPIO_PCR_MISCCFG_IRQ_ROUTE);
> +  Data32Or  = (UINT32)Irq << N_GPIO_PCR_MISCCFG_IRQ_ROUTE;
> +
> +  NoOfGpioComs = GpioGetComSbiPortIds (&GpioComSbiIds);
> +
> +  //
> +  // Program MISCCFG register for each community
> +  //
> +  for (GpioComIndex = 0; GpioComIndex < NoOfGpioComs; GpioComIndex++)
> {
> +    MmioAndThenOr32 (
> +      PCH_PCR_ADDRESS (GpioComSbiIds[GpioComIndex],
> R_GPIO_PCR_MISCCFG),
> +      Data32And,
> +      Data32Or
> +      );
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This procedure will return Port ID of GPIO Community from GpioPad
> +
> +  @param[in] GpioPad            GpioPad
> +
> +  @retval GpioCommunityPortId   Port ID of GPIO Community
> +**/
> +UINT8
> +GpioGetGpioCommunityPortIdFromGpioPad (
> +  IN GPIO_PAD        GpioPad
> +  )
> +{
> +  CONST GPIO_GROUP_INFO  *GpioGroupInfo;
> +  UINT32                 GpioGroupInfoLength;
> +  UINT32                 GroupIndex;
> +
> +  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
> +
> +  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
> +
> +  return GpioGroupInfo[GroupIndex].Community;
> +}
> +
> +/**
> +  This procedure will return PadCfg address from GpioPad
> +
> +  @param[in] GpioPad            GpioPad
> +
> +  @retval GpioPadCfgAddress     PadCfg Address of GpioPad
> +**/
> +UINT32
> +GpioGetGpioPadCfgAddressFromGpioPad (
> +  IN GPIO_PAD        GpioPad
> +  )
> +{
> +  UINT32                 PadCfgRegAddress;
> +  CONST GPIO_GROUP_INFO  *GpioGroupInfo;
> +  UINT32                 GpioGroupInfoLength;
> +  UINT32                 GroupIndex;
> +  UINT32                 PadNumber;
> +
> +  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
> +  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
> +
> +  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
> +
> +  //
> +  // Create Pad Configuration register offset
> +  //
> +  PadCfgRegAddress = GpioGroupInfo[GroupIndex].PadCfgOffset +
> S_GPIO_PCR_PADCFG * PadNumber;
> +
> +  return PadCfgRegAddress;
> +}
> +
> +
> +/**
> +  This procedure will check if GpioPad is owned by host.
> +
> +  @param[in] GpioPad       GPIO pad
> +
> +  @retval TRUE             GPIO pad is owned by host
> +  @retval FALSE            GPIO pad is not owned by host and should not be
> used with GPIO lib API
> +**/
> +BOOLEAN
> +GpioIsPadHostOwned (
> +  IN GPIO_PAD             GpioPad
> +  )
> +{
> +  GPIO_PAD_OWN         PadOwnVal;
> +
> +  //
> +  // Check if selected GPIO Pad is not owned by CSME/ISH
> +  // If GPIO is not owned by Host all access to PadCfg will be dropped
> +  //
> +  GpioGetPadOwnership (GpioPad, &PadOwnVal);
> +  if (PadOwnVal != GpioPadOwnHost) {
> +    DEBUG ((DEBUG_ERROR, "GPIO ERROR: %a is not owned by host!\n",
> GpioName (GpioPad)));
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  This procedure will check if GpioPad argument is valid.
> +  Function will check below conditions:
> +   - GpioPad represents a pad for current PCH
> +   - GpioPad belongs to valid GpioGroup
> +   - GPIO PadNumber is not greater than number of pads for this group
> +
> +  @param[in] GpioPad       GPIO pad
> +
> +  @retval TRUE             GPIO pad is valid and can be used with GPIO lib API
> +  @retval FALSE            GPIO pad is invalid and cannot be used with GPIO lib
> API
> +**/
> +BOOLEAN
> +GpioIsPadValid (
> +  IN GPIO_PAD             GpioPad
> +  )
> +{
> +  CONST GPIO_GROUP_INFO  *GpioGroupInfo;
> +  UINT32                 GpioGroupInfoLength;
> +  UINT32                 PadNumber;
> +
> +  if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
> +    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad (0x%08x) used
> on this chipset!\n", GpioPad));
> +    goto Error;
> +  }
> +
> +  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
> +
> +  //
> +  // Check if legal pin number
> +  //
> +  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
> +  if (PadNumber >= GpioGroupInfo[GpioGetGroupIndexFromGpioPad
> (GpioPad)].PadPerGroup) {
> +    DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible
> range for this group\n", PadNumber));
> +    goto Error;
> +  }
> +
> +  return TRUE;
> +Error:
> +  ASSERT (FALSE);
> +  return FALSE;
> +}
> +
> +/**
> +  This procedure will read GPIO Pad Configuration register
> +
> +  @param[in] GpioPad          GPIO pad
> +  @param[in] DwReg            Choose PADCFG register: 0:DW0, 1:DW1
> +
> +  @retval PadCfgRegValue      PADCFG_DWx value
> +**/
> +UINT32
> +GpioReadPadCfgReg (
> +  IN GPIO_PAD             GpioPad,
> +  IN UINT8                DwReg
> +  )
> +{
> +  UINT32                 PadCfgReg;
> +  CONST GPIO_GROUP_INFO  *GpioGroupInfo;
> +  UINT32                 GpioGroupInfoLength;
> +  UINT32                 GroupIndex;
> +  UINT32                 PadNumber;
> +
> +  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
> +  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
> +
> +  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
> +
> +  //
> +  // Create Pad Configuration register offset
> +  //
> +  PadCfgReg = GpioGroupInfo[GroupIndex].PadCfgOffset +
> S_GPIO_PCR_PADCFG * PadNumber + 0x4 * DwReg;
> +
> +  return MmioRead32 (PCH_PCR_ADDRESS
> (GpioGroupInfo[GroupIndex].Community, PadCfgReg));
> +}
> +
> +/**
> +  This procedure will write or read GPIO Pad Configuration register
> +
> +  @param[in] GpioPad              GPIO pad
> +  @param[in] DwReg                Choose PADCFG register: 0:DW0, 1:DW1
> +  @param[in] PadCfgAndMask        Mask to be AND'ed with PADCFG reg
> value
> +  @param[in] PadCfgOrMask         Mask to be OR'ed with PADCFG reg value
> +
> +  @retval none
> +**/
> +VOID
> +GpioWritePadCfgReg (
> +  IN GPIO_PAD             GpioPad,
> +  IN UINT8                DwReg,
> +  IN UINT32               PadCfgAndMask,
> +  IN UINT32               PadCfgOrMask
> +  )
> +{
> +  UINT32                 PadCfgReg;
> +  CONST GPIO_GROUP_INFO  *GpioGroupInfo;
> +  UINT32                 GpioGroupInfoLength;
> +  UINT32                 GroupIndex;
> +  UINT32                 PadNumber;
> +  UINT32                 PadCfgLock;
> +  UINT32                 PadCfgLockTx;
> +
> +  PadCfgLock = 0;
> +  PadCfgLockTx = 0;
> +
> +  //
> +  // Check if Pad Configuration (except output state) is to be changed.
> +  // If AND and OR masks will indicate that configuration fields (other than
> output control)
> +  // are to be modified it means that there is a need to perform an unlock (if
> set)
> +  //
> +  if ((~PadCfgAndMask | PadCfgOrMask) & (UINT32)~B_GPIO_PCR_TX_STATE)
> {
> +    GpioGetPadCfgLock (GpioPad, &PadCfgLock);
> +    if (PadCfgLock) {
> +      GpioUnlockPadCfg (GpioPad);
> +    }
> +  }
> +
> +  //
> +  // Check if Pad Output state is to be changed
> +  // If AND and OR masks will indicate that output control
> +  // is to be modified it means that there is a need to perform an unlock (if set)
> +  //
> +  if ((~PadCfgAndMask | PadCfgOrMask) & B_GPIO_PCR_TX_STATE) {
> +    GpioGetPadCfgLockTx (GpioPad, &PadCfgLockTx);
> +    if (PadCfgLockTx) {
> +      GpioUnlockPadCfgTx (GpioPad);
> +    }
> +  }
> +
> +  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
> +  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
> +
> +  GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
> +
> +  //
> +  // Create Pad Configuration register offset
> +  //
> +  PadCfgReg = GpioGroupInfo[GroupIndex].PadCfgOffset +
> S_GPIO_PCR_PADCFG * PadNumber + 0x4 * DwReg;
> +
> +  MmioAndThenOr32 (
> +    PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community,
> PadCfgReg),
> +    PadCfgAndMask,
> +    PadCfgOrMask
> +    );
> +
> +  if (PadCfgLock) {
> +    GpioLockPadCfg (GpioPad);
> +  }
> +  if (PadCfgLockTx) {
> +    GpioLockPadCfgTx (GpioPad);
> +  }
> +}
> +
> +/**
> +  This procedure will set GPIO mode
> +
> +  @param[in]  GpioPad             GPIO pad
> +  @param[out] PadModeValue        GPIO pad mode value
> +
> +  @retval EFI_SUCCESS             The function completed successfully
> +  @retval EFI_INVALID_PARAMETER   Invalid group or pad number
> +**/
> +EFI_STATUS
> +GpioSetPadMode (
> +  IN GPIO_PAD                GpioPad,
> +  IN GPIO_PAD_MODE           PadModeValue
> +  )
> +{
> +  UINT32               PadCfgOrMask;
> +
> +  if (!GpioIsPadValid (GpioPad)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!GpioIsPadHostOwned (GpioPad)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (PadModeValue != (GPIO_PAD_MODE)GpioHardwareDefault) {
> +
> +    PadCfgOrMask = (((PadModeValue & B_GPIO_PAD_MODE_MASK) >>
> (N_GPIO_PAD_MODE_BIT_POS + 1)) << N_GPIO_PCR_PAD_MODE);
> +
> +    GpioWritePadCfgReg (
> +      GpioPad,
> +      0,
> +      (UINT32)~B_GPIO_PCR_PAD_MODE,
> +      PadCfgOrMask
> +      );
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This procedure will get GPIO mode
> +
> +  @param[in]  GpioPad             GPIO pad
> +  @param[out] PadModeValue        GPIO pad mode value
> +
> +  @retval EFI_SUCCESS             The function completed successfully
> +  @retval EFI_INVALID_PARAMETER   Invalid GpioPad
> +**/
> +EFI_STATUS
> +GpioGetPadMode (
> +  IN  GPIO_PAD                 GpioPad,
> +  OUT GPIO_PAD_MODE            *PadModeValue
> +  )
> +{
> +  UINT32        PadCfgRegValue;
> +
> +  if (!GpioIsPadValid (GpioPad)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!GpioIsPadHostOwned (GpioPad)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  PadCfgRegValue = GpioReadPadCfgReg (GpioPad, 0);
> +
> +  *PadModeValue = (GPIO_PAD_MODE)(((PadCfgRegValue &
> B_GPIO_PCR_PAD_MODE) >> (N_GPIO_PCR_PAD_MODE -
> (N_GPIO_PAD_MODE_BIT_POS + 1))) | (0x1 << N_GPIO_PAD_MODE_BIT_POS));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  The function performs GPIO Power Management programming.
> +**/
> +VOID
> +GpioConfigurePm (
> +  VOID
> +  )
> +{
> +  UINT32       Data32Or;
> +  UINT32       Data32And;
> +  PCH_SBI_PID  *GpioComSbiIds;
> +  UINT32       NoOfGpioComs;
> +  UINT32       GpioComIndex;
> +
> +  Data32And = (UINT32)~0,
> +  //
> +  // Enable MISCCFG.GPSIDEDPCGEn, MISCCFG.GPRCOMPCDLCGEn,
> MISCCFG.GPRTCDLCGEn,
> +  // MISCCFG.GPDLCGEn and MISCCFG.GPDPCGEn for GPIO communities
> +  //
> +  Data32Or = (B_GPIO_PCR_MISCCFG_GPSIDEDPCGEN |
> +              B_GPIO_PCR_MISCCFG_GPRCOMPCDLCGEN |
> +              B_GPIO_PCR_MISCCFG_GPRTCDLCGEN |
> +              B_GPIO_PCR_MISCCFG_GPDLCGEN |
> +              B_GPIO_PCR_MISCCFG_GPDPCGEN);
> +
> +  NoOfGpioComs = GpioGetComSbiPortIds (&GpioComSbiIds);
> +
> +  //
> +  // Configure Clock Gating in each community
> +  //
> +  for (GpioComIndex = 0; GpioComIndex < NoOfGpioComs; GpioComIndex++)
> {
> +    MmioAndThenOr32 (
> +      PCH_PCR_ADDRESS (GpioComSbiIds[GpioComIndex],
> R_GPIO_PCR_MISCCFG),
> +      Data32And,
> +      Data32Or
> +      );
> +  }
> +}
> +
> +/**
> +  This procedure is used to unlock all GPIO pads.
> +  This function can only be called when platform is still in HOSTIA_BOOT_SAI.
> +**/
> +VOID
> +GpioUnlockAllPads (
> +  VOID
> +  )
> +{
> +  UINT32         DwNum;
> +  UINT32         GroupIndex;
> +  UINT32         NumberOfGroups;
> +  GPIO_GROUP     Group;
> +  UINT32         LockValue;
> +  EFI_STATUS     Status;
> +
> +  NumberOfGroups = GpioGetNumberOfGroups ();
> +
> +  for (GroupIndex = 0; GroupIndex < NumberOfGroups; GroupIndex++) {
> +    Group = GpioGetGroupFromGroupIndex (GroupIndex);
> +    for (DwNum = 0; DwNum <= GPIO_GET_DW_NUM (GpioGetPadPerGroup
> (Group)); DwNum++) {
> +
> +      GpioGetPadCfgLockForGroupDw (Group, DwNum, &LockValue);
> +
> +      if (LockValue) {
> +        Status = GpioUnlockPadCfgForGroupDw (Group, DwNum, ~0u);
> +        ASSERT_EFI_ERROR (Status);
> +      }
> +
> +      GpioGetPadCfgLockTxForGroupDw (Group, DwNum, &LockValue);
> +
> +      if (LockValue) {
> +        Status = GpioUnlockPadCfgTxForGroupDw (Group, DwNum, ~0u);
> +        ASSERT_EFI_ERROR (Status);
> +      }
> +    }
> +  }
> +}
> +
> +/**
> +  Generates GPIO name from GpioPad
> +  This function returns pointer to the static buffer
> +
> +  @param[in] GpioPad  GpioPad
> +
> +  @retval CHAR8*  Pointer to the gpio name string
> +**/
> +CHAR8*
> +GpioName (
> +  IN GPIO_PAD  GpioPad
> +  )
> +{
> +  return GpioGetPadName (GpioPad, GpioGetStaticNameBuffer (),
> GPIO_NAME_LENGTH_MAX);
> +}
> +
> +
> +//
> +// For GPIO debounce feature glitch filter clock is used
> +// which is driven by RTC clock with f = 32kHz (T = 31.25us)
> +//
> +#define GPIO_DEB_CLK_PERIOD_IN_NS  31250
> +
> +/**
> +  This procedure enables debounce feature on a selected pad configured in
> input mode
> +  Debounce time can be specified in microseconds. GPIO HW supports only
> certain values
> +  according to below formula:
> +   DebounceTime = (2 ^ PADCFG_DW2.DEBOUNCE)*(glitch filter clock period).
> +  RTC clock with f = 32 KHz is used for glitch filter.
> +   DebounceTime = (2 ^ PADCFG_DW2.DEBOUNCE)*(31.25 us).
> +  Supported DebounceTime values are following:
> +   DebounceTime = 0 -> Debounce feature disabled
> +   DebounceTime > 0 && < 250us -> Not supported
> +   DebounceTime = 250us - 1024000us -> Supported range (DebounceTime =
> 250us * 2^n)
> +  For values not supported by GPIO HW, function will round down
> +  to closest supported
> +
> +  @param[in] GpioPad              GPIO pad
> +  @param[in, out] DebounceTime    Debounce Time in microseconds
> +                                  If Debounce Time = 0, Debouncer feature will be
> disabled
> +                                  Function will set DebounceTime argument to
> rounded supported value
> +
> +  @retval EFI_SUCCESS             The function completed successfully
> +  @retval EFI_INVALID_PARAMETER   Invalid GpioPad or unsupported
> DebounceDuration value
> +  @retval EFI_UNSUPPORTED         GpioPad is not owned by host
> +**/
> +EFI_STATUS
> +GpioSetDebounceTimer (
> +  IN GPIO_PAD                  GpioPad,
> +  IN OUT UINT32                *DebounceTime
> +  )
> +{
> +  UINT32   DebounceEnable;
> +  UINT32   DebounceValue;
> +  UINT32   InRangeDebounceTime;
> +  UINT32   SupportedDebounceTime;
> +  UINT32   Temp;
> +  BOOLEAN  SupportedValue;
> +
> +  if (!GpioIsPadValid (GpioPad)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!GpioIsPadHostOwned (GpioPad)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (*DebounceTime > 1024000) {
> +    InRangeDebounceTime = 1024000;
> +    SupportedValue = FALSE;
> +  } else if ((*DebounceTime < 250) && (*DebounceTime > 0)) {
> +    InRangeDebounceTime = 0;
> +    SupportedValue = FALSE;
> +  } else {
> +    InRangeDebounceTime = *DebounceTime;
> +    SupportedValue = TRUE;
> +  }
> +
> +  //
> +  // DebounceValue = log2 (InRangeDebounceTime * f_deb_clk)
> +  //
> +  DebounceValue = 0;
> +  Temp = InRangeDebounceTime * 1000 / GPIO_DEB_CLK_PERIOD_IN_NS;
> +
> +  //
> +  // Check if any rounding occurred
> +  //
> +  if (InRangeDebounceTime != (Temp * GPIO_DEB_CLK_PERIOD_IN_NS / 1000))
> {
> +    SupportedValue = FALSE;
> +  }
> +
> +  //
> +  // Check if value is power of 2
> +  //
> +  if ((Temp != 0) && ((Temp & (Temp - 1)) != 0)) {
> +    SupportedValue = FALSE;
> +  }
> +
> +  //
> +  // DebounceValue = log2 (Temp)
> +  //
> +  while (Temp > 1) {
> +    Temp >>= 1;
> +    DebounceValue++;
> +  }
> +
> +  if (DebounceValue > 0) {
> +    DebounceEnable = B_GPIO_PCR_DEBEN;
> +    SupportedDebounceTime = (1 << DebounceValue) *
> GPIO_DEB_CLK_PERIOD_IN_NS / 1000;
> +  } else {
> +    DebounceEnable = 0;
> +    SupportedDebounceTime = 0;
> +  }
> +
> +  GpioWritePadCfgReg (
> +    GpioPad,
> +    2,
> +    (UINT32)~(B_GPIO_PCR_DEBOUNCE | B_GPIO_PCR_DEBEN),
> +    (DebounceValue << N_GPIO_PCR_DEBOUNCE) | DebounceEnable
> +    );
> +
> +  if (!SupportedValue) {
> +    DEBUG ((DEBUG_WARN, "GPIO WARNING: %a %dus debounce time
> rounded down to %dus\n",
> +            GpioName (GpioPad),
> +            *DebounceTime,
> +            SupportedDebounceTime));
> +  }
> +
> +  *DebounceTime = SupportedDebounceTime;
> +
> +  return EFI_SUCCESS;
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioPrivateLibCnl.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioPrivateLibCnl.c
> new file mode 100644
> index 0000000000..a6d260f4ad
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPriv
> ateLib/GpioPrivateLibCnl.c
> @@ -0,0 +1,225 @@
> +/** @file
> +  This file contains specific GPIO information
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/DebugLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/GpioLib.h>
> +#include <Library/GpioNativeLib.h>
> +#include <Private/Library/GpioPrivateLib.h>
> +#include <Register/PchRegsGpioCnl.h>
> +#include <Register/PchRegsPmcCnl.h>
> +#include <GpioPinsCnlLp.h>
> +#include <GpioPinsCnlH.h>
> +#include <GpioConfig.h>
> +#include <Register/PchRegsPcr.h>
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_GROUP_INFO
> mPchLpGpioGroupInfo[] = {
> +  {PID_GPIOCOM0, R_CNL_PCH_LP_GPIO_PCR_GPP_A_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_A_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_A_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_A_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_GPP_A_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_A_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_GPP_A_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_GPP_A_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_GPP_A_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_GPP_A_PAD_MAX}, //CNL PCH-LP GPP_A
> +  {PID_GPIOCOM0, R_CNL_PCH_LP_GPIO_PCR_GPP_B_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_GPI_GPE_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_SMI_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_SMI_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_NMI_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_NMI_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_GPP_B_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_GPP_B_PAD_MAX}, //CNL PCH-LP GPP_B
> +  {PID_GPIOCOM4, R_CNL_PCH_LP_GPIO_PCR_GPP_C_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_GPI_GPE_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_SMI_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_SMI_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_NMI_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_NMI_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_GPP_C_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_GPP_C_PAD_MAX}, //CNL PCH-LP GPP_C
> +  {PID_GPIOCOM1, R_CNL_PCH_LP_GPIO_PCR_GPP_D_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_GPI_GPE_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_SMI_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_SMI_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_NMI_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_NMI_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_GPP_D_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_GPP_D_PAD_MAX}, //CNL PCH-LP GPP_D
> +  {PID_GPIOCOM4, R_CNL_PCH_LP_GPIO_PCR_GPP_E_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_GPI_GPE_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_SMI_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_SMI_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_NMI_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_NMI_EN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_GPP_E_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_GPP_E_PAD_MAX}, //CNL PCH-LP GPP_E
> +  {PID_GPIOCOM1, R_CNL_PCH_LP_GPIO_PCR_GPP_F_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_F_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_F_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_F_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_GPP_F_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_F_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_GPP_F_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_GPP_F_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_GPP_F_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_GPP_F_PAD_MAX}, //CNL PCH-LP GPP_F
> +  {PID_GPIOCOM0, R_CNL_PCH_LP_GPIO_PCR_GPP_G_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_G_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_G_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_G_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_GPP_G_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_G_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_GPP_G_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_GPP_G_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_GPP_G_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_GPP_G_PAD_MAX}, //CNL PCH-LP GPP_G
> +  {PID_GPIOCOM1, R_CNL_PCH_LP_GPIO_PCR_GPP_H_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_H_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPP_H_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_H_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_GPP_H_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPP_H_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_GPP_H_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_GPP_H_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_GPP_H_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_GPP_H_PAD_MAX}, //CNL PCH-LP GPP_H
> +  {PID_GPIOCOM2, R_CNL_PCH_LP_GPIO_PCR_GPD_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPD_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_GPD_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_GPD_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_GPD_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_GPD_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_GPD_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_GPD_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_GPD_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_GPD_PAD_MAX},   //CNL PCH-LP GPD
> +  {PID_GPIOCOM1, R_CNL_PCH_LP_GPIO_PCR_VGPIO_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_VGPIO_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_VGPIO_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_VGPIO_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_VGPIO_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_VGPIO_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_VGPIO_0_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_VGPIO_0_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_VGPIO_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_VGPIO_PAD_MAX}, //CNL PCH-LP vGPIO
> +  {PID_GPIOCOM0, R_CNL_PCH_LP_GPIO_PCR_SPI_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_SPI_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_SPI_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_SPI_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_SPI_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_SPI_GPI_GPE_EN,   NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_SPI_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_SPI_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_SPI_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_SPI_PAD_MAX},   //CNL PCH-LP SPI
> +  {PID_GPIOCOM3, R_CNL_PCH_LP_GPIO_PCR_AZA_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_AZA_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_AZA_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_AZA_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_AZA_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_AZA_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_AZA_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_AZA_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_AZA_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_AZA_PAD_MAX},   //CNL PCH-LP AZA
> +  {PID_GPIOCOM3, R_CNL_PCH_LP_GPIO_PCR_CPU_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_CPU_HOSTSW_OWN,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,                NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_CPU_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_CPU_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_CPU_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_CPU_PAD_MAX},   //CNL PCH-LP CPU
> +  {PID_GPIOCOM4, R_CNL_PCH_LP_GPIO_PCR_JTAG_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_JTAG_HOSTSW_OWN,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,                NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_JTAG_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_JTAG_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_JTAG_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_JTAG_PAD_MAX},  //CNL PCH-LP JTAG
> +  {PID_GPIOCOM4, R_CNL_PCH_LP_GPIO_PCR_HVMOS_PAD_OWN,
> R_CNL_PCH_LP_GPIO_PCR_HVMOS_HOSTSW_OWN,
> R_CNL_PCH_LP_GPIO_PCR_HVMOS_GPI_IS,
> R_CNL_PCH_LP_GPIO_PCR_HVMOS_GPI_IE,
> R_CNL_PCH_LP_GPIO_PCR_HVMOS_GPI_GPE_STS,
> R_CNL_PCH_LP_GPIO_PCR_HVMOS_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,            NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_LP_GPIO_PCR_HVMOS_PADCFGLOCK,
> R_CNL_PCH_LP_GPIO_PCR_HVMOS_PADCFGLOCKTX,
> R_CNL_PCH_LP_GPIO_PCR_HVMOS_PADCFG_OFFSET,
> CNL_PCH_LP_GPIO_HVMOS_PAD_MAX}  //CNL PCH-LP HVMOS
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_GROUP_INFO
> mPchHGpioGroupInfo[] = {
> +  {PID_GPIOCOM0, R_CNL_PCH_H_GPIO_PCR_GPP_A_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_A_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_A_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_A_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_A_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_A_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_GPP_A_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_A_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_A_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_A_PAD_MAX}, //CNL PCH-H GPP_A
> +  {PID_GPIOCOM0, R_CNL_PCH_H_GPIO_PCR_GPP_B_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_GPI_GPE_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_SMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_SMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_NMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_NMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_B_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_B_PAD_MAX}, //CNL PCH-H GPP_B
> +  {PID_GPIOCOM1, R_CNL_PCH_H_GPIO_PCR_GPP_C_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_GPI_GPE_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_SMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_SMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_NMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_NMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_C_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_C_PAD_MAX}, //CNL PCH-H GPP_C
> +  {PID_GPIOCOM1, R_CNL_PCH_H_GPIO_PCR_GPP_D_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_GPI_GPE_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_SMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_SMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_NMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_NMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_D_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_D_PAD_MAX}, //CNL PCH-H GPP_D
> +  {PID_GPIOCOM3, R_CNL_PCH_H_GPIO_PCR_GPP_E_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_GPI_GPE_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_SMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_SMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_NMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_NMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_E_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_E_PAD_MAX}, //CNL PCH-H GPP_E
> +  {PID_GPIOCOM3, R_CNL_PCH_H_GPIO_PCR_GPP_F_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_F_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_F_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_F_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_F_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_F_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_GPP_F_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_F_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_F_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_F_PAD_MAX}, //CNL PCH-H GPP_F
> +  {PID_GPIOCOM1, R_CNL_PCH_H_GPIO_PCR_GPP_G_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_GPI_GPE_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_SMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_SMI_EN, NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_G_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_G_PAD_MAX}, //CNL PCH-H GPP_G
> +  {PID_GPIOCOM3, R_CNL_PCH_H_GPIO_PCR_GPP_H_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_H_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_H_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_H_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_H_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_H_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_GPP_H_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_H_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_H_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_H_PAD_MAX}, //CNL PCH-H GPP_H
> +  {PID_GPIOCOM4, R_CNL_PCH_H_GPIO_PCR_GPP_I_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_GPI_GPE_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_SMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_SMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_NMI_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_NMI_EN,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_I_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_I_PAD_MAX}, //CNL PCH-H GPP_I
> +  {PID_GPIOCOM4, R_CNL_PCH_H_GPIO_PCR_GPP_J_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_J_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_J_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_J_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_J_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_J_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_GPP_J_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_J_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_J_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_J_PAD_MAX}, //CNL PCH-H GPP_J
> +  {PID_GPIOCOM3, R_CNL_PCH_H_GPIO_PCR_GPP_K_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_K_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPP_K_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPP_K_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPP_K_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPP_K_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_GPP_K_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPP_K_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPP_K_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPP_K_PAD_MAX}, //CNL PCH-H GPP_K
> +  {PID_GPIOCOM2, R_CNL_PCH_H_GPIO_PCR_GPD_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPD_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_GPD_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_GPD_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_GPD_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_GPD_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_GPD_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_GPD_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_GPD_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_GPD_PAD_MAX},   //CNL PCH-H GPD
> +  {PID_GPIOCOM1, R_CNL_PCH_H_GPIO_PCR_VGPIO_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_VGPIO_HOSTSW_OWN,
> R_CNL_PCH_H_GPIO_PCR_VGPIO_GPI_IS,
> R_CNL_PCH_H_GPIO_PCR_VGPIO_GPI_IE,
> R_CNL_PCH_H_GPIO_PCR_VGPIO_GPI_GPE_STS,
> R_CNL_PCH_H_GPIO_PCR_VGPIO_GPI_GPE_EN,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_VGPIO_0_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_VGPIO_0_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_VGPIO_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_VGPIO_PAD_MAX}, //CNL PCH-H vGPIO
> +  {PID_GPIOCOM3, R_CNL_PCH_H_GPIO_PCR_SPI_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_SPI_HOSTSW_OWN,
> NO_REGISTER_FOR_PROPERTY,          NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,               NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_SPI_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_SPI_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_SPI_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_SPI_PAD_MAX},   //CNL PCH-H SPI
> +  {PID_GPIOCOM1, R_CNL_PCH_H_GPIO_PCR_AZA_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_AZA_HOSTSW_OWN,
> NO_REGISTER_FOR_PROPERTY,          NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,               NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_AZA_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_AZA_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_AZA_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_AZA_PAD_MAX},   //CNL PCH-H AZA
> +  {PID_GPIOCOM4, R_CNL_PCH_H_GPIO_PCR_CPU_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_CPU_HOSTSW_OWN,
> NO_REGISTER_FOR_PROPERTY,          NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,               NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_CPU_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_CPU_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_CPU_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_CPU_PAD_MAX},   //CNL PCH-H CPU
> +  {PID_GPIOCOM4, R_CNL_PCH_H_GPIO_PCR_JTAG_PAD_OWN,
> R_CNL_PCH_H_GPIO_PCR_JTAG_HOSTSW_OWN,
> NO_REGISTER_FOR_PROPERTY,          NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,               NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> NO_REGISTER_FOR_PROPERTY,           NO_REGISTER_FOR_PROPERTY,
> R_CNL_PCH_H_GPIO_PCR_JTAG_PADCFGLOCK,
> R_CNL_PCH_H_GPIO_PCR_JTAG_PADCFGLOCKTX,
> R_CNL_PCH_H_GPIO_PCR_JTAG_PADCFG_OFFSET,
> CNL_PCH_H_GPIO_JTAG_PAD_MAX}   //CNL PCH-H JTAG
> +};
> +
> +/**
> +  This procedure will retrieve address and length of GPIO info table
> +
> +  @param[out]  GpioGroupInfoTableLength   Length of GPIO group table
> +
> +  @retval Pointer to GPIO group table
> +
> +**/
> +CONST GPIO_GROUP_INFO*
> +GpioGetGroupInfoTable (
> +  OUT UINT32              *GpioGroupInfoTableLength
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *GpioGroupInfoTableLength = ARRAY_SIZE (mPchLpGpioGroupInfo);
> +    return mPchLpGpioGroupInfo;
> +  } else {
> +    *GpioGroupInfoTableLength = ARRAY_SIZE (mPchHGpioGroupInfo);
> +    return mPchHGpioGroupInfo;
> +  }
> +}
> +
> +/**
> +  Get GPIO Chipset ID specific to PCH generation and series
> +**/
> +UINT32
> +GpioGetThisChipsetId (
> +  VOID
> +  )
> +{
> +  if (IsPchLp ()) {
> +    return GPIO_CNL_LP_CHIPSET_ID;
> +  } else {
> +    return GPIO_CNL_H_CHIPSET_ID;
> +  }
> +}
> +
> +/**
> +  This internal procedure will check if group is within DeepSleepWell.
> +
> +  @param[in]  Group               GPIO Group
> +
> +  @retval GroupWell               TRUE:  This is DSW Group
> +                                  FALSE: This is not DSW Group
> +**/
> +BOOLEAN
> +GpioIsDswGroup (
> +  IN  GPIO_GROUP         Group
> +  )
> +{
> +  if ((Group == GPIO_CNL_LP_GROUP_GPD) || (Group ==
> GPIO_CNL_H_GROUP_GPD)) {
> +    return TRUE;
> +  } else {
> +    return FALSE;
> +  }
> +}
> +
> +/**
> +  This procedure will perform special handling of GPP_A_12.
> +
> +  @param[in]  None
> +
> +  @retval None
> +**/
> +VOID
> +GpioA12SpecialHandling (
> +  VOID
> +  )
> +{
> +  GPIO_PAD_OWN         PadOwnVal;
> +  GPIO_PAD             GpioPad;
> +
> +  //
> +  // PCH BWG 16.6. GPP_A_12 Special Handling
> +  //
> +  if (IsPchLp ()) {
> +    GpioPad = GPIO_CNL_LP_GPP_A12;
> +  } else {
> +    GpioPad = GPIO_CNL_H_GPP_A12;
> +  }
> +  GpioGetPadOwnership (GpioPad, &PadOwnVal);
> +
> +  //
> +  // If the pad is host-own, BIOS has to always lock this pad after being
> initialized
> +  //
> +  if (PadOwnVal == GpioPadOwnHost) {
> +    //
> +    // Set PadCfgLock for GPP_A_12
> +    //
> +    GpioLockPadCfg (GpioPad);
> +  }
> +}
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SBI_PID mGpioComSbiIds[] =
> +{
> +  PID_GPIOCOM0, PID_GPIOCOM1, PID_GPIOCOM2, PID_GPIOCOM3,
> PID_GPIOCOM4
> +};
> +
> +/**
> +  This function provides GPIO Community PortIDs
> +
> +  @param[out] NativePinsTable                Table with GPIO COMMx SBI
> PortIDs
> +
> +  @retval      Number of communities
> +**/
> +UINT32
> +GpioGetComSbiPortIds (
> +  OUT PCH_SBI_PID    **GpioComSbiIds
> +  )
> +{
> +  *GpioComSbiIds = mGpioComSbiIds;
> +  return ARRAY_SIZE (mGpioComSbiIds);
> +}
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_GROUP_TO_GPE_MAPPING
> mPchLpGpioGroupToGpeMapping[] = {
> +  {GPIO_CNL_LP_GROUP_GPP_A,  0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_GPP_A,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_GPP_A},
> +  {GPIO_CNL_LP_GROUP_GPP_B,  0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_GPP_B,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_GPP_B},
> +  {GPIO_CNL_LP_GROUP_GPP_C,  0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_GPP_C,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_GPP_C},
> +  {GPIO_CNL_LP_GROUP_GPP_D,  0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_GPP_D,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_GPP_D},
> +  {GPIO_CNL_LP_GROUP_GPP_E,  0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_GPP_E,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_GPP_E},
> +  {GPIO_CNL_LP_GROUP_GPP_F,  0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_GPP_F,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_GPP_F},
> +  {GPIO_CNL_LP_GROUP_GPP_G,  0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_GPP_G,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_GPP_G},
> +  {GPIO_CNL_LP_GROUP_GPP_H,  0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_GPP_H,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_GPP_H},
> +  {GPIO_CNL_LP_GROUP_GPD,    0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_GPD,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_GPD},
> +  {GPIO_CNL_LP_GROUP_VGPIO , 0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_VGPIO,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_VGPIO},
> +  {GPIO_CNL_LP_GROUP_SPI,    0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_SPI,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_SPI},
> +  {GPIO_CNL_LP_GROUP_AZA,    0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_AZA,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_AZA},
> +  {GPIO_CNL_LP_GROUP_JTAG,   0,
> V_CNL_PCH_LP_PMC_PWRM_GPIO_CFG_JTAG,
> V_CNL_PCH_LP_GPIO_PCR_MISCCFG_GPE0_JTAG}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED GPIO_GROUP_TO_GPE_MAPPING
> mPchHGpioGroupToGpeMapping[] = {
> +  {GPIO_CNL_H_GROUP_GPP_A,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_A,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_A},
> +  {GPIO_CNL_H_GROUP_GPP_B,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_B,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_B},
> +  {GPIO_CNL_H_GROUP_GPP_C,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_C,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_C},
> +  {GPIO_CNL_H_GROUP_GPP_D,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_D,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_D},
> +  {GPIO_CNL_H_GROUP_GPP_E,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_E,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_E},
> +  {GPIO_CNL_H_GROUP_GPP_F,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_F,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_F},
> +  {GPIO_CNL_H_GROUP_GPP_G,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_G,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_G},
> +  {GPIO_CNL_H_GROUP_GPP_H,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_H,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_H},
> +  {GPIO_CNL_H_GROUP_GPP_I,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_I,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_I},
> +  {GPIO_CNL_H_GROUP_GPP_J,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_J,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_J},
> +  {GPIO_CNL_H_GROUP_GPP_K,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPP_K,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPP_K},
> +  {GPIO_CNL_H_GROUP_GPD,    0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_GPD,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_GPD},
> +  {GPIO_CNL_H_GROUP_VGPIO,  0,
> V_CNL_PCH_H_PMC_PWRM_GPIO_CFG_VGPIO,
> V_CNL_PCH_H_GPIO_PCR_MISCCFG_GPE0_VGPIO}
> +};
> +
> +/**
> +  Get information for GPIO Group required to program GPIO and PMC for
> desired 1-Tier GPE mapping
> +
> +  @param[out] GpioGroupToGpeMapping        Table with GPIO Group to
> GPE mapping
> +  @param[out] GpioGroupToGpeMappingLength  GPIO Group to GPE
> mapping table length
> +**/
> +VOID
> +GpioGetGroupToGpeMapping (
> +  OUT GPIO_GROUP_TO_GPE_MAPPING  **GpioGroupToGpeMapping,
> +  OUT UINT32                     *GpioGroupToGpeMappingLength
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *GpioGroupToGpeMapping = mPchLpGpioGroupToGpeMapping;
> +    *GpioGroupToGpeMappingLength = ARRAY_SIZE
> (mPchLpGpioGroupToGpeMapping);
> +  } else {
> +    *GpioGroupToGpeMapping = mPchHGpioGroupToGpeMapping;
> +    *GpioGroupToGpeMappingLength = ARRAY_SIZE
> (mPchHGpioGroupToGpeMapping);
> +  }
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi14.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi14.c
> new file mode 100644
> index 0000000000..2f9b6a7e6f
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi14.c
> @@ -0,0 +1,67 @@
> +/** @file
> +  This file contains functions for PCH DMI SIP14
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Private/Library/PchDmiLib.h>
> +#include <Library/PchCycleDecodingLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Register/PchRegsDmi.h>
> +#include <Register/PchRegsDmi14.h>
> +#include <Register/PchRegsPcr.h>
> +
> +/**
> +  This function checks if DMI SIP14 Secured Register Lock (SRL) is set
> +
> +  @retval SRL state
> +**/
> +BOOLEAN
> +IsPchDmi14Locked (
> +  VOID
> +  )
> +{
> +  return ((PchPcrRead32 (PID_DMI, R_PCH_DMI14_PCR_DMIC) &
> B_PCH_DMI14_PCR_DMIC_SRL) != 0);
> +}
> +
> +/**
> +  Enable PCIe Relaxed Order for DMI SIP14
> +**/
> +VOID
> +PchDmi14EnablePcieRelaxedOrder (
> +  VOID
> +  )
> +{
> +  //
> +  // Enable Forced Relaxed Ordering to always allow downstream
> completions to pass posted writes.
> +  // Set Completion Relaxed Ordering Attribute Override Value
> +  // and Completion Relaxed Ordering Attribute Override Enable
> +  //
> +  PchPcrAndThenOr32 (PID_DMI, R_PCH_DMI14_PCR_2314, ~0u, (BIT31 |
> BIT7));
> +}
> +
> +/**
> + Secure Register Lock data
> +
> + @param[out] SrlRegOffset        Register offset holding Secure Register Lock
> setting
> + @param[out] SrlRegMask          Mask for Secure Register Lock setting
> +**/
> +VOID
> +PchDmi14SrlRegData (
> +  OUT UINT16  *SrlRegOffset,
> +  OUT UINT32  *SrlRegMask
> +  )
> +{
> +  *SrlRegMask = B_PCH_DMI14_PCR_DMIC_SRL;
> +  *SrlRegOffset = R_PCH_DMI14_PCR_DMIC;
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi15.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi15.c
> new file mode 100644
> index 0000000000..c711b3de39
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmi15.c
> @@ -0,0 +1,113 @@
> +/** @file
> +  This file contains functions for PCH DMI SIP15
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Private/Library/PchDmiLib.h>
> +#include <Library/PchCycleDecodingLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Register/PchRegsDmi.h>
> +#include <Register/PchRegsDmi15.h>
> +#include <Register/PchRegsPcr.h>
> +
> +/**
> +  This function checks if DMI SIP15 Secured Register Lock (SRL) is set
> +
> +  @retval SRL state
> +**/
> +BOOLEAN
> +IsPchDmi15Locked (
> +  VOID
> +  )
> +{
> +  return ((PchPcrRead32 (PID_DMI, R_PCH_DMI15_PCR_MPC) &
> B_PCH_DMI15_PCR_MPC_SRL) != 0);
> +}
> +
> +/**
> +  Set DMI thermal throttling to recommended configuration.
> +  It's intended only for P-DMI SIP15.
> +**/
> +VOID
> +PchDmi15SetRecommendedThermalThrottling (
> +  VOID
> +  )
> +{
> +  UINT32  Data32And;
> +  UINT32  Data32Or;
> +  ///
> +  /// DMI recommended Thermal Sensor Target Width
> +  /// is the HW default configuration:
> +  ///  - Thermal Sensor 3 Target Width: 0 (x1)
> +  ///  - Thermal Sensor 2 Target Width: 1 (x2)
> +  ///  - Thermal Sensor 1 Target Width: 2 (x4)
> +  ///  - Thermal Sensor 0 Target Width: 3 (x8)
> +  /// Enable Thermal Sensor Autonomous Width
> +  ///
> +  Data32And = (UINT32)~(B_PCH_DMI15_PCR_UPHWAWC_TS3TW |
> B_PCH_DMI15_PCR_UPHWAWC_TS2TW |
> +                        B_PCH_DMI15_PCR_UPHWAWC_TS1TW |
> B_PCH_DMI15_PCR_UPHWAWC_TS0TW);
> +  Data32Or  = (0 << N_PCH_DMI15_PCR_UPHWAWC_TS3TW) |
> +              (1 << N_PCH_DMI15_PCR_UPHWAWC_TS2TW) |
> +              (2 << N_PCH_DMI15_PCR_UPHWAWC_TS1TW) |
> +              (3 << N_PCH_DMI15_PCR_UPHWAWC_TS0TW) |
> +              B_PCH_DMI15_PCR_UPHWAWC_TSAWEN;
> +
> +  PchPcrAndThenOr32 (PID_DMI, R_PCH_DMI15_PCR_UPHWAWC,
> Data32And, Data32Or);
> +}
> +
> +/**
> +  Set DMI thermal throttling to custom configuration.
> +  This function will configure Thermal Sensor 0/1/2/3 TargetWidth and set
> +  DMI Thermal Sensor Autonomous Width Enable.
> +  It's intended only for P-DMI SIP15.
> +
> +  @param[in] DmiThermalThrottling        DMI Thermal Throttling structure.
> +**/
> +VOID
> +PchDmi15SetCustomThermalThrottling (
> +  IN DMI_THERMAL_THROTTLING      DmiThermalThrottling
> +  )
> +{
> +  UINT32  Data32And;
> +  UINT32  Data32Or;
> +
> +  ///
> +  /// DMI Throttling action
> +  ///
> +  Data32And = (UINT32)~(B_PCH_DMI15_PCR_UPHWAWC_TS3TW |
> B_PCH_DMI15_PCR_UPHWAWC_TS2TW |
> +                        B_PCH_DMI15_PCR_UPHWAWC_TS1TW |
> B_PCH_DMI15_PCR_UPHWAWC_TS0TW);
> +  Data32Or  = (DmiThermalThrottling.ThermalSensor3TargetWidth <<
> N_PCH_DMI15_PCR_UPHWAWC_TS3TW) |
> +              (DmiThermalThrottling.ThermalSensor2TargetWidth <<
> N_PCH_DMI15_PCR_UPHWAWC_TS2TW) |
> +              (DmiThermalThrottling.ThermalSensor1TargetWidth <<
> N_PCH_DMI15_PCR_UPHWAWC_TS1TW) |
> +              (DmiThermalThrottling.ThermalSensor0TargetWidth <<
> N_PCH_DMI15_PCR_UPHWAWC_TS0TW) |
> +              B_PCH_DMI15_PCR_UPHWAWC_TSAWEN;
> +
> +  PchPcrAndThenOr32 (PID_DMI, R_PCH_DMI15_PCR_UPHWAWC,
> Data32And, Data32Or);
> +}
> +
> +
> +/**
> + Secure Register Lock data
> +
> + @param[out] SrlRegOffset        Register offset holding Secure Register Lock
> setting
> + @param[out] SrlRegMask          Mask for Secure Register Lock setting
> +**/
> +VOID
> +PchDmi15SrlRegData (
> +  OUT UINT16  *SrlRegOffset,
> +  OUT UINT32  *SrlRegMask
> +  )
> +{
> +  *SrlRegMask = B_PCH_DMI15_PCR_MPC_SRL;
> +  *SrlRegOffset = R_PCH_DMI15_PCR_MPC;
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmiLib.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmiLib.c
> new file mode 100644
> index 0000000000..f1b2867659
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmiLib.c
> @@ -0,0 +1,569 @@
> +/** @file
> +  PCH DMI library.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Private/Library/PchDmiLib.h>
> +#include <Library/PchCycleDecodingLib.h>
> +#include <Private/Library/PchPsfPrivateLib.h>
> +#include <Register/PchRegsPcr.h>
> +#include <Register/PchRegsDmi.h>
> +
> +#include "PchDmi14.h"
> +#include "PchDmi15.h"
> +
> +/**
> +  This function checks if DMI Secured Register Lock (SRL) is set
> +
> +  @retval SRL state
> +**/
> +BOOLEAN
> +IsPchDmiLocked (
> +  VOID
> +  )
> +{
> +  if (IsPchWithPdmi ()) {
> +    return IsPchDmi15Locked ();
> +  } else {
> +    return IsPchDmi14Locked ();
> +  }
> +}
> +
> +/**
> +  Backward DMI library API compatibility
> +  ACPI base address programming is done in PSF
> +
> +  @param[in] Address                    Address for ACPI base.
> +
> +  @retval EFI_UNSUPPORTED               NOT supported programming.
> +**/
> +EFI_STATUS
> +PchDmiSetAcpiBase (
> +  IN  UINT16                            Address
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  Backward DMI library API compatibility
> +  PWRMBASE is a standard BAR and doesn't require
> +  additional DMI base decoding programming
> +
> +  @param[in] Address                    Address for PWRM base.
> +
> +  @retval EFI_UNSUPPORTED               NOT supported programming.
> +**/
> +EFI_STATUS
> +PchDmiSetPwrmBase (
> +  IN  UINT32                            Address
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  Set PCH TCO base address decoding in DMI
> +
> +  @param[in] Address                    Address for TCO base address.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_INVALID_PARAMETER         Invalid base address passed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiSetTcoBase (
> +  IN  UINT16                            Address
> +  )
> +{
> +  if (IsPchDmiLocked ()) {
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Program "TCO Base Address" PCR[DMI] + 2778h[15:5, 1] to [SMBUS PCI
> offset 50h[15:5], 1].
> +  //
> +  PchPcrWrite16 (
> +    PID_DMI, R_PCH_DMI_PCR_TCOBASE,
> +    (Address | BIT1)
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get PCH TCO base address.
> +
> +  @retval Address                   Address of TCO base address.
> +**/
> +UINT16
> +PchDmiGetTcoBase (
> +  VOID
> +  )
> +{
> +  //
> +  // Read "TCO Base Address" PCR[DMI] + 2778h[15:5]
> +  //
> +  return (PchPcrRead16 (PID_DMI, R_PCH_DMI_PCR_TCOBASE) &
> B_PCH_DMI_PCR_TCOBASE_TCOBA);
> +}
> +
> +/**
> +  Set PCH LPC/eSPI generic IO range decoding in DMI
> +
> +  @param[in] Address                    Address for generic IO range base
> address.
> +  @param[in] Length                     Length of generic IO range.
> +  @param[in] RangeIndex                 Index of choosen range
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiSetLpcGenIoRange (
> +  IN  UINT32                            Address,
> +  IN  UINT32                            Length,
> +  IN  UINT32                            RangeIndex
> +  )
> +{
> +  UINT32                                Data32;
> +  //
> +  // This cycle decoding is only allowed to set when DMIC.SRL is 0.
> +  //
> +  if (IsPchDmiLocked ()) {
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Data32 =  (UINT32) (((Length - 1) << 16) & B_LPC_CFG_GENX_DEC_IODRA);
> +  Data32 |= (UINT32) Address;
> +  Data32 |= B_LPC_CFG_GENX_DEC_EN;
> +  //
> +  // Program LPC Generic IO Range #, PCR[DMI] + 2730h ~ 273Fh to the same
> value programmed in LPC/eSPI PCI Offset 84h~93h.
> +  //
> +  PchPcrWrite32 (
> +    PID_DMI, (UINT16) (R_PCH_DMI_PCR_LPCLGIR1 + RangeIndex * 4),
> +    Data32
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Set PCH eSPI eSPI CS1# generic IO range decoding in DMI
> +
> +  @param[in] Address                    Address for generic IO range base
> address.
> +  @param[in] Length                     Length of generic IO range.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiSetEspiCs1GenIoRange (
> +  IN  UINT32                            Address,
> +  IN  UINT32                            Length
> +  )
> +{
> +  UINT32                                Data32;
> +  //
> +  // This cycle decoding is only allowed to set when DMIC.SRL is 0.
> +  //
> +  if (IsPchDmiLocked ()) {
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Data32 =  (UINT32) (((Length - 1) << 16) & B_LPC_CFG_GENX_DEC_IODRA);
> +  Data32 |= (UINT32) Address;
> +  Data32 |= B_LPC_CFG_GENX_DEC_EN;
> +  //
> +  // Program eSPI Generic IO Range #, PCR[DMI] + 27BCh to the same value
> programmed in eSPI PCI Offset A4h.
> +  //
> +  PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_SEGIR, Data32);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Clear PCH LPC/eSPI generic IO range decoding in DMI
> +
> +  @param[in] RangeIndex                 Index of chosen range
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiClearLpcGenIoRange (
> +  IN  UINTN                             RangeIndex
> +  )
> +{
> +  //
> +  // This cycle decoding is only allowed to set when DMIC.SRL is 0.
> +  //
> +  if (IsPchDmiLocked ()) {
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Program LPC Generic IO Range #, PCR[DMI] + 2730h ~ 273Fh to the same
> value programmed in LPC/eSPI PCI Offset 84h~93h.
> +  //
> +  PchPcrWrite32 (
> +    PID_DMI, (UINT16) (R_PCH_DMI_PCR_LPCLGIR1 + RangeIndex * 4),
> +    0
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Clear PCH eSPI CS1# generic IO range decoding in DMI
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiClearEspiCs1GenIoRange (
> +  VOID
> +  )
> +{
> +  //
> +  // This cycle decoding is only allowed to set when DMIC.SRL is 0.
> +  //
> +  if (IsPchDmiLocked ()) {
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +  //
> +  // Program LPC Generic IO Range #, PCR[DMI] + 27BCh to the same value
> programmed in eSPI PCI Offset A4h.
> +  //
> +  PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_SEGIR, 0);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Set PCH LPC/eSPI memory range decoding in DMI
> +
> +  @param[in] Address                    Address for memory base address.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiSetLpcMemRange (
> +  IN  UINT32                            Address
> +  )
> +{
> +  if (IsPchDmiLocked ()) {
> +    DEBUG ((DEBUG_ERROR, "PchDmiSetLpcMemRange Error. DMI is
> locked.\n"));
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Program LPC Memory Range, PCR[DMI] + 2740h to the same value
> programmed in LPC/eSPI PCI Offset 98h.
> +  //
> +  PchPcrWrite32 (
> +    PID_DMI, R_PCH_DMI_PCR_LPCGMR,
> +    (Address | B_LPC_CFG_LGMR_LMRD_EN)
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Set PCH eSPI CS1# memory range decoding in DMI
> +
> +  @param[in] Address                    Address for memory base address.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiSetEspiCs1MemRange (
> +  IN  UINT32                            Address
> +  )
> +{
> +  if (IsPchDmiLocked ()) {
> +    DEBUG ((DEBUG_ERROR, "PchLpcMemRange2Set Error. DMI is locked.\n"));
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Program LPC Memory Range, PCR[DMI] + 27C0h to the same value
> programmed in eSPI PCI Offset A8h.
> +  //
> +  PchPcrWrite32 (
> +    PID_DMI, R_PCH_DMI_PCR_SEGMR,
> +    (Address | B_LPC_CFG_LGMR_LMRD_EN)
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check if Boot BIOS Strap is set for SPI.
> +
> +  @retval TRUE                Boot BIOS Strap set for SPI
> +  @retval FALSE               Boot BIOS Strap set for LPC/eSPI
> +**/
> +BOOLEAN
> +PchDmiIsBootBiosStrapSetForSpi (
> +  VOID
> +  )
> +{
> +  //
> +  // Check General Control and Status (GCS) [10]
> +  // '0': SPI
> +  // '1': LPC/eSPI
> +  //
> +  return ((PchPcrRead32 (PID_DMI, R_PCH_DMI_PCR_GCS) &
> B_PCH_DMI_PCR_BBS) != B_PCH_DMI_PCR_BBS);
> +}
> +
> +/**
> +  Set PCH BIOS range decoding in DMI
> +  Please check EDS for detail of BiosDecodeEnable bit definition.
> +    bit 15: F8-FF Enable
> +    bit 14: F0-F8 Enable
> +    bit 13: E8-EF Enable
> +    bit 12: E0-E8 Enable
> +    bit 11: D8-DF Enable
> +    bit 10: D0-D7 Enable
> +    bit  9: C8-CF Enable
> +    bit  8: C0-C7 Enable
> +    bit  7: Legacy F Segment Enable
> +    bit  6: Legacy E Segment Enable
> +    bit  5: Reserved
> +    bit  4: Reserved
> +    bit  3: 70-7F Enable
> +    bit  2: 60-6F Enable
> +    bit  1: 50-5F Enable
> +    bit  0: 40-4F Enable
> +
> +  @param[in] BiosDecodeEnable           Bios decode enable setting.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiSetBiosDecodeEnable (
> +  IN  UINT16                            BiosDecodeEnable
> +  )
> +{
> +  if (IsPchDmiLocked ()) {
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // program LPC BIOS Decode Enable, PCR[DMI] + 2744h to the same value
> programmed in LPC or SPI Offset D8h.
> +  //
> +  PchPcrWrite16 (PID_DMI, R_PCH_DMI_PCR_LPCBDE, BiosDecodeEnable);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Set PCH LPC/eSPI IO decode ranges in DMI
> +  Please check EDS for detail of LPC/eSPI IO decode ranges bit definition.
> +  Bit  12: FDD range
> +  Bit 9:8: LPT range
> +  Bit 6:4: ComB range
> +  Bit 2:0: ComA range
> +
> +  @param[in] LpcIoDecodeRanges          LPC/eSPI IO decode ranges bit
> settings.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiSetLpcIoDecodeRanges (
> +  IN  UINT16                            LpcIoDecodeRanges
> +  )
> +{
> +  //
> +  // This cycle decoding is only allowed to set when DMI is not locked.
> +  //
> +  if (IsPchDmiLocked ()) {
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // program LPC I/O Decode Ranges, PCR[DMI] + 2770h[15:0] to the same
> value programmed in LPC/eSPI PCI offset 80h.
> +  //
> +  PchPcrWrite16 (PID_DMI, R_PCH_DMI_PCR_LPCIOD, LpcIoDecodeRanges);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Set PCH LPC/eSPI IO enable decoding in DMI
> +
> +  @param[in] LpcIoEnableDecoding        LPC/eSPI IO enable decoding bit
> settings.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PchDmiSetLpcIoEnable (
> +  IN  UINT16                            LpcIoEnableDecoding
> +  )
> +{
> +  //
> +  // This cycle decoding is only allowed to set when DMI is not locked.
> +  //
> +  if (IsPchDmiLocked ()) {
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // program LPC I/O Decode Ranges, PCR[DMI] + 2774h[15:0] to the same
> value programmed in LPC/eSPI PCI offset 82h.
> +  //
> +  PchPcrWrite16 (PID_DMI, R_PCH_DMI_PCR_LPCIOE, LpcIoEnableDecoding);
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +  Set PCH IO port 80h cycle decoding to PCIE root port in DMI
> +
> +  @param[in] RpNumber                   PCIE root port physical number.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +**/
> +EFI_STATUS
> +PchDmiSetIoPort80Decode (
> +  IN  UINTN                             RpNumber
> +  )
> +{
> +  UINT16            DmiRpDestinationId;
> +  PSF_PORT_DEST_ID  PsfRpDestinationId;
> +
> +  if (IsPchDmiLocked ()) {
> +    DEBUG ((DEBUG_ERROR, "PchIoPort80DecodeSet Error. DMI is
> locked.\n"));
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  ///
> +  /// IO port 80h is typically used by decoder/LED hardware for debug
> purposes.
> +  /// By default PCH will forward IO port 80h cycles to LPC bus. The Reserved
> Page Route (RPR) bit
> +  /// of General Control and Status register, located at PCR[DMI] + 274Ch[11] ,
> allows software to
> +  /// re-direct IO port 80h cycles to PCIe bus so that a target (for example, a
> debug card) on
> +  /// PCIe bus can receive and claim these cycles.
> +  /// The "RPR Destination ID", PCR[DMI] + 274Ch[31:16] need to be set
> accordingly to point
> +  /// to the root port that decode this range. Reading from Port 80h may not
> return valid values
> +  /// if the POST-card itself do not shadow the writes. Unlike LPC, PCIe does
> not shadow the Port 80 writes.
> +  ///
> +  PsfRpDestinationId = PsfPcieDestinationId ((UINT32)RpNumber);
> +
> +  DmiRpDestinationId = (UINT16)((0x2 << 12) |
> +                                (PsfRpDestinationId.Fields.PsfId << 8) |
> +                                (PsfRpDestinationId.Fields.PortGroupId << 7) |
> +                                (PsfRpDestinationId.Fields.PortId << 3) |
> +                                 PsfRpDestinationId.Fields.ChannelId);
> +
> +  //
> +  // Program "RPR Destination ID", PCR[DMI] + 274Ch[31:16] to the Dest ID of
> RP.
> +  //
> +  PchPcrWrite16 (PID_DMI, R_PCH_DMI_PCR_GCS + 2, DmiRpDestinationId);
> +  //
> +  // Program "Reserved Page Route", PCR[DMI] + 274Ch[11] to '1'.
> +  // Use byte write on GCS+1 and leave the BILD bit which is RWO.
> +  //
> +  PchPcrAndThenOr8 (PID_DMI, R_PCH_DMI_PCR_GCS + 1, 0xFF,
> (B_PCH_DMI_PCR_RPR >> 8));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Set DMI thermal throttling to recommended configuration.
> +  It's intended only for P-DMI.
> +**/
> +VOID
> +PchDmiSetRecommendedThermalThrottling (
> +  VOID
> +  )
> +{
> +  if (IsPchWithPdmi ()) {
> +    PchDmi15SetRecommendedThermalThrottling ();
> +  }
> +}
> +
> +/**
> +  Set DMI thermal throttling to custom configuration.
> +  This function will configure Thermal Sensor 0/1/2/3 TargetWidth and set
> +  DMI Thermal Sensor Autonomous Width Enable.
> +  It's intended only for P-DMI.
> +
> +  @param[in] DmiThermalThrottling        DMI Thermal Throttling structure.
> +**/
> +VOID
> +PchDmiSetCustomThermalThrottling (
> +  IN DMI_THERMAL_THROTTLING      DmiThermalThrottling
> +  )
> +{
> +  if (IsPchWithPdmi ()) {
> +    PchDmi15SetCustomThermalThrottling (DmiThermalThrottling);
> +  }
> +}
> +
> +/**
> +  Determines where to send the reserved page registers
> +  Accesses to the I/O ranges 80h - 8Fh will be forwarded to PCIe Root Port
> +  with the destination ID specified in GCS.RPRDID using DMI source decode.
> +**/
> +VOID
> +PchDmiSetReservedPageRegToPcieRootPort (
> +  VOID
> +  )
> +{
> +  PchPcrAndThenOr8 (
> +    PID_DMI, R_PCH_DMI_PCR_GCS + 1,
> +    (UINT8) ~0,
> +    (UINT8) (B_PCH_DMI_PCR_RPR >> 8)
> +    );
> +}
> +
> +/**
> +  Determines where to send the reserved page registers
> +  DMI will not perform source decode on the I/O ranges 80h - 8Fh. The cycles
> hitting these ranges will
> +  end up in P2SB which will then forward the cycle to LPC or eSPI through IOSF
> Sideband.
> +**/
> +VOID
> +PchDmiSetReservedPageRegToLpc (
> +  VOID
> +  )
> +{
> +  PchPcrAndThenOr8 (
> +    PID_DMI, R_PCH_DMI_PCR_GCS + 1,
> +    (UINT8) (~(B_PCH_DMI_PCR_RPR >> 8)),
> +    0
> +    );
> +}
> +
> +/**
> +  uCode Patch Region Enable (UPRE). Enables memory access targeting the
> uCode patch region (0xFEF00000 to 0xFEFFFFFF)
> +  to be forwarded to SPI Flash. This can only be set if the boot flash is on SPI.
> +**/
> +VOID
> +PchDmiEnableUCodePatchRegion (
> +  VOID
> +  )
> +{
> +  ///
> +  /// Setup "uCode Patch Region Enable", PCR [DMI] + 2748h[0] to '0b'
> +  ///
> +  PchPcrAndThenOr32 (PID_DMI, R_PCH_DMI_PCR_UCPR, (UINT32)
> ~B_PCH_DMI_PCR_UCPR_UPRE, 0);
> +}
> +
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmiWithS3Lib.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmiWithS3Lib.c
> new file mode 100644
> index 0000000000..9778c9a252
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiL
> ib/PchDmiWithS3Lib.c
> @@ -0,0 +1,79 @@
> +/** @file
> +  PCH DMI library with S3 boot script support.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/S3BootScriptLib.h>
> +#include <Register/PchRegsPcr.h>
> +#include <Register/PchRegsDmi.h>
> +
> +#include "PchDmi14.h"
> +#include "PchDmi15.h"
> +
> +/**
> +  Configure PCH DMI Lock
> +**/
> +VOID
> +PchDmiSetLockWithS3BootScript (
> +  VOID
> +  )
> +{
> +  UINT32  Data32Or;
> +  UINT32  Data32And;
> +  UINT16  Address;
> +
> +  Data32And = 0xFFFFFFFF;
> +  if (IsPchWithPdmi ()) {
> +    PchDmi15SrlRegData (&Address, &Data32Or);
> +  } else {
> +    PchDmi14SrlRegData (&Address, &Data32Or);
> +  }
> +
> +  PchPcrAndThenOr32 (
> +    PID_DMI, Address,
> +    Data32And,
> +    Data32Or
> +    );
> +  PCH_PCR_BOOT_SCRIPT_READ_WRITE (
> +    S3BootScriptWidthUint32,
> +    PID_DMI, Address,
> +    &Data32Or,
> +    &Data32And
> +    );
> +}
> +
> +/**
> +  Set BIOS interface Lock-Down
> +**/
> +VOID
> +PchDmiSetBiosLockDownWithS3BootScript (
> +  VOID
> +  )
> +{
> +  UINT32  Data32Or;
> +  UINT32  Data32And;
> +
> +  //
> +  // Set BIOS Lock-Down (BILD)
> +  // When set, prevents GCS.BBS from being changed
> +  //
> +  Data32And = 0xFFFFFFFF;
> +  Data32Or = B_PCH_DMI_PCR_BILD;
> +  PchPcrAndThenOr32 (PID_DMI, R_PCH_DMI_PCR_GCS, Data32And,
> Data32Or);
> +  PCH_PCR_BOOT_SCRIPT_READ_WRITE (
> +    S3BootScriptWidthUint32,
> +    PID_DMI, R_PCH_DMI_PCR_GCS,
> +    &Data32Or,
> +    &Data32And
> +    );
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitC
> ommonLib/PchInitCommon.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitC
> ommonLib/PchInitCommon.c
> new file mode 100644
> index 0000000000..14bd51ec43
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitC
> ommonLib/PchInitCommon.c
> @@ -0,0 +1,221 @@
> +/** @file
> +  Pch common library for PCH INIT PEI/DXE/SMM modules
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/PciSegmentLib.h>
> +#include <PchPolicyCommon.h>
> +#include <Library/PchCycleDecodingLib.h>
> +#include <Library/PchPcieRpLib.h>
> +#include <Library/PchSbiAccessLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/SataLib.h>
> +#include <Library/S3BootScriptLib.h>
> +#include <Register/PchRegsPcie.h>
> +
> +extern CONST PCH_PCIE_CONTROLLER_INFO mPchPcieControllerInfo[];
> +extern CONST UINT32 mPchPcieControllerInfoSize;
> +
> +#define PORT_PLS_TIMEOUT 100    ///< 100 * 10 us = 1ms timeout for USB3
> PortSC PLS polling
> +
> +/**
> +  This function returns PID according to PCIe controller index
> +
> +  @param[in] ControllerIndex     PCIe controller index
> +
> +  @retval PCH_SBI_PID    Returns PID for SBI Access
> +**/
> +PCH_SBI_PID
> +PchGetPcieControllerSbiPid (
> +  IN  UINT32  ControllerIndex
> +  )
> +{
> +  ASSERT (ControllerIndex < mPchPcieControllerInfoSize);
> +  return mPchPcieControllerInfo[ControllerIndex].Pid;
> +}
> +
> +/**
> +  This function returns PID according to Root Port Number
> +
> +  @param[in] RpIndex     Root Port Index (0-based)
> +
> +  @retval PCH_SBI_PID    Returns PID for SBI Access
> +**/
> +PCH_SBI_PID
> +GetRpSbiPid (
> +  IN  UINTN  RpIndex
> +  )
> +{
> +  return PchGetPcieControllerSbiPid ((UINT32) (RpIndex /
> PCH_PCIE_CONTROLLER_PORTS));
> +}
> +
> +/**
> +  Calculate root port device number based on physical port index.
> +
> +  @param[in]  RpIndex              Root port index (0-based).
> +
> +  @retval     Root port device number.
> +**/
> +UINT32
> +PchGetPcieRpDevice (
> +  IN  UINT32   RpIndex
> +  )
> +{
> +  UINTN ControllerIndex;
> +  ControllerIndex = RpIndex / PCH_PCIE_CONTROLLER_PORTS;
> +  ASSERT (ControllerIndex < mPchPcieControllerInfoSize);
> +  return mPchPcieControllerInfo[ControllerIndex].DevNum;
> +}
> +
> +/**
> +  This function reads Pci Config register via SBI Access
> +
> +  @param[in]  RpIndex             Root Port Index (0-based)
> +  @param[in]  Offset              Offset of Config register
> +  @param[out] *Data32             Value of Config register
> +
> +  @retval EFI_SUCCESS             SBI Read successful.
> +**/
> +EFI_STATUS
> +PchSbiRpPciRead32 (
> +  IN    UINT32  RpIndex,
> +  IN    UINT32  Offset,
> +  OUT   UINT32  *Data32
> +  )
> +{
> +  EFI_STATUS    Status;
> +  UINT32        RpDevice;
> +  UINT8         Response;
> +  UINT16        Fid;
> +
> +  RpDevice = PchGetPcieRpDevice (RpIndex);
> +  Fid = (UINT16) ((RpDevice << 3) | (RpIndex % 4 ));
> +  Status = PchSbiExecutionEx (
> +             GetRpSbiPid (RpIndex),
> +             Offset,
> +             PciConfigRead,
> +             FALSE,
> +             0xF,
> +             0,
> +             Fid,
> +             Data32,
> +             &Response
> +             );
> +  if (Status != EFI_SUCCESS) {
> +    DEBUG((DEBUG_ERROR,"Sideband Read Failed of RpIndex %d Offset 0x%x.
> Device = %d Fid = 0x%x\n",RpIndex, Offset, RpDevice, Fid));
> +    ASSERT (FALSE);
> +  }
> +  return Status;
> +}
> +
> +/**
> +  This function And then Or Pci Config register via SBI Access
> +
> +  @param[in]  RpIndex             Root Port Index (0-based)
> +  @param[in]  Offset              Offset of Config register
> +  @param[in]  Data32And           Value of Config register to be And-ed
> +  @param[in]  Data32AOr           Value of Config register to be Or-ed
> +
> +  @retval EFI_SUCCESS             SBI Read and Write successful.
> +**/
> +EFI_STATUS
> +PchSbiRpPciAndThenOr32 (
> +  IN  UINT32  RpIndex,
> +  IN  UINT32  Offset,
> +  IN  UINT32  Data32And,
> +  IN  UINT32  Data32Or
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT32      RpDevice;
> +  UINT32      Data32;
> +  UINT8       Response;
> +  UINT16      Fid;
> +
> +  RpDevice = PchGetPcieRpDevice (RpIndex);
> +  Status = PchSbiRpPciRead32 (RpIndex, Offset, &Data32);
> +  if (Status == EFI_SUCCESS) {
> +    Data32 &= Data32And;
> +    Data32 |= Data32Or;
> +    Fid = (UINT16) ((RpDevice << 3) | (RpIndex % 4 ));
> +    Status = PchSbiExecutionEx (
> +               GetRpSbiPid (RpIndex),
> +               Offset,
> +               PciConfigWrite,
> +               FALSE,
> +               0xF,
> +               0,
> +               Fid,
> +               &Data32,
> +               &Response
> +               );
> +    if (Status != EFI_SUCCESS) {
> +      DEBUG((DEBUG_ERROR,"Sideband Write Failed of RpIndex %d Offset
> 0x%x. Device = %d Fid = 0x%x\n",RpIndex, Offset, RpDevice, Fid));
> +      ASSERT (FALSE);
> +    }
> +  } else {
> +    ASSERT (FALSE);
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Print registers value
> +
> +  @param[in] PrintMmioBase       Mmio base address
> +  @param[in] PrintSize           Number of registers
> +  @param[in] OffsetFromBase      Offset from mmio base address
> +
> +  @retval None
> +**/
> +VOID
> +PrintRegisters (
> +  IN  UINTN        PrintMmioBase,
> +  IN  UINT32       PrintSize,
> +  IN  UINT32       OffsetFromBase
> +  )
> +{
> +  UINT32  Offset;
> +  DEBUG ((DEBUG_VERBOSE, "       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D
> 0E 0F"));
> +  for (Offset = 0; Offset < PrintSize; Offset++) {
> +    if ((Offset % 16) == 0) {
> +      DEBUG ((DEBUG_VERBOSE, "\n %04X: ", (Offset + OffsetFromBase) &
> 0xFFF0));
> +    }
> +    DEBUG ((DEBUG_VERBOSE, "%02X ", MmioRead8 (PrintMmioBase +
> Offset)));
> +  }
> +  DEBUG ((DEBUG_VERBOSE, "\n"));
> +}
> +
> +/**
> +  Print registers value
> +
> +  @param[in] PrintPciSegmentBase Pci segment base address
> +  @param[in] PrintSize           Number of registers
> +  @param[in] OffsetFromBase      Offset from mmio base address
> +
> +  @retval None
> +**/
> +VOID
> +PrintPciRegisters (
> +  IN  UINT64       PrintPciSegmentBase,
> +  IN  UINT32       PrintSize,
> +  IN  UINT32       OffsetFromBase
> +  )
> +{
> +  UINT32  Offset;
> +  DEBUG ((DEBUG_VERBOSE, "       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D
> 0E 0F"));
> +  for (Offset = 0; Offset < PrintSize; Offset++) {
> +    if ((Offset % 16) == 0) {
> +      DEBUG ((DEBUG_VERBOSE, "\n %04X: ", (Offset + OffsetFromBase) &
> 0xFFF0));
> +    }
> +    DEBUG ((DEBUG_VERBOSE, "%02X ", PciSegmentRead8
> (PrintPciSegmentBase + Offset)));
> +  }
> +  DEBUG ((DEBUG_VERBOSE, "\n"));
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciEx
> pressHelpersLib/PchPciExpressHelpersLibrary.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciEx
> pressHelpersLib/PchPciExpressHelpersLibrary.c
> new file mode 100644
> index 0000000000..dcb43285b7
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciEx
> pressHelpersLib/PchPciExpressHelpersLibrary.c
> @@ -0,0 +1,2407 @@
> +/** @file
> +  This file contains routines that support PCI Express initialization
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "PchPciExpressHelpersLibrary.h"
> +#include <Library/BaseMemoryLib.h>
> +
> +#define ASPM_L1_NO_LIMIT 0xFF
> +#define ASPM_L0s_NO_LIMIT 0x7
> +
> +#define LINK_RETRAIN_WAIT_TIME 1000 // microseconds
> +//
> +// This structure conveniently keeps segment:bus:device:function
> coordinates of a PCIe device
> +// in a single variable. PcieCap is offset to PCI Express capabilities. Having it
> cached together
> +// with coordinates is an optimization feature, because code in this file uses
> it a lot
> +//
> +typedef struct {
> +  UINT32 Seg     : 8;
> +  UINT32 Bus     : 8;
> +  UINT32 Dev     : 5;
> +  UINT32 Func    : 3;
> +  UINT32 PcieCap : 8;
> +} SBDF;
> +
> +typedef struct {
> +  UINT32 MaxSnoopLatencyValue         : 10;
> +  UINT32 MaxSnoopLatencyScale         : 3;
> +  UINT32 MaxSnoopLatencyRequirement   : 1;
> +  UINT32 MaxNoSnoopLatencyValue       : 10;
> +  UINT32 MaxNoSnoopLatencyScale       : 3;
> +  UINT32 MaxNoSnoopLatencyRequirement : 1;
> +  UINT32 ForceOverride                : 1;
> +} LTR_OVERRIDE;
> +
> +typedef struct {
> +  UINT32 MaxSnoopLatencyValue         : 10;
> +  UINT32 MaxSnoopLatencyScale         : 3;
> +  UINT32 MaxNoSnoopLatencyValue       : 10;
> +  UINT32 MaxNoSnoopLatencyScale       : 3;
> +} LTR_LIMIT;
> +
> +#define MSLV_BIT_OFFSET   0
> +#define MSLS_BIT_OFFSET  10
> +#define MNSLV_BIT_OFFSET 13
> +#define MNSLS_BIT_OFFSET 23
> +
> +
> +typedef struct {
> +  UINT32                          Size;
> +  const PCH_PCIE_DEVICE_OVERRIDE* Table;
> +} OVERRIDE_TABLE;
> +
> +typedef enum {
> +  DevTypePci,
> +  DevTypePcieEndpoint,
> +  DevTypePcieUpstream,
> +  DevTypePcieDownstream,
> +  DevTypeMax
> +} PCI_DEV_TYPE;
> +
> +//
> +// This structure keeps in one place all data relevant to enabling L0s and L1.
> +// L0s latencies are encoded in the same way as in hardware registers. The
> only operation
> +// that will be performed on them is comparison
> +// L1 latencies are decoded to microseconds, because they will be used in
> subtractions and additions
> +//
> +typedef struct {
> +  UINT32  L0sSupported          : 1;
> +  UINT32  L1Supported           : 1;
> +  UINT32  L0sAcceptableLatency  : 3; // encoded as in hardware register
> +  UINT32  L1AcceptableLatencyUs : 8; // decoded to microseconds
> +  UINT32  LinkL0sExitLatency    : 3; // encoded as in hardware register
> +  UINT32  LinkL1ExitLatencyUs   : 8; // decoded to microseconds
> +} ASPM_CAPS;
> +
> +typedef struct {
> +  UINT32     AspmL11  : 1;
> +  UINT32     AspmL12  : 1;
> +  UINT32     PmL11    : 1;
> +  UINT32     PmL12    : 1;
> +  UINT32     Cmrt     : 8; // Common Mode Restore Time
> +  UINT32     TpoScale : 2; // T power_on scale
> +  UINT32     TpoValue : 6; // T power_on value
> +} L1SS_CAPS;
> +
> +#define MAX_SBDF_TABLE_SIZE 50 //arbitrary table size; big enough to
> accomodate even full length TBT chain.
> +
> +typedef struct {
> +  UINT32 Count;
> +  SBDF   Entry [MAX_SBDF_TABLE_SIZE];
> +} SBDF_TABLE;
> +
> +/**
> +  Converts device's segment:bus:device:function coordinates to flat address
> +
> +  @param[in] Sbdf   device's segment:bus:device:function coordinates
> +  @retval    address of device's PCI cfg space
> +**/
> +STATIC
> +UINT64
> +SbdfToBase (
> +  SBDF Sbdf
> +  )
> +{
> +  return PCI_SEGMENT_LIB_ADDRESS (Sbdf.Seg, Sbdf.Bus, Sbdf.Dev, Sbdf.Func,
> 0);
> +}
> +
> +/**
> +  Get PCIe port number for enabled port.
> +  @param[in] RpBase    Root Port pci segment base address
> +  @retval Root Port number (1 based)
> +**/
> +UINT32
> +PciePortNum (
> +  IN     UINT64  RpBase
> +  )
> +{
> +  return PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_LCAP) >>
> N_PCH_PCIE_CFG_LCAP_PN;
> +}
> +
> +/**
> +  Get PCIe root port index
> +  @param[in] RpBase    Root Port pci segment base address
> +  @retval Root Port index (0 based)
> +**/
> +UINT32
> +PciePortIndex (
> +  IN     UINT64  RpBase
> +  )
> +{
> +  return PciePortNum (RpBase) - 1;
> +}
> +
> +/**
> +  Translate PCIe Port/Lane pair to 0-based PCIe lane number.
> +
> +  @param[in] RpIndex    Root Port index
> +  @param[in] RpLane     Root Port Lane (0-3)
> +
> +  @retval PCIe lane number (0-based)
> +**/
> +UINT32
> +PchPciePhysicalLane (
> +  UINT32 RpIndex,
> +  UINT32 RpLane
> +  )
> +{
> +  UINT32  ControllerIndex;
> +  UINT32  ControllerLane;
> +
> +  ASSERT (RpIndex < GetPchMaxPciePortNum ());
> +  ASSERT (((RpIndex % 4) + RpLane) < 4);
> +
> +  ControllerIndex = (RpIndex / 4);
> +  ControllerLane  = (RpIndex % 4) + RpLane;
> +  if (IsPcieLaneReversalEnabled (RpIndex)) {
> +    ControllerLane = 3 - ControllerLane;
> +  }
> +  return (ControllerIndex * 4) + ControllerLane;
> +}
> +
> +/**
> +  Checks if lane reversal is enabled on a given root port
> +
> +  @param[in] RpIndex  Root port index (0-based)
> +
> +  @retval TRUE if lane reversal is enbabled, FALSE otherwise
> +**/
> +BOOLEAN
> +IsPcieLaneReversalEnabled (
> +  IN     UINT32  RpIndex
> +  )
> +{
> +  UINT32  Data32;
> +  PchSbiRpPciRead32 (PchGetPcieFirstPortIndex (RpIndex),
> R_PCH_PCIE_CFG_PCIEDBG, &Data32);
> +  return !! (Data32 & B_PCH_PCIE_CFG_PCIEDBG_LR);
> +}
> +
> +/**
> +  Calculates the index of the first port on the same controller.
> +
> +  @param[in] RpIndex     Root Port Number (0-based)
> +
> +  @retval Index of the first port on the first controller.
> +**/
> +UINT32
> +PchGetPcieFirstPortIndex (
> +  IN     UINT32  RpIndex
> +  )
> +{
> +  UINT32  ControllerIndex;
> +
> +  ControllerIndex = RpIndex / PCH_PCIE_CONTROLLER_PORTS;
> +  return ControllerIndex * PCH_PCIE_CONTROLLER_PORTS;
> +}
> +
> +/*
> +  Returns Tpower_on capability of device
> +
> +  @param[in] DeviceBase       device's PCI segment base address
> +  @param[in] L1ssCapOffset    offset to L1substates capability in device's
> extended config space
> +
> +  @retval                     structure containing Tpoweron scale and value
> +*/
> +T_POWER_ON
> +GetTpoCapability (
> +  UINT64 DeviceBase,
> +  UINT32 L1ssCapOffset
> +  )
> +{
> +  T_POWER_ON Tpo;
> +  UINT32     L1ssCapabilities;
> +
> +  L1ssCapabilities = PciSegmentRead32 (DeviceBase + L1ssCapOffset +
> R_PCIE_EX_L1SCAP_OFFSET);
> +  Tpo.Scale = (L1ssCapabilities & B_PCIE_EX_L1SCAP_PTPOS) >>
> N_PCIE_EX_L1SCAP_PTPOS;
> +  Tpo.Value = (L1ssCapabilities & B_PCIE_EX_L1SCAP_PTV) >>
> N_PCIE_EX_L1SCAP_PTV;
> +  return Tpo;
> +}
> +
> +/*
> +  Converts Tpower_on from value:scale notation to microseconds
> +
> +  @param[in] TpoScale   T power on scale
> +  @param[in] TpoValue   T power on value
> +
> +  @retval    number of microseconds
> +*/
> +UINT32
> +TpoToUs (
> +  UINT32 TpoScale,
> +  UINT32 TpoValue
> +  )
> +{
> +  static const UINT8 TpoScaleMultiplier[] = {2, 10, 100};
> +
> +  ASSERT (TpoScale < TpoScaleMax);
> +  if (TpoScale >= TpoScaleMax) {
> +    return 0;
> +  }
> +  return (TpoScaleMultiplier[TpoScale] * TpoValue);
> +}
> +
> +/**
> +  Finds the Offset to a given Capabilities ID
> +  Each capability has an ID and a pointer to next Capability, so they form a
> linked list.
> +  This function walks the list of Capabilities present in device's pci cfg. If
> requested capability
> +  can be found, its offset is returned.
> +  If the capability can't be found or if device doesn't exist, function returns 0
> +  CAPID list:
> +    0x01 = PCI Power Management Interface
> +    0x04 = Slot Identification
> +    0x05 = MSI Capability
> +    0x10 = PCI Express Capability
> +
> +  @param[in] DeviceBase           device's base address
> +  @param[in] CapId                CAPID to search for
> +
> +  @retval 0                       CAPID not found (this includes situation where
> device doesn't exit)
> +  @retval Other                   CAPID found, Offset of desired CAPID
> +**/
> +UINT8
> +PcieBaseFindCapId (
> +  IN UINT64  DeviceBase,
> +  IN UINT8   CapId
> +  )
> +{
> +  UINT8  CapHeaderOffset;
> +  UINT8  CapHeaderId;
> +  UINT16 Data16;
> +  //
> +  // We do not explicitly check if device exists to save time and avoid
> unnecessary PCI access
> +  // If the device doesn't exist, check for CapHeaderId != 0xFF will fail and
> function will return offset 0
> +  //
> +  if ((PciSegmentRead8 (DeviceBase + PCI_PRIMARY_STATUS_OFFSET) &
> EFI_PCI_STATUS_CAPABILITY) == 0x00) {
> +    ///
> +    /// Function has no capability pointer
> +    ///
> +    return 0;
> +  } else {
> +    ///
> +    /// Check the header layout to determine the Offset of Capabilities Pointer
> Register
> +    ///
> +    if ((PciSegmentRead8 (DeviceBase + PCI_HEADER_TYPE_OFFSET) &
> HEADER_LAYOUT_CODE) == (HEADER_TYPE_CARDBUS_BRIDGE)) {
> +      ///
> +      /// If CardBus bridge, start at Offset 0x14
> +      ///
> +      CapHeaderOffset = EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR;
> +    } else {
> +      ///
> +      /// Otherwise, start at Offset 0x34
> +      ///
> +      CapHeaderOffset = PCI_CAPBILITY_POINTER_OFFSET;
> +    }
> +    ///
> +    /// Get Capability Header, A pointer value of 00h is used to indicate the last
> capability in the list.
> +    ///
> +    CapHeaderId     = 0;
> +    CapHeaderOffset = PciSegmentRead8 (DeviceBase + CapHeaderOffset) &
> ((UINT8) ~(BIT0 | BIT1));
> +    while (CapHeaderOffset != 0 && CapHeaderId != 0xFF) {
> +      Data16 = PciSegmentRead16 (DeviceBase + CapHeaderOffset);
> +      CapHeaderId = (UINT8)(Data16 & 0xFF);
> +      if (CapHeaderId == CapId) {
> +        if (CapHeaderOffset > PCI_MAXLAT_OFFSET) {
> +          ///
> +          /// Return valid capability offset
> +          ///
> +          DEBUG ((DEBUG_INFO,"CapId %x,%x->%02x\n",
> ((UINT32)(DeviceBase&0xFFFFF000)>>12), CapId, CapHeaderOffset));
> +          return CapHeaderOffset;
> +        } else {
> +          ASSERT ((FALSE));
> +          return 0;
> +        }
> +      }
> +      ///
> +      /// Each capability must be DWORD aligned.
> +      /// The bottom two bits of all pointers (including the initial pointer at 34h)
> are reserved
> +      /// and must be implemented as 00b although software must mask them
> to allow for future uses of these bits.
> +      ///
> +      CapHeaderOffset = (UINT8)(Data16 >> 8);
> +    }
> +    return 0;
> +  }
> +}
> +
> +/**
> +  Find the Offset to a given Capabilities ID
> +  CAPID list:
> +    0x01 = PCI Power Management Interface
> +    0x04 = Slot Identification
> +    0x05 = MSI Capability
> +    0x10 = PCI Express Capability
> +
> +  @param[in] Segment              Pci Segment Number
> +  @param[in] Bus                  Pci Bus Number
> +  @param[in] Device               Pci Device Number
> +  @param[in] Function             Pci Function Number
> +  @param[in] CapId                CAPID to search for
> +
> +  @retval 0                       CAPID not found
> +  @retval Other                   CAPID found, Offset of desired CAPID
> +**/
> +UINT8
> +PcieFindCapId (
> +  IN UINT8   Segment,
> +  IN UINT8   Bus,
> +  IN UINT8   Device,
> +  IN UINT8   Function,
> +  IN UINT8   CapId
> +  )
> +{
> +  UINT64 DeviceBase;
> +
> +  DEBUG ((DEBUG_INFO,"PcieFindCapId () SBDF %0x: %0x: %0x :%0x, CapId =
> %0x \n", Segment, Bus, Device, Function, CapId));
> +  DeviceBase = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function,
> 0);
> +  return PcieBaseFindCapId (DeviceBase, CapId);
> +}
> +
> +/**
> +  Search and return the offset of desired Pci Express Capability ID
> +  CAPID list:
> +    0x0001 = Advanced Error Reporting Capability
> +    0x0002 = Virtual Channel Capability
> +    0x0003 = Device Serial Number Capability
> +    0x0004 = Power Budgeting Capability
> +
> +  @param[in] DeviceBase           device base address
> +  @param[in] CapId                Extended CAPID to search for
> +
> +  @retval 0                       CAPID not found, this includes situation where
> device doesn't exist
> +  @retval Other                   CAPID found, Offset of desired CAPID
> +**/
> +UINT16
> +PcieBaseFindExtendedCapId (
> +  IN UINT64  DeviceBase,
> +  IN UINT16  CapId
> +  )
> +{
> +  UINT16  CapHeaderOffset;
> +  UINT16  CapHeaderId;
> +  ///
> +  /// Start to search at Offset 0x100
> +  /// Get Capability Header, A pointer value of 00h is used to indicate the last
> capability in the list.
> +  ///
> +  CapHeaderId     = 0;
> +  CapHeaderOffset = R_PCH_PCIE_CFG_EXCAP_OFFSET;
> +  while (CapHeaderOffset != 0 && CapHeaderId != MAX_UINT16) {
> +    CapHeaderId = PciSegmentRead16 (DeviceBase + CapHeaderOffset);
> +    if (CapHeaderId == CapId) {
> +      return CapHeaderOffset;
> +    }
> +    ///
> +    /// Each capability must be DWORD aligned.
> +    /// The bottom two bits of all pointers are reserved and must be
> implemented as 00b
> +    /// although software must mask them to allow for future uses of these
> bits.
> +    ///
> +    CapHeaderOffset = (PciSegmentRead16 (DeviceBase + CapHeaderOffset +
> 2) >> 4) & ((UINT16) ~(BIT0 | BIT1));
> +  }
> +
> +  return 0;
> +}
> +
> +/**
> +  Search and return the offset of desired Pci Express Capability ID
> +  CAPID list:
> +    0x0001 = Advanced Error Reporting Capability
> +    0x0002 = Virtual Channel Capability
> +    0x0003 = Device Serial Number Capability
> +    0x0004 = Power Budgeting Capability
> +
> +  @param[in] Segment              Pci Segment Number
> +  @param[in] Bus                  Pci Bus Number
> +  @param[in] Device               Pci Device Number
> +  @param[in] Function             Pci Function Number
> +  @param[in] CapId                Extended CAPID to search for
> +
> +  @retval 0                       CAPID not found, this includes situation where
> device doesn't exist
> +  @retval Other                   CAPID found, Offset of desired CAPID
> +**/
> +UINT16
> +PcieFindExtendedCapId (
> +  IN UINT8   Segment,
> +  IN UINT8   Bus,
> +  IN UINT8   Device,
> +  IN UINT8   Function,
> +  IN UINT16  CapId
> +  )
> +{
> +  UINT64  DeviceBase;
> +
> +  DeviceBase = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function,
> 0);
> +  return PcieBaseFindExtendedCapId (DeviceBase, CapId);
> +}
> +
> +/**
> +  This function checks whether PHY lane power gating is enabled on the port.
> +
> +  @param[in] RpBase                 Root Port base address
> +
> +  @retval TRUE                      PHY power gating is enabled
> +  @retval FALSE                     PHY power gating disabled
> +**/
> +STATIC
> +BOOLEAN
> +PcieIsPhyLanePgEnabled (
> +  IN     UINT64  RpBase
> +  )
> +{
> +  UINT32 Data32;
> +  Data32 = PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL);
> +  return (Data32 & B_PCH_PCIE_CFG_PCIEPMECTL_DLSULPPGE) != 0;
> +}
> +
> +/**
> +  Get current PCIe link speed.
> +
> +  @param[in] RpBase    Root Port base address
> +  @retval Link speed
> +**/
> +UINT32
> +GetLinkSpeed (
> +  UINT64  RpBase
> +  )
> +{
> +  return PciSegmentRead16 (RpBase + R_PCH_PCIE_CFG_LSTS) &
> B_PCIE_LSTS_CLS;
> +}
> +
> +/**
> +  Get max PCIe link speed supported by the root port.
> +
> +  @param[in] RpBase    Root Port base address
> +  @retval Max link speed
> +**/
> +UINT32
> +GetMaxLinkSpeed (
> +  UINT64 RpBase
> +  )
> +{
> +  return PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_LCAP) &
> B_PCIE_LCAP_MLS;
> +}
> +
> +/**
> +  Get max payload size supported by device.
> +
> +  @param[in] Sbdf   device's segment:bus:device:function coordinates
> +  @retval    Max payload size, encoded in the same way as in register (0=128b,
> 1=256b, etc)
> +**/
> +STATIC
> +UINT8
> +GetMps (
> +  SBDF Sbdf
> +  )
> +{
> +  return (PciSegmentRead16 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_DCAP_OFFSET) & B_PCIE_DCAP_MPS);
> +}
> +
> +/**
> +  Sets Maximum Payload Size to be used by device
> +
> +  @param[in] Sbdf   device's segment:bus:device:function coordinates
> +  @param[in] Mps    Max payload size, encoded in the same way as in
> register (0=128b, 1=256b, etc)
> +**/
> +STATIC
> +VOID
> +SetMps (
> +  SBDF  Sbdf,
> +  UINT8  Mps
> +  )
> +{
> +  PciSegmentAndThenOr16 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_DCTL_OFFSET, (UINT16) ~B_PCIE_DCTL_MPS, Mps <<
> N_PCIE_DCTL_MPS);
> +}
> +
> +/**
> +  Checks if given PCI device is capable of Latency Tolerance Reporting
> +
> +  @param[in] Sbdf            device's segment:bus:device:function
> coordinates
> +
> +  @retval TRUE if yes
> +**/
> +STATIC
> +BOOLEAN
> +IsLtrCapable (
> +  SBDF Sbdf
> +  )
> +{
> +  if (Sbdf.PcieCap == 0) {
> +    return FALSE;
> +  }
> +  return !!(PciSegmentRead32 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_DCAP2_OFFSET) & B_PCIE_DCAP2_LTRMS);
> +}
> +
> +/**
> +  Enables LTR feature in given device
> +
> +  @param[in] Sbdf            device's segment:bus:device:function
> coordinates
> +**/
> +STATIC
> +VOID
> +EnableLtr (
> +  SBDF Sbdf
> +  )
> +{
> +  if (Sbdf.PcieCap == 0) {
> +    return;
> +  }
> +  PciSegmentOr32 (SbdfToBase (Sbdf) + Sbdf.PcieCap + R_PCIE_DCTL2_OFFSET,
> B_PCIE_DCTL2_LTREN);
> +}
> +
> +/**
> +  Checks if PCI device at given address exists
> +
> +  @param[in] Base            device's base address
> +
> +  @retval TRUE if exists
> +**/
> +BOOLEAN
> +IsDevicePresent (
> +  UINT64 Base
> +  )
> +{
> +  if (PciSegmentRead16 (Base) == 0xFFFF) {
> +    return FALSE;
> +  }
> +  return TRUE;
> +}
> +
> +/**
> +  Returns information about type of device.
> +
> +  @param[out] Sbdf            device's segment:bus:device:function
> coordinates
> +  @retval     one of: not a PCIe device (legacy PCI), PCIe endpoint, PCIe
> upstream port or PCIe downstream port (including rootport)
> +**/
> +STATIC
> +PCI_DEV_TYPE
> +GetDeviceType (
> +  SBDF Sbdf
> +  )
> +{
> +  UINT8 DeviceType;
> +
> +  if (Sbdf.PcieCap == 0) {
> +    return DevTypePci;
> +  }
> +  DeviceType = (UINT8) ((PciSegmentRead16 (SbdfToBase (Sbdf) +
> Sbdf.PcieCap + R_PCIE_XCAP_OFFSET) & B_PCIE_XCAP_DT) >>
> N_PCIE_XCAP_DT);
> +  if (DeviceType == PCIE_DEVICE_PORT_TYPE_UPSTREAM_PORT) {
> +    return DevTypePcieUpstream;
> +  } else if (DeviceType == PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT ||
> DeviceType == PCIE_DEVICE_PORT_TYPE_ROOT_PORT) {
> +    return DevTypePcieDownstream;
> +  } else {
> +    return DevTypePcieEndpoint;
> +  }
> +}
> +
> +/**
> +  Initializes Dev:Func numbers for use in FindNextPcieChild or
> FindNextLegalSbdf functions.
> +
> +  @param[out] Sbdf            device's segment:bus:device:function
> coordinates
> +**/
> +STATIC
> +VOID
> +InitChildFinder (
> +  OUT SBDF *Sbdf
> +  )
> +{
> +  //
> +  // Initialize Dev/Func to maximum values, so that when FindNextLegalSbdf
> ()
> +  // is called on those input parameters, it will return 1st legal address (Dev 0
> Func 0).
> +  //
> +  Sbdf->Dev = PCI_MAX_DEVICE;
> +  Sbdf->Func = PCI_MAX_FUNC;
> +}
> +
> +/**
> +  Checks the device is a bridge and has non-zero secondary bus number
> assigned.
> +  If so, it returns TRUE and initializes ChildSbdf with such values that
> +  allow searching for devices on the secondary bus.
> +  ChildSbdf will be mangled even if this function returns FALSE.
> +
> +  Legal bus assignment is assumed. This function doesn't check subordinate
> bus numbers of
> +  the the device it was called on or any bridges between it and root complex
> +
> +  @param[in]  Sbdf       device's segment:bus:device:function coordinates
> +  @param[out] ChildSbdf  SBDF initialized in such way that calling
> FindNextPcieChild( ) on it will find all children devices
> +
> +  @retval TRUE if device is a bridge and has a bus behind it; FALSE otherwise
> +**/
> +STATIC
> +BOOLEAN
> +HasChildBus (
> +  SBDF   Sbdf,
> +  SBDF   *ChildSbdf
> +  )
> +{
> +  UINT32 Data32;
> +  UINT64 Base;
> +  UINT8  SecondaryBus;
> +
> +  ChildSbdf->Seg = Sbdf.Seg;
> +  InitChildFinder (ChildSbdf);
> +
> +  Base = SbdfToBase (Sbdf);
> +
> +  if (PciSegmentRead8 (Base + R_PCI_BCC_OFFSET) != PCI_CLASS_BRIDGE) {
> +    DEBUG ((DEBUG_INFO, "HasChildBus%02:%02:%02: no\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +    return FALSE;
> +  }
> +  Data32 = PciSegmentRead32 (Base +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
> +  SecondaryBus = (UINT8)((Data32 & B_PCI_BRIDGE_BNUM_SCBN) >> 8);
> +  ChildSbdf->Bus = SecondaryBus;
> +  if (SecondaryBus == 0) {
> +    DEBUG ((DEBUG_INFO, "HasChildBus%02x:%02x:%02x: no\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +    return FALSE;
> +  } else {
> +    DEBUG ((DEBUG_INFO, "HasChildBus%02x:%02x:%02x: yes, %x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func, SecondaryBus));
> +    return TRUE;
> +  }
> +}
> +
> +/**
> +  Checks if device is a multifunction device
> +  Besides comparing Multifunction bit (BIT7) it checks if contents of
> HEADER_TYPE register
> +  make sense (header != 0xFF) to prevent false positives when called on
> devices which do not exist
> +
> +  @param[in] Base            device's base address
> +
> +  @retval TRUE if multifunction; FALSE otherwise
> +**/
> +BOOLEAN
> +IsMultifunctionDevice (
> +  UINT64 Base
> +  )
> +{
> +  UINT8 HeaderType;
> +  HeaderType = PciSegmentRead8(Base + PCI_HEADER_TYPE_OFFSET);
> +  if ((HeaderType == 0xFF) || ((HeaderType &
> HEADER_TYPE_MULTI_FUNCTION) == 0)) {
> +    return FALSE;
> +  }
> +  return TRUE;
> +}
> +
> +/**
> +  Returns combination of two LTR override values
> +  The resulting LTR override separately chooses stricter limits for snoop and
> nosnoop
> +
> +  @param[in] LtrA      LTR override values to be combined
> +  @param[in] LtrB      LTR override values to be combined
> +
> +  @retval LTR override value
> +**/
> +STATIC
> +LTR_OVERRIDE
> +CombineLtr (
> +  LTR_OVERRIDE LtrA,
> +  LTR_OVERRIDE LtrB
> +  )
> +{
> +  UINT64        DecodedLatencyA;
> +  UINT64        DecodedLatencyB;
> +  LTR_OVERRIDE  Result;
> +  static UINT32 ScaleEncoding [8] = {1, 32, 1024, 32768, 1048576, 33554432, 0,
> 0};
> +
> +  DecodedLatencyA = ScaleEncoding[LtrA.MaxSnoopLatencyScale] *
> LtrA.MaxSnoopLatencyValue;
> +  DecodedLatencyB = ScaleEncoding[LtrB.MaxSnoopLatencyScale] *
> LtrB.MaxSnoopLatencyValue;
> +  if ((!LtrB.MaxSnoopLatencyRequirement) || ((DecodedLatencyA <
> DecodedLatencyB) && LtrA.MaxSnoopLatencyRequirement)) {
> +    Result.MaxSnoopLatencyValue       = LtrA.MaxSnoopLatencyValue;
> +    Result.MaxSnoopLatencyScale       = LtrA.MaxSnoopLatencyScale;
> +    Result.MaxSnoopLatencyRequirement =
> LtrA.MaxSnoopLatencyRequirement;
> +  } else {
> +    Result.MaxSnoopLatencyValue       = LtrB.MaxSnoopLatencyValue;
> +    Result.MaxSnoopLatencyScale       = LtrB.MaxSnoopLatencyScale;
> +    Result.MaxSnoopLatencyRequirement =
> LtrB.MaxSnoopLatencyRequirement;
> +  }
> +  DecodedLatencyA = ScaleEncoding[LtrA.MaxNoSnoopLatencyScale] *
> LtrA.MaxNoSnoopLatencyValue;
> +  DecodedLatencyB = ScaleEncoding[LtrB.MaxNoSnoopLatencyScale] *
> LtrB.MaxNoSnoopLatencyValue;
> +  if ((!LtrB.MaxNoSnoopLatencyRequirement) || ((DecodedLatencyA <
> DecodedLatencyB) && LtrA.MaxNoSnoopLatencyRequirement)) {
> +    Result.MaxNoSnoopLatencyValue       = LtrA.MaxNoSnoopLatencyValue;
> +    Result.MaxNoSnoopLatencyScale       = LtrA.MaxNoSnoopLatencyScale;
> +    Result.MaxNoSnoopLatencyRequirement =
> LtrA.MaxNoSnoopLatencyRequirement;
> +  } else {
> +    Result.MaxNoSnoopLatencyValue       = LtrB.MaxNoSnoopLatencyValue;
> +    Result.MaxNoSnoopLatencyScale       = LtrB.MaxNoSnoopLatencyScale;
> +    Result.MaxNoSnoopLatencyRequirement =
> LtrB.MaxNoSnoopLatencyRequirement;
> +  }
> +  Result.ForceOverride = FALSE;
> +  if (LtrA.ForceOverride || LtrB.ForceOverride) {
> +    Result.ForceOverride = TRUE;
> +  }
> +  DEBUG ((DEBUG_INFO, "CombineLtr: A(V%d S%d E%d : V%d S%d E%d,
> F%d)\n",
> +    LtrA.MaxSnoopLatencyValue, LtrA.MaxSnoopLatencyScale,
> LtrA.MaxSnoopLatencyRequirement,
> +    LtrA.MaxNoSnoopLatencyValue, LtrA.MaxNoSnoopLatencyScale,
> LtrA.MaxNoSnoopLatencyRequirement,
> +    LtrA.ForceOverride
> +    ));
> +  DEBUG ((DEBUG_INFO, "          : B(V%d S%d E%d : V%d S%d E%d, F%d)\n",
> +    LtrB.MaxSnoopLatencyValue, LtrB.MaxSnoopLatencyScale,
> LtrB.MaxSnoopLatencyRequirement,
> +    LtrB.MaxNoSnoopLatencyValue, LtrB.MaxNoSnoopLatencyScale,
> LtrB.MaxNoSnoopLatencyRequirement,
> +    LtrB.ForceOverride
> +    ));
> +  DEBUG ((DEBUG_INFO, "          : R(V%d S%d E%d : V%d S%d E%d, F%d)\n",
> +    Result.MaxSnoopLatencyValue, Result.MaxSnoopLatencyScale,
> Result.MaxSnoopLatencyRequirement,
> +    Result.MaxNoSnoopLatencyValue, Result.MaxNoSnoopLatencyScale,
> Result.MaxNoSnoopLatencyRequirement,
> +    Result.ForceOverride
> +    ));
> +  return Result;
> +}
> +
> +/**
> +  Returns LTR override value for given device
> +  The value is extracted from Device Override table. If the device is not found,
> +  the returned value will have Requirement bits clear
> +
> +  @param[in] Base            device's base address
> +  @param[in] Override        device override table
> +
> +  @retval LTR override value
> +**/
> +STATIC
> +LTR_OVERRIDE
> +GetOverrideLtr (
> +  UINT64         Base,
> +  OVERRIDE_TABLE *Override
> +  )
> +{
> +  UINT16       DevId;
> +  UINT16       VenId;
> +  UINT16       RevId;
> +  UINT32       Index;
> +  LTR_OVERRIDE ReturnValue = {0};
> +
> +  VenId = PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);
> +  DevId = PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);
> +  RevId = PciSegmentRead16 (Base + PCI_REVISION_ID_OFFSET);
> +
> +  for (Index = 0; Index < Override->Size; Index++) {
> +    if (((Override->Table[Index].OverrideConfig & PchPcieLtrOverride) ==
> PchPcieLtrOverride) &&
> +        (Override->Table[Index].VendorId == VenId) &&
> +        ((Override->Table[Index].DeviceId == DevId) ||
> (Override->Table[Index].DeviceId == 0xFFFF)) &&
> +        ((Override->Table[Index].RevId == RevId) ||
> (Override->Table[Index].RevId == 0xFF))) {
> +      if (Override->Table[Index].SnoopLatency & 0x8000) {
> +        ReturnValue.MaxSnoopLatencyRequirement = 1;
> +        ReturnValue.MaxSnoopLatencyValue =
> Override->Table[Index].SnoopLatency & 0x3FF;
> +        ReturnValue.MaxSnoopLatencyScale =
> (Override->Table[Index].SnoopLatency & 0x1C00) >> 10;
> +      }
> +      if (Override->Table[Index].NonSnoopLatency & 0x8000) {
> +        ReturnValue.MaxNoSnoopLatencyRequirement = 1;
> +        ReturnValue.MaxNoSnoopLatencyValue =
> Override->Table[Index].NonSnoopLatency & 0x3FF;
> +        ReturnValue.MaxNoSnoopLatencyScale =
> (Override->Table[Index].NonSnoopLatency & 0x1C00) >> 10;
> +      }
> +      ReturnValue.ForceOverride = Override->Table[Index].ForceLtrOverride;
> +      break;
> +    }
> +  }
> +  return ReturnValue;
> +}
> +
> +/**
> +  Sets LTR limit in a device.
> +
> +  @param[in] Base            device's base address
> +  @param[in] Ltr             LTR limit
> +**/
> +STATIC
> +VOID
> +SetLtrLimit (
> +  UINT64    Base,
> +  LTR_LIMIT Ltr
> +  )
> +{
> +  UINT16 LtrCapOffset;
> +  UINT16 Data16;
> +
> +  LtrCapOffset = PcieBaseFindExtendedCapId (Base,
> R_PCH_PCIE_LTRECH_CID);
> +  if (LtrCapOffset == 0) {
> +    return;
> +  }
> +  Data16 = (UINT16)((Ltr.MaxSnoopLatencyValue <<
> N_PCH_PCIE_LTRECH_MSLR_VALUE) | (Ltr.MaxSnoopLatencyScale <<
> N_PCH_PCIE_LTRECH_MSLR_SCALE));
> +  PciSegmentWrite16(Base + LtrCapOffset +
> R_PCH_PCIE_LTRECH_MSLR_OFFSET, Data16);
> +
> +  Data16 = (UINT16)((Ltr.MaxNoSnoopLatencyValue <<
> N_PCH_PCIE_LTRECH_MNSLR_VALUE) | (Ltr.MaxNoSnoopLatencyScale <<
> N_PCH_PCIE_LTRECH_MNSLR_SCALE));
> +  PciSegmentWrite16(Base + LtrCapOffset +
> R_PCH_PCIE_LTRECH_MNSLR_OFFSET, Data16);
> +}
> +
> +/**
> +  Checks if device at given address exists and is a PCI Express device.
> +  PCI express devices are distinguished from PCI by having Capability ID 0x10
> +  If the device is PCI express then its SDBF structure gets updated with pointer
> to
> +  the PCIe Capability. This is an optimization feature. It greatly decreases the
> number
> +  of bus accesses, since most features configured by this library depend on
> registers
> +  whose location is relative to PCIe capability.
> +
> +  @param[in,out] Sbdf   on entry, segment:bus:device:function coordinates
> +                        on exit, PcieCap offset is updated
> +  @retval               TRUE when PCIe device exists; FALSE if it's not PCIe or
> there's no device at all
> +**/
> +STATIC
> +BOOLEAN
> +IsPcieDevice (
> +  SBDF *Sbdf
> +  )
> +{
> +  UINT8 PcieCapOffset;
> +  UINT64 Base;
> +
> +  Base = SbdfToBase (*Sbdf);
> +
> +  if (PciSegmentRead16 (Base) == 0xFFFF) {
> +    return FALSE;
> +  }
> +
> +
> +  PcieCapOffset = PcieBaseFindCapId (Base, EFI_PCI_CAPABILITY_ID_PCIEXP);
> +  if (PcieCapOffset == 0) {
> +    DEBUG ((DEBUG_INFO, "IsPcieDevice %02x:%02x:%02x - legacy\n",
> Sbdf->Bus, Sbdf->Dev, Sbdf->Func));
> +    return FALSE;
> +  } else {
> +    Sbdf->PcieCap = PcieCapOffset;
> +    DEBUG ((DEBUG_INFO, "IsPcieDevice %02x:%02x:%02x - yes\n", Sbdf->Bus,
> Sbdf->Dev, Sbdf->Func));
> +    return TRUE;
> +  }
> +}
> +
> +/**
> +  Returns TRUE and Dev:Func numbers where a PCIe device could legally be
> located, or FALSE if there
> +  no such coordinates left.
> +
> +  Segment and Bus fields of SBDF structure are input only and determine
> which bus will be scanned.
> +  This function should be called in a while() loop. It replaces the less efficient
> method of
> +  using nested FOR loops that iterate over all device and function numbers. It
> is optimized for
> +  the amount of bus access. If function0 doesn't exist or doesn't have
> Multifunction bit set,
> +  then higher function numbers are skipped. If parent of this bus is a
> downstream port, then
> +  Device numbers 1-31 get skipped too (there can be only Dev0 behind
> downstream ports)
> +  If device/function number == 0x1F/0x7, this function returns first possible
> address, that is 0:0
> +  Any other device number means Dev:Func contain address of last found
> child device
> +  and this function should search for next one
> +
> +  @param[in]     ParentDevType  type of bridge who's partent of this bus
> +  @param[in,out] Sbdf           On entry: location returned previously from
> this function
> +                                          Dev:Func value of 1F:07 means search should
> start from the beginning
> +                                On exit:  if legal Dev:Func combination was found,
> that Dev:Func is returned
> +                                          otherwise, Dev:Func are initialized to 1F:07 for
> convenience
> +  @retval TRUE when next legal Dev:Func address was found; FALSE otherwise
> +**/
> +STATIC
> +BOOLEAN
> +FindNextLegalSbdf (
> +  IN     PCI_DEV_TYPE ParentDevType,
> +  IN OUT SBDF         *Sbdf
> +  )
> +{
> +  UINT8  MaxDev;
> +  UINT64 Func0Base;
> +
> +  if (ParentDevType == DevTypePcieEndpoint) {
> +    return FALSE;
> +  }
> +  if (ParentDevType == DevTypePcieUpstream) {
> +    MaxDev = PCI_MAX_DEVICE;
> +  } else {
> +    MaxDev = 0;
> +  }
> +  Func0Base = PCI_SEGMENT_LIB_ADDRESS (Sbdf->Seg, Sbdf->Bus, Sbdf->Dev,
> 0, 0);
> +  if ((Sbdf->Dev == PCI_MAX_DEVICE) && Sbdf->Func == PCI_MAX_FUNC) {
> +    Sbdf->Dev = 0;
> +    Sbdf->Func = 0;
> +    return TRUE;
> +  } else if ((Sbdf->Func == PCI_MAX_FUNC) || (Sbdf->Func == 0
> && !IsMultifunctionDevice (Func0Base))) {
> +  //
> +  // if it's the last function of a device, then return Func0 of new device or
> FALSE in case there are no more devices
> +  //
> +    if (Sbdf->Dev == MaxDev) {
> +      InitChildFinder (Sbdf);
> +      return FALSE;
> +    }
> +    (Sbdf->Dev)++;
> +    Sbdf->Func = 0;
> +    return TRUE;
> +  } else {
> +    (Sbdf->Func)++;
> +    return TRUE;
> +  }
> +}
> +
> +/**
> +  Finds next PCIe (not legacy PCI) device behind given device
> +  If device/function number == 0x1F/0x7, this function searches for children
> from scratch
> +  Any other device number means Dev:Func contain address of last found
> child device
> +  and this function should search for next one
> +
> +  @param[in]     ParentDevType  type of bridge who's partent of this bus
> +  @param[in,out] Sbdf           On entry: location returned previously from
> this function
> +                                          Dev:Func value of 0x1F:0x07 means search
> should start from the beginning
> +                                On exit:  if PCIe device was found, its SBDF
> coordinates are returned
> +                                          otherwise, Dev:Func are initialized to
> 0x1F:0x07 for convenience
> +  @retval TRUE when next PCIe device was found; FALSE otherwise
> +**/
> +STATIC
> +BOOLEAN
> +FindNextPcieChild (
> +  IN     PCI_DEV_TYPE ParentDevType,
> +  IN OUT SBDF   *Sbdf
> +  )
> +{
> +  while ( FindNextLegalSbdf (ParentDevType, Sbdf)) {
> +    if (IsPcieDevice (Sbdf)) {
> +      return TRUE;
> +    }
> +  }
> +  return FALSE;
> +}
> +
> +/**
> +  Checks device's Slot Clock Configuration
> +
> +  @param[in] Base            device's base address
> +
> +  @retval TRUE when device uses slot clock, FALSE otherwise
> +**/
> +BOOLEAN
> +GetScc (
> +  UINT64    Base,
> +  UINT8     PcieCapOffset
> +  )
> +{
> +  return !!(PciSegmentRead16 (Base + PcieCapOffset + R_PCIE_LSTS_OFFSET)
> & B_PCIE_LSTS_SCC);
> +}
> +
> +/**
> +  Sets Common Clock Configuration bit for given device.
> +
> +  @param[in] Base            device's base address
> +**/
> +VOID
> +EnableCcc (
> +  UINT64    Base,
> +  UINT8     PcieCapOffset
> +  )
> +{
> +  PciSegmentOr8 (Base + PcieCapOffset + R_PCIE_LCTL_OFFSET,
> B_PCIE_LCTL_CCC);
> +}
> +
> +/**
> +  Retrains link behind given device.
> +  It only makes sense to call it for downstream ports. If called for upstream
> port nothing will happen.
> +  If WaitUntilDone is TRUE function will wait until link retrain had finished,
> otherwise it will return immediately.
> +  Link must finish retrain before software can access the device on the other
> side. If it's not going to access it
> +  then considerable time can be saved by not waiting here.
> +
> +  @param[in] Sbdf           Device's Segment:Bus:Device:Function
> coordinates
> +  @param[in] WaitUntilDone  when TRUE, function waits until link has
> retrained
> +**/
> +VOID
> +RetrainLink (
> +  UINT64  Base,
> +  UINT8   PcieCapOffset,
> +  BOOLEAN WaitUntilDone
> +  )
> +{
> +  UINT16 LinkTraining;
> +  UINT32 TimeoutUs;
> +
> +  TimeoutUs = LINK_RETRAIN_WAIT_TIME;
> +  //
> +  // Before triggering link retrain make sure it's not already retraining.
> Otherwise
> +  // settings recently entered in LCTL register might go unnoticed
> +  //
> +  do {
> +    LinkTraining = (PciSegmentRead16 (Base + PcieCapOffset +
> R_PCIE_LSTS_OFFSET) & B_PCIE_LSTS_LT);
> +    TimeoutUs--;
> +  } while (LinkTraining && (TimeoutUs != 0));
> +
> +  PciSegmentOr8 (Base + PcieCapOffset + R_PCIE_LCTL_OFFSET,
> B_PCIE_LCTL_RL);
> +
> +  TimeoutUs = LINK_RETRAIN_WAIT_TIME;
> +  if (WaitUntilDone) {
> +    do {
> +      LinkTraining = (PciSegmentRead16 (Base + PcieCapOffset +
> R_PCIE_LSTS_OFFSET) & B_PCIE_LSTS_LT);
> +      TimeoutUs--;
> +    } while (LinkTraining && (TimeoutUs != 0));
> +  }
> +}
> +
> +/**
> +  Checks if given device supports Clock Power Management
> +
> +  @param[in] Sbdf     segment:bus:device:function coordinates of a device
> +
> +  @retval TRUE when device supports it, FALSE otherwise
> +**/
> +STATIC
> +BOOLEAN
> +IsCpmSupported (
> +  SBDF Sbdf
> +  )
> +{
> +  return !!(PciSegmentRead32 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_LCAP_OFFSET) & B_PCIE_LCAP_CPM);
> +}
> +
> +/**
> +  Sets Enable Clock Power Management bit for given device
> +
> +  @param[in] Base            device's base address
> +**/
> +STATIC
> +VOID
> +EnableCpm (
> +  SBDF Sbdf
> +  )
> +{
> +  PciSegmentOr16 (SbdfToBase (Sbdf) + Sbdf.PcieCap + R_PCIE_LCTL_OFFSET,
> B_PCIE_LCTL_ECPM);
> +}
> +
> +/**
> +  Checks if given device is an IoAPIC
> +
> +  @param[in] Base            device's base address
> +
> +  @retval TRUE if it's an IoAPIC
> +**/
> +BOOLEAN
> +IsIoApicDevice (
> +  UINT64 Base
> +  )
> +{
> +  UINT8 BaseClassCode;
> +  UINT8 SubClassCode;
> +  UINT8 ProgInterface;
> +
> +  BaseClassCode = PciSegmentRead8 (Base + PCI_CLASSCODE_OFFSET + 2);
> +  SubClassCode  = PciSegmentRead8 (Base + PCI_CLASSCODE_OFFSET + 1);
> +  ProgInterface = PciSegmentRead8 (Base + PCI_CLASSCODE_OFFSET);
> +  if ((BaseClassCode == PCI_CLASS_SYSTEM_PERIPHERAL) &&
> +      (SubClassCode == PCI_SUBCLASS_PIC) &&
> +      ((ProgInterface == PCI_IF_APIC_CONTROLLER) ||
> +       (ProgInterface == PCI_IF_APIC_CONTROLLER2))) {
> +    return TRUE;
> +  }
> +  return FALSE;
> +}
> +
> +/**
> +  There are some devices which support L1 substates, but due to silicon bugs
> the corresponding register
> +  cannot be found by scanning PCIe capabilities. This function checks list of
> such devices and if one
> +  is found, returns its L1ss capability register offset
> +
> +  @param[in] Base       base address of device
> +  @param[in] Override   table of devices that need override
> +  @retval               offset to L1ss capability register
> +**/
> +UINT16
> +GetOverrideL1ssCapsOffset (
> +  UINT64         Base,
> +  OVERRIDE_TABLE *Override
> +  )
> +{
> +  UINT16 DeviceId;
> +  UINT16 VendorId;
> +  UINT8  Revision;
> +  UINT32 Index;
> +
> +  VendorId = PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);
> +  DeviceId = PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);
> +  Revision = PciSegmentRead8  (Base + PCI_REVISION_ID_OFFSET);
> +
> +  for (Index = 0; Index < Override->Size; Index++) {
> +    if (((Override->Table[Index].OverrideConfig & PchPcieL1SubstatesOverride)
> == PchPcieL1SubstatesOverride) &&
> +        (Override->Table[Index].VendorId == VendorId) &&
> +        (Override->Table[Index].DeviceId == DeviceId) &&
> +        (Override->Table[Index].RevId == Revision ||
> Override->Table[Index].RevId == 0xFF)) {
> +      return Override->Table[Index].L1SubstatesCapOffset;
> +    }
> +  }
> +  return 0;
> +}
> +
> +/**
> +  There are some devices whose implementation of L1 substates is partially
> broken. This function checks
> +  list of such devices and if one is found, overrides their L1ss-related
> capabilities
> +
> +  @param[in]     Base       base address of device
> +  @param[in]     Override   table of devices that need override
> +  @param[in,out] L1ss       on entry, capabilities read from register; on exit,
> capabilities modified according ot override table
> +**/
> +STATIC
> +VOID
> +OverrideL1ssCaps (
> +  UINT64         Base,
> +  OVERRIDE_TABLE *Override,
> +  L1SS_CAPS      *L1ss
> +  )
> +{
> +  UINT16 DeviceId;
> +  UINT16 VendorId;
> +  UINT8  Revision;
> +  UINT32 Index;
> +
> +  VendorId = PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);
> +  DeviceId = PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);
> +  Revision = PciSegmentRead8  (Base + PCI_REVISION_ID_OFFSET);
> +
> +  for (Index = 0; Index < Override->Size; Index++) {
> +    if (((Override->Table[Index].OverrideConfig & PchPcieL1SubstatesOverride)
> == PchPcieL1SubstatesOverride) &&
> +        (Override->Table[Index].VendorId == VendorId) &&
> +        (Override->Table[Index].DeviceId == DeviceId) &&
> +        (Override->Table[Index].RevId == Revision ||
> Override->Table[Index].RevId == 0xFF)) {
> +      L1ss->PmL12   &= !!(Override->Table[Index].L1SubstatesCapMask &
> B_PCIE_EX_L1SCAP_PPL12S);
> +      L1ss->PmL11   &= !!(Override->Table[Index].L1SubstatesCapMask &
> B_PCIE_EX_L1SCAP_PPL11S);
> +      L1ss->AspmL12 &= !!(Override->Table[Index].L1SubstatesCapMask &
> B_PCIE_EX_L1SCAP_AL12S);
> +      L1ss->AspmL11 &= !!(Override->Table[Index].L1SubstatesCapMask &
> B_PCIE_EX_L1SCAP_AL1SS);
> +      if (Override->Table[Index].L1sTpowerOnValue != 0) {
> +        L1ss->Cmrt = Override->Table[Index].L1sCommonModeRestoreTime;
> +        L1ss->TpoScale = Override->Table[Index].L1sTpowerOnScale;
> +        L1ss->TpoValue = Override->Table[Index].L1sTpowerOnValue;
> +      }
> +      return;
> +    }
> +  }
> +}
> +
> +/**
> +  Returns L1 sub states capabilities of a device
> +
> +  @param[in] Base   base address of a device
> +
> +  @retval L1SS_CAPS structure filled with device's capabilities
> +**/
> +STATIC
> +L1SS_CAPS
> +GetL1ssCaps (
> +  UINT64         Base,
> +  OVERRIDE_TABLE *Override
> +  )
> +{
> +  L1SS_CAPS Capabilities = {0};
> +  UINT16    PcieCapOffset;
> +  UINT32    CapsRegister;
> +
> +  PcieCapOffset = GetOverrideL1ssCapsOffset (Base, Override);
> +  if (PcieCapOffset == 0) {
> +    PcieCapOffset = PcieBaseFindExtendedCapId (Base, V_PCIE_EX_L1S_CID);
> +  }
> +  if (PcieCapOffset == 0) {
> +    return Capabilities;
> +  }
> +  CapsRegister = PciSegmentRead32 (Base + PcieCapOffset +
> R_PCIE_EX_L1SCAP_OFFSET);
> +  if (CapsRegister & B_PCIE_EX_L1SCAP_L1PSS) {
> +    Capabilities.PmL11 = !!(CapsRegister & B_PCIE_EX_L1SCAP_PPL11S);
> +    Capabilities.PmL12 = !!(CapsRegister & B_PCIE_EX_L1SCAP_PPL12S);
> +    Capabilities.AspmL12 = !!(CapsRegister & B_PCIE_EX_L1SCAP_AL12S);
> +    Capabilities.AspmL11 = !!(CapsRegister & B_PCIE_EX_L1SCAP_AL1SS);
> +    Capabilities.Cmrt = (CapsRegister & B_PCIE_EX_L1SCAP_CMRT) >>
> N_PCIE_EX_L1SCAP_CMRT;
> +    Capabilities.TpoValue = (CapsRegister & B_PCIE_EX_L1SCAP_PTV) >>
> N_PCIE_EX_L1SCAP_PTV;
> +    Capabilities.TpoScale = (CapsRegister & B_PCIE_EX_L1SCAP_PTPOS) >>
> N_PCIE_EX_L1SCAP_PTPOS;
> +  }
> +  OverrideL1ssCaps (Base, Override, &Capabilities);
> +  return Capabilities;
> +}
> +
> +/**
> +  Returns combination of two sets of L1 substate capabilities
> +  Given feature is supported by the link only if both sides support it
> +  Time parameters for link (Cmrt and Tpo) depend on the bigger value
> between two sides
> +
> +  @param[in] L1ssA      L1 substate capabilities of first device
> +  @param[in] L1ssB      L1 substate capabilities of second device
> +
> +  @retval Link's L1 substate capabilities
> +**/
> +STATIC
> +L1SS_CAPS
> +CombineL1ss (
> +  L1SS_CAPS L1ssA,
> +  L1SS_CAPS L1ssB
> +  )
> +{
> +  L1SS_CAPS Combined;
> +
> +  Combined.PmL12 = L1ssA.PmL12 && L1ssB.PmL12;
> +  Combined.PmL11 = L1ssA.PmL11 && L1ssB.PmL11;
> +  Combined.AspmL12 = L1ssA.AspmL12 && L1ssB.AspmL12;
> +  Combined.AspmL11 = L1ssA.AspmL11 && L1ssB.AspmL11;
> +  Combined.Cmrt = MAX (L1ssA.Cmrt, L1ssB.Cmrt);
> +  if (TpoToUs (L1ssA.TpoScale, L1ssA.TpoValue) > TpoToUs (L1ssB.TpoScale,
> L1ssB.TpoValue)) {
> +    Combined.TpoScale = L1ssA.TpoScale;
> +    Combined.TpoValue = L1ssA.TpoValue;
> +  } else {
> +    Combined.TpoScale = L1ssB.TpoScale;
> +    Combined.TpoValue = L1ssB.TpoValue;
> +  }
> +  return Combined;
> +}
> +
> +/**
> +  Configures L1 substate feature in a device
> +
> +  @param[in] Sbdf     segment:bus:device:function coordinates of a device
> +  @param[in] L1ss     configuration to be programmed
> +  @param[in] Override table of devices that require special handling
> +**/
> +STATIC
> +VOID
> +SetL1ss (
> +  SBDF           Sbdf,
> +  L1SS_CAPS      L1ss,
> +  OVERRIDE_TABLE *Override
> +  )
> +{
> +  UINT16    PcieCapOffset;
> +  UINT32    Ctrl1Register;
> +  UINT32    Ctrl2Register;
> +  UINT64    Base;
> +
> +  Base = SbdfToBase(Sbdf);
> +  Ctrl1Register = 0;
> +  Ctrl2Register = 0;
> +
> +  PcieCapOffset = GetOverrideL1ssCapsOffset (Base, Override);
> +  if (PcieCapOffset == 0) {
> +    PcieCapOffset = PcieBaseFindExtendedCapId (Base, V_PCIE_EX_L1S_CID);
> +  }
> +  if (PcieCapOffset == 0) {
> +    return;
> +  }
> +  Ctrl1Register |= (L1ss.PmL12 ? B_PCIE_EX_L1SCAP_PPL12S : 0);
> +  Ctrl1Register |= (L1ss.PmL11 ? B_PCIE_EX_L1SCAP_PPL11S : 0);
> +  Ctrl1Register |= (L1ss.AspmL12 ? B_PCIE_EX_L1SCAP_AL12S : 0);
> +  Ctrl1Register |= (L1ss.AspmL11 ? B_PCIE_EX_L1SCAP_AL1SS : 0);
> +  if (GetDeviceType (Sbdf) == DevTypePcieDownstream) {
> +    Ctrl1Register |= (L1ss.Cmrt << N_PCIE_EX_L1SCAP_CMRT);
> +  }
> +  ///
> +  ///  Set L1.2 LTR threshold to 80us (value = 0x50, scale = 0x2 = 1024ns), in
> accordance to BWG
> +  ///  BUG BUG BUG  It shouldn't be hardcoded, it should consider Tpoweron,
> otherwise we risk situation where
> +  ///  BUG BUG BUG  threshold is lower than Tpo, and every L1 entry turns
> into L1.2 entry with no possibility
> +  ///  BUG BUG BUG  to exit before LTR elapses, because exit can take no less
> than Tpo
> +  ///
> +  Ctrl1Register |= (0x50 << N_PCIE_EX_L1SCTL1_L12LTRTLV);
> +  Ctrl1Register |= (2 << N_PCIE_EX_L1SCTL1_L12LTRTLSV);
> +
> +  Ctrl2Register |= (L1ss.TpoScale);
> +  Ctrl2Register |= (L1ss.TpoValue << N_PCIE_EX_L1SCTL2_POWT);
> +
> +  PciSegmentWrite32 (Base + PcieCapOffset + R_PCIE_EX_L1SCTL1_OFFSET, 0);
> +  PciSegmentWrite32 (Base + PcieCapOffset + R_PCIE_EX_L1SCTL2_OFFSET,
> Ctrl2Register);
> +  PciSegmentWrite32 (Base + PcieCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
> Ctrl1Register);
> +}
> +
> +/**
> +  Converts L1 latency from enumerated register value to microseconds
> +
> +  @param[in] L1Latency     latency value retrieved from register; see PCIE
> specification for encoding
> +  @retval    L1 latency converted to microseconds
> +**/
> +UINT32
> +L1LatencyToUs (
> +  UINT32 L1Latency
> +  )
> +{
> +  if (L1Latency < 7) {
> +    return 1 * (BIT0 << L1Latency);
> +  } else {
> +    return ASPM_L1_NO_LIMIT;
> +  }
> +}
> +
> +/**
> +  Modifies L1 latency by provided value
> +
> +  @param[in] Aspm     Structure that contains ASPM capabilities of a link,
> including L1 acceptable latency
> +  @param[in] Value    Value, in microseconds, to be added to L1 acceptable
> latency. Can be negative.
> +  @retval             Aspm structure with modified L1 acceptable latency
> +**/
> +STATIC
> +ASPM_CAPS
> +PatchL1AcceptableLatency (
> +  ASPM_CAPS Aspm,
> +  INT8      Value
> +  )
> +{
> +  if (Aspm.L1AcceptableLatencyUs != ASPM_L1_NO_LIMIT) {
> +    if (Value > 0) {
> +      Aspm.L1AcceptableLatencyUs += Value;
> +    } else {
> +      if (Aspm.L1AcceptableLatencyUs > (UINT32)(-1*Value)) {
> +        Aspm.L1AcceptableLatencyUs = Aspm.L1AcceptableLatencyUs + Value;
> +      } else {
> +        Aspm.L1AcceptableLatencyUs = 0;
> +      }
> +    }
> +  }
> +  return Aspm;
> +}
> +
> +/**
> +  Reads ASPM capabilities of a device
> +
> +  @param[in] Sbdf segment:bus:device:function coordinates of a device
> +
> +@retval           structure containing device's ASPM capabilities
> +**/
> +STATIC
> +ASPM_CAPS
> +GetAspmCaps (
> +  SBDF   Sbdf
> +  )
> +{
> +
> +  UINT32    LinkCapRegister;
> +  UINT32    DevCapRegister;
> +  UINT64    Base;
> +  ASPM_CAPS Aspm = {0};
> +
> +  Base = SbdfToBase (Sbdf);
> +
> +  LinkCapRegister = PciSegmentRead32 (Base + Sbdf.PcieCap +
> R_PCIE_LCAP_OFFSET);
> +  DevCapRegister = PciSegmentRead32 (Base + Sbdf.PcieCap +
> R_PCIE_DCAP_OFFSET);
> +
> +  ///
> +  /// Check endpoint for pre-1.1 devices based on the Role based Error
> Reporting Capability bit. Don't report L0s support for old devices
> +  ///
> +  if (DevCapRegister & B_PCIE_DCAP_RBER) {
> +    Aspm.L0sSupported = !!(LinkCapRegister & B_PCIE_LCAP_APMS_L0S);
> +  }
> +  Aspm.L1Supported = !!(LinkCapRegister & B_PCIE_LCAP_APMS_L1);
> +
> +  Aspm.LinkL0sExitLatency = (LinkCapRegister & B_PCIE_LCAP_EL0) >>
> N_PCIE_LCAP_EL0;
> +  Aspm.LinkL1ExitLatencyUs = L1LatencyToUs( (LinkCapRegister &
> B_PCIE_LCAP_EL1) >> N_PCIE_LCAP_EL1);
> +
> +  if (GetDeviceType (Sbdf) == DevTypePcieEndpoint) {
> +    Aspm.L0sAcceptableLatency = (DevCapRegister & B_PCIE_DCAP_E0AL) >>
> N_PCIE_DCAP_E0AL;
> +    Aspm.L1AcceptableLatencyUs = L1LatencyToUs( (DevCapRegister &
> B_PCIE_DCAP_E1AL) >> N_PCIE_DCAP_E1AL);
> +    DEBUG ((DEBUG_INFO, "GetAspmCaps %02x:%02x:%02x L0s%c %d:%d
> L1%c %d:%d\n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func,
> +
> Aspm.L0sSupported?'+':'-', Aspm.LinkL0sExitLatency,
> Aspm.L0sAcceptableLatency,
> +
> Aspm.L1Supported?'+':'-', Aspm.LinkL1ExitLatencyUs,
> Aspm.L1AcceptableLatencyUs));
> +  } else {
> +    Aspm.L0sAcceptableLatency = ASPM_L0s_NO_LIMIT;
> +    Aspm.L1AcceptableLatencyUs = ASPM_L1_NO_LIMIT;
> +    DEBUG ((DEBUG_INFO, "GetAspmCaps %02x:%02x:%02x L0s%c %d:x L1%c
> %d:x\n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func,
> +
> Aspm.L0sSupported?'+':'-', Aspm.LinkL0sExitLatency,
> +
> Aspm.L1Supported?'+':'-', Aspm.LinkL1ExitLatencyUs));
> +  }
> +  return Aspm;
> +}
> +
> +/**
> +  Get ASPM L0s and L1 override of given device.
> +
> +  @param[in] Sbdf                Segment,Bus,Device,Function address of
> currently visited PCIe device
> +  @param[in,out] MyAspm          Current device's ASPM capabilities
> structure
> +  @param[in] Override            Pch Pcie devices OverrideTable
> +**/
> +STATIC
> +VOID
> +GetOverrideAspm (
> +  SBDF           Sbdf,
> +  ASPM_CAPS      *MyAspm,
> +  OVERRIDE_TABLE *Override
> +  )
> +{
> +  UINT16      DeviceId;
> +  UINT16      VendorId;
> +  UINT8       Revision;
> +  UINT32      Index;
> +  UINT64      Base;
> +
> +  Base = SbdfToBase (Sbdf);
> +
> +  VendorId = PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);
> +  DeviceId = PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);
> +  Revision = PciSegmentRead8  (Base + PCI_REVISION_ID_OFFSET);
> +
> +  for (Index = 0; Index < Override->Size; Index++) {
> +    if (((Override->Table[Index].OverrideConfig & PchPcieL1L2Override) ==
> PchPcieL1L2Override) &&
> +        (Override->Table[Index].VendorId == VendorId) &&
> +        (Override->Table[Index].DeviceId == DeviceId) &&
> +        (Override->Table[Index].RevId == Revision ||
> Override->Table[Index].RevId == 0xFF)) {
> +      DEBUG ((DEBUG_INFO, "GetOverrideAspm %02x:%02x:%02x, original
> L0sSupported = 0x%x, L1Supported = 0x%x\n",
> +              Sbdf.Bus, Sbdf.Dev, Sbdf.Func, MyAspm->L0sSupported,
> MyAspm->L1Supported));
> +      if (MyAspm->L0sSupported) {
> +        //
> +        // If L0s is supported in capability, apply platform override.
> +        //
> +        MyAspm->L0sSupported = Override->Table[Index].EndPointAspm &
> BIT0;
> +      }
> +      if (MyAspm->L1Supported) {
> +        //
> +        // If L1 is supported in capability, apply platform override.
> +        //
> +        MyAspm->L1Supported = (Override->Table[Index].EndPointAspm &
> BIT1) >> 1;
> +      }
> +      DEBUG ((DEBUG_INFO, "GetOverrideAspm %02x:%02x:%02x, override
> L0sSupported = 0x%x, L1Supported = 0x%x\n",
> +              Sbdf.Bus, Sbdf.Dev, Sbdf.Func, MyAspm->L0sSupported,
> MyAspm->L1Supported));
> +    }
> +  }
> +}
> +
> +/**
> +  Combines ASPM capabilities of two devices on both ends of a link to
> determine link's ASPM capabilities
> +
> +  @param[in] AspmA, AspmB  ASPM capabilities of two devices
> +
> +@retval    ASPM_CAPS structure containing combined ASPM capabilities
> +**/
> +STATIC
> +ASPM_CAPS
> +CombineAspm (
> +  ASPM_CAPS AspmA,
> +  ASPM_CAPS AspmB,
> +  BOOLEAN   DownstreamPort
> +  )
> +{
> +  ASPM_CAPS Combined;
> +
> +  if (DownstreamPort) {
> +    //
> +    // When combining ASPM in downstream ports, combination must reflect
> state of link just below
> +    // and consider all acceptable latencies of all endpoints anywhere down
> below that port
> +    //
> +    Combined.L0sSupported = AspmA.L0sSupported & AspmB.L0sSupported;
> +    Combined.L1Supported = AspmA.L1Supported & AspmB.L1Supported;
> +    Combined.LinkL0sExitLatency = MAX (AspmA.LinkL0sExitLatency,
> AspmB.LinkL0sExitLatency);
> +    Combined.LinkL1ExitLatencyUs = MAX (AspmA.LinkL1ExitLatencyUs,
> AspmB.LinkL1ExitLatencyUs);
> +    Combined.L0sAcceptableLatency = MIN (AspmA.L0sAcceptableLatency,
> AspmB.L0sAcceptableLatency);
> +    Combined.L1AcceptableLatencyUs = MIN (AspmA.L1AcceptableLatencyUs,
> AspmB.L1AcceptableLatencyUs);
> +  } else {
> +    //
> +    // When combining ASPM in switch upstream ports,
> +    // Supported and ExitLatency must only reflect capabilities of upstream
> port itself
> +    // But acceptable latencies must consider all endpoints anywhere below
> +    //
> +    Combined.L0sSupported = AspmA.L0sSupported;
> +    Combined.L1Supported = AspmA.L1Supported;
> +    Combined.LinkL0sExitLatency = AspmA.LinkL0sExitLatency;
> +    Combined.LinkL1ExitLatencyUs = AspmA.LinkL1ExitLatencyUs;
> +    Combined.L0sAcceptableLatency = MIN (AspmA.L0sAcceptableLatency,
> AspmB.L0sAcceptableLatency);
> +    Combined.L1AcceptableLatencyUs = MIN (AspmA.L1AcceptableLatencyUs,
> AspmB.L1AcceptableLatencyUs);
> +  }
> +  DEBUG ((DEBUG_INFO, "CombineAspm %x:%x -> %x\n",
> AspmA.L1AcceptableLatencyUs, AspmB.L1AcceptableLatencyUs,
> Combined.L1AcceptableLatencyUs));
> +  return Combined;
> +}
> +
> +/**
> +  Checks if L1 can be enabled on given link, according to ASPM parameters of
> that link
> +
> +  @param[in] Aspm            set of parameters describing this link and
> endpoint devices below it
> +  @retval    TRUE if L1 can be enabled
> +**/
> +STATIC
> +BOOLEAN
> +IsL1Allowed (
> +  ASPM_CAPS Aspm
> +  )
> +{
> +  return (Aspm.L1Supported && (Aspm.L1AcceptableLatencyUs >=
> Aspm.LinkL1ExitLatencyUs));
> +}
> +
> +/**
> +  Checks if L0s can be enabled on given link, according to ASPM parameters of
> that link
> +
> +  @param[in] Aspm            set of parameters describing this link and
> endpoint devices below it
> +  @retval    TRUE if L0s can be enabled
> +**/
> +STATIC
> +BOOLEAN
> +IsL0sAllowed (
> +  ASPM_CAPS Aspm
> +  )
> +{
> +  return (Aspm.L0sSupported && (Aspm.L0sAcceptableLatency >=
> Aspm.LinkL0sExitLatency));
> +}
> +
> +/**
> +  Enables L0s and L1 for given port, if possible.
> +  L0s/L1 can be enabled if it's supported on both sides of a link and if link's
> latency doesn't exceed
> +  acceptable latency of any endpoint below this link
> +
> +  @param[in] Base            device's base address
> +  @param[in] Aspm            set of parameters describing this link and
> endpoint devices below it
> +**/
> +STATIC
> +VOID
> +SetAspm (
> +  SBDF      Sbdf,
> +  ASPM_CAPS Aspm
> +  )
> +{
> +  UINT16 DataOr;
> +
> +  DataOr = 0;
> +  if (IsL0sAllowed (Aspm)) {
> +    DataOr |= V_PCIE_LCTL_ASPM_L0S;
> +  }
> +  if (IsL1Allowed (Aspm)) {
> +    DataOr |= V_PCIE_LCTL_ASPM_L1;
> +  }
> +  DEBUG ((DEBUG_INFO, "SetAspm on %02x:%02x:%02x to %d\n",
> Sbdf.Bus,Sbdf.Dev,Sbdf.Func, DataOr));
> +  PciSegmentAndThenOr16 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_LCTL_OFFSET, (UINT16)~B_PCIE_LCTL_ASPM, DataOr);
> +}
> +
> +/**
> +  Adds device entry to a list of devices.
> +
> +  @param[in,out] Table    array of devices
> +  @param[in]     Sbdf     segment:bus:device:function coordinates of device
> to be added to table
> +**/
> +STATIC
> +VOID
> +AddToDeviceTable (
> +  SBDF_TABLE *Table,
> +  SBDF       Sbdf
> +  )
> +{
> +  if (Table->Count < MAX_SBDF_TABLE_SIZE) {
> +    Table->Entry[Table->Count++] = Sbdf;
> +  } else {
> +    ASSERT (FALSE);
> +  }
> +}
> +
> +/**
> +  Remove device entry from a list and clear its bus assignment
> +
> +  @param[in,out] Table    array of devices
> +**/
> +STATIC
> +VOID
> +ClearBusFromTable (
> +  SBDF_TABLE *Table
> +  )
> +{
> +  while (Table->Count > 0) {
> +    PciSegmentWrite32 (SbdfToBase (Table->Entry[Table->Count - 1]) +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0);
> +    Table->Count--;
> +  }
> +}
> +
> +/**
> +  Attempts to assign secondary and subordinate bus numbers to uninitialized
> bridges in PCIe tree
> +  If the device is a bridge and already has bus numbers assigned, they won't
> be changed
> +  Otherwise new bus number will be assigned below this bridge.
> +  This function can be called from SMM, where BIOS must not modify bus
> numbers to prevent
> +  conflict with OS enumerator. To prevent this, this function returns list of
> bridges whose
> +  bus numbers were changed. All devices from that list must have buses
> cleared afterwards.
> +
> +  @param[in] Sbdf                segment:bus:device:function coordinates of
> device to be added to table
> +  @param[in] MinBus              minimum Bus number that can be assigned
> below this port
> +  @param[in] MaxBus              maximum Bus number that can be assigned
> below this port
> +  @param[in] BridgeCleanupList   list of bridges where bus numbers were
> modified
> +
> +  @retval    maximum bus number assigned anywhere below this device
> +**/
> +STATIC
> +UINT8
> +RecursiveBusAssignment (
> +  SBDF       Sbdf,
> +  UINT8      MinBus,
> +  UINT8      MaxBus,
> +  SBDF_TABLE *BridgeCleanupList
> +  )
> +{
> +  UINT64  Base;
> +  SBDF    ChildSbdf;
> +  PCI_DEV_TYPE DevType;
> +  UINT32  Data32;
> +  UINT8   BelowBus;
> +  UINT8   SecondaryBus;
> +  UINT8   SubordinateBus;
> +
> +  ChildSbdf.Seg = Sbdf.Seg;
> +  InitChildFinder (&ChildSbdf);
> +  Base = SbdfToBase (Sbdf);
> +
> +  //
> +  // On way down:
> +  //   assign secondary bus, then increase it by one before stepping down;
> temporarily assign max subordinate bus
> +  // On way up:
> +  //   fix subordinate bus assignment to equal max bus number assigned
> anywhere below; return that number
> +  //
> +  DevType = GetDeviceType (Sbdf);
> +  if ((Sbdf.Bus >= MaxBus) || (DevType == DevTypePcieEndpoint) || (DevType
> == DevTypePci)) {
> +    return (UINT8) Sbdf.Bus;
> +  } else  {
> +    Data32 = PciSegmentRead32 (Base +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
> +    SecondaryBus = (UINT8)((Data32 & B_PCI_BRIDGE_BNUM_SCBN) >> 8);
> +    SubordinateBus = (UINT8)((Data32 & B_PCI_BRIDGE_BNUM_SBBN) >> 16);
> +    if (SecondaryBus != 0) {
> +      ChildSbdf.Bus = SecondaryBus;
> +      MinBus = SecondaryBus + 1;
> +      DEBUG ((DEBUG_INFO, "RecursiveBusAssignmentP %x:%x:%x ->
> %x,%x,%x \n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func, Sbdf.Bus, MinBus,
> SubordinateBus));
> +      while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +        BelowBus = RecursiveBusAssignment (ChildSbdf, MinBus,
> SubordinateBus, BridgeCleanupList);
> +        MinBus = BelowBus + 1;
> +      }
> +      return SubordinateBus;
> +    } else {
> +      Data32 = Sbdf.Bus + (MinBus << 8) + (MaxBus << 16);
> +      PciSegmentWrite32(Base +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, Data32);
> +      AddToDeviceTable (BridgeCleanupList, Sbdf);
> +      DEBUG ((DEBUG_INFO, "RecursiveBusAssignmentE %x:%x:%x ->
> %x,%x,%x \n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func, Sbdf.Bus, MinBus, MaxBus));
> +      BelowBus = MinBus;
> +      ChildSbdf.Bus = MinBus;
> +      MinBus++;
> +      while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +        BelowBus = RecursiveBusAssignment (ChildSbdf, MinBus, MaxBus,
> BridgeCleanupList);
> +        MinBus = BelowBus + 1;
> +      }
> +      Data32  &= ~B_PCI_BRIDGE_BNUM_SBBN;
> +      Data32 |= (BelowBus << 16);
> +      PciSegmentWrite32 (Base +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, Data32);
> +      DEBUG ((DEBUG_INFO, "RecursiveBusAssignmentL %x:%x:%x ->
> %x,%x,%x \n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func, Sbdf.Bus, (Data32&0xFF00)>>8,
> BelowBus));
> +      return BelowBus;
> +    }
> +  }
> +}
> +
> +/**
> +  Enables L0s and/or L1 for PCIE links in the hierarchy below
> +  L0s/L1 can be enabled when both sides of a link support it and link latency
> is smaller than acceptable latency
> +  ASPM of a given link is independend from any other link (except 1ms L1
> adjustment, read below), so it's possible to
> +  have a hierarchy when RP link has no ASPM but links below do.
> +
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +  @param[in] Depth                          How many links there are between
> this port and root complex
> +  @param[in] Override                       Pch Pcie devices OverrideTable
> +
> +  @retval structure that describes acceptable latencies of all endpoints below
> plus ASPM parameters of last link
> +**/
> +STATIC
> +ASPM_CAPS
> +RecursiveAspmConfiguration (
> +  SBDF           Sbdf,
> +  UINT8          Depth,
> +  OVERRIDE_TABLE *Override
> +  )
> +{
> +  SBDF         ChildSbdf;
> +  ASPM_CAPS    MyAspm;
> +  ASPM_CAPS    ChildAspm;
> +  PCI_DEV_TYPE DevType;
> +
> +  DEBUG ((DEBUG_INFO, "RecursiveAspmConfiguration %x:%x:%x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> +
> +  //
> +  // On way down:
> +  //   pass number of links traversed; increase it per upstream port visited
> (not endpoint)
> +  // On way up:
> +  //   EndPoint: read Acceptable Latencies; subtract Depth From
> L1AcceptableLat to account for "1us per switch additional delay"
> +  //   Downstreamport: AND L0s/L1 caps; calculate LinkLatency; enable L0s/L1
> if supported and if acceptable latency is bigger than link latency;
> +  //     if L1 not enabled, add back 1us to Acceptable Latency to cancel earlier
> Depth subtraction
> +  //   UpstreamPort: calculate minimum of below Acceptable Latencies;
> return that, with upper link's Latency and L0s/L1 support
> +  //
> +  DevType = GetDeviceType(Sbdf);
> +  if (DevType == DevTypePcieUpstream) {
> +    Depth++;
> +  }
> +  MyAspm = GetAspmCaps (Sbdf);
> +  //
> +  // Get ASPM L0s and L1 override
> +  //
> +  GetOverrideAspm (Sbdf, &MyAspm, Override);
> +  if (DevType == DevTypePcieEndpoint) {
> +    //
> +    // Every switch between endpoint and CPU introduces 1us additional
> latency on L1 exit. This is reflected by
> +    // subtracting 1us per switch from endpoint's acceptable L1 latency.
> +    // In case L1 doesn't get enabled in one of switches, that 1us will be added
> back.
> +    // This calculation is not precise. It ignores that some switches' added
> delay may be shadowed by
> +    // other links' exit latency. But it guarantees that acceptable latency won't
> be exceeded and is simple
> +    // enough to perform in a single iteration without backtracking.
> +    //
> +    return PatchL1AcceptableLatency (MyAspm, (-1 * Depth));
> +  }
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +      ChildAspm = RecursiveAspmConfiguration (ChildSbdf, Depth, Override);
> +      MyAspm = CombineAspm (MyAspm, ChildAspm, (DevType ==
> DevTypePcieDownstream));
> +    }
> +    if (DevType == DevTypePcieDownstream) {
> +      SetAspm (Sbdf, MyAspm);
> +      //
> +      // ASPM config must be consistent across all functions of a device. That's
> why there's while loop.
> +      //
> +      while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +        SetAspm (ChildSbdf, MyAspm);
> +      }
> +      if (!IsL1Allowed (MyAspm)) {
> +        MyAspm = PatchL1AcceptableLatency (MyAspm, 1);
> +      }
> +    }
> +  }
> +  return MyAspm;
> +}
> +
> +/**
> +  Enables L1 substates for PCIE links in the hierarchy below
> +  L1.1 / L1.2 can be enabled if both sides of a link support it.
> +
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +
> +  @retval  structure that describes L1ss capabilities of the device
> +**/
> +STATIC
> +L1SS_CAPS
> +RecursiveL1ssConfiguration (
> +  SBDF           Sbdf,
> +  OVERRIDE_TABLE *Override
> +  )
> +{
> +  UINT64  Base;
> +  SBDF    ChildSbdf;
> +  L1SS_CAPS CombinedCaps;
> +  L1SS_CAPS ChildCaps;
> +  PCI_DEV_TYPE DevType;
> +
> +  DEBUG ((DEBUG_INFO, "RecursiveL1ssConfiguration %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +
> +  Base = SbdfToBase (Sbdf);
> +  //
> +  // On way down:
> +  //   do nothing
> +  // On way up:
> +  //   In downstream ports, combine L1ss capabilities of that port and device
> behind it, then enable L1.1 and/or L1.2 if possible
> +  //   Return L1ss capabilities
> +  //
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> +    DevType = GetDeviceType (Sbdf);
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +      ChildCaps = RecursiveL1ssConfiguration (ChildSbdf, Override);
> +      if (DevType == DevTypePcieDownstream && ChildSbdf.Func == 0) {
> +        CombinedCaps = CombineL1ss (GetL1ssCaps (Base, Override),
> ChildCaps);
> +        SetL1ss (Sbdf, CombinedCaps, Override);
> +        SetL1ss (ChildSbdf, CombinedCaps, Override);
> +      }
> +    }
> +  }
> +  return GetL1ssCaps (Base, Override);
> +}
> +
> +/**
> +  Checks if there is an IoAPIC device in the PCIe hierarchy.
> +  If one is found, this function doesn't check for more and returns
> +
> +  @param[in] BusLimit                       maximum Bus number that can be
> assigned below this port
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +
> +  @retval  TRUE if IoAPIC device was found
> +**/
> +STATIC
> +BOOLEAN
> +RecursiveIoApicCheck (
> +  SBDF       Sbdf
> +  )
> +{
> +  SBDF         ChildSbdf;
> +  UINT8        IoApicPresent;
> +  PCI_DEV_TYPE DevType;
> +
> +  DEBUG ((DEBUG_INFO, "RecursiveIoApicCheck %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +
> +  IoApicPresent = FALSE;
> +
> +  if (IsIoApicDevice (SbdfToBase (Sbdf))) {
> +    DEBUG ((DEBUG_INFO, "IoApicFound @%x:%x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +    return TRUE;
> +  }
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> +    DevType = GetDeviceType (Sbdf);
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +      IoApicPresent = RecursiveIoApicCheck (ChildSbdf);
> +      if (IoApicPresent) {
> +        break;
> +      }
> +    }
> +  }
> +  DEBUG ((DEBUG_INFO, "IoApic status %d @%x:%x:%x:%x\n", IoApicPresent,
> Sbdf.Seg, Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> +  return IoApicPresent;
> +}
> +
> +/**
> +  Calculates Maximum Payload Size supported by PCIe hierarchy.
> +  Starting from a device, it finds the minimum MPS supported by devices
> below it.
> +  There are many valid strategies for setting MPS. This implementation
> chooses
> +  one that is safest, but doesn't guarantee maximum performance:
> +    Find minimum MPS under given rootport, then program that minimum
> value everywhere below that rootport
> +
> +  @param[in] BusLimit                       maximum Bus number that can be
> assigned below this port
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +
> +  @retval  MPS supported by PCIe hierarchy, calculated as MIN(MPS of all
> devices below)
> +**/
> +STATIC
> +UINT8
> +RecursiveMpsCheck (
> +  SBDF       Sbdf
> +  )
> +{
> +  SBDF         ChildSbdf;
> +  UINT8        MyMps;
> +  UINT8        SubtreeMps;
> +  PCI_DEV_TYPE DevType;
> +
> +  DEBUG ((DEBUG_INFO, "RecursiveMpsCheck %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +
> +  MyMps = GetMps (Sbdf);
> +  if (MyMps == 0) {
> +    return MyMps;
> +  }
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> +    DevType = GetDeviceType (Sbdf);
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +      SubtreeMps = RecursiveMpsCheck (ChildSbdf);
> +      MyMps = MIN(MyMps, SubtreeMps);
> +    }
> +  }
> +  return MyMps;
> +}
> +
> +/**
> +  Sets Maximum Payload Size in PCIe hierarchy.
> +  Starting from a device, it programs the same MPS value to it and all devices
> below it.
> +  There are many valid strategies for setting MPS. This implementation
> chooses
> +  one that is safest, but doesn't guarantee maximum performance:
> +    Find minimum MPS under given rootport, then program that minimum
> value everywhere below that rootport
> +
> +  @param[in] BusLimit                       maximum Bus number that can be
> assigned below this port
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +  @param[in] Mps                            Maximum Payload Size to be
> programmed
> +**/
> +STATIC
> +VOID
> +RecursiveMpsConfiguration (
> +  SBDF       Sbdf,
> +  UINT8      Mps
> +  )
> +{
> +  SBDF    ChildSbdf;
> +  PCI_DEV_TYPE DevType;
> +
> +  DEBUG ((DEBUG_INFO, "RecursiveMpsConfiguration %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> +    DevType = GetDeviceType (Sbdf);
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +      RecursiveMpsConfiguration (ChildSbdf, Mps);
> +    }
> +  }
> +  SetMps (Sbdf, Mps);
> +}
> +
> +/**
> +  Sets Enable Clock Power Management bit for devices that support it.
> +  A device supports CPM only if all function of this device report CPM support.
> +  Downstream ports never report CPM capability, so it's only relevant for
> upstream ports.
> +  When this function executes on upstream component, it will check CPM &
> set ECPM of downstream component
> +  When this function executes on downstream component, all devices below
> it are guaranteed to
> +  return CPM=0 so it will do nothing
> +
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +
> +  @retval TRUE = this device supports CPM, FALSE = it doesn't
> +**/
> +STATIC
> +BOOLEAN
> +RecursiveCpmConfiguration (
> +  SBDF       Sbdf
> +  )
> +{
> +  SBDF         ChildSbdf;
> +  BOOLEAN      ChildCpm;
> +  PCI_DEV_TYPE DevType;
> +
> +  DEBUG ((DEBUG_INFO, "RecursiveCpmConfiguration %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +
> +  ChildCpm = FALSE;
> +
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> +    ChildCpm = TRUE;
> +    DevType = GetDeviceType (Sbdf);
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +      ChildCpm &= RecursiveCpmConfiguration (ChildSbdf);
> +    }
> +    if (ChildCpm) {
> +      while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +        EnableCpm (ChildSbdf);
> +      }
> +    }
> +  }
> +  return IsCpmSupported (Sbdf);
> +}
> +
> +/**
> +  Sets Common Clock Configuration bit for devices that share common clock
> across link
> +  Devices on both sides of a PCIE link share common clock if both upstream
> component
> +  and function 0 of downstream component report Slot Clock Configuration
> bit = 1.
> +  When this function executes on upstream component, it checks SCC of both
> sides of the link
> +  If they both support it, sets CCC for both sides (this means all functions of
> downstream component)
> +  When this function executes on downstream component, it only returns
> SCC capability
> +
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +  @param[in] WaitForRetrain                 decides if this function should
> busy-wait for link retrain
> +
> +  @retval TRUE = this device supports SCC, FALSE = it doesn't
> +**/
> +STATIC
> +BOOLEAN
> +RecursiveCccConfiguration (
> +  SBDF       Sbdf,
> +  BOOLEAN    WaitForRetrain
> +  )
> +{
> +  UINT64       Base;
> +  SBDF         ChildSbdf;
> +  BOOLEAN      MyScc;
> +  BOOLEAN      ChildScc;
> +  BOOLEAN      LinkScc;
> +  PCI_DEV_TYPE DevType;
> +
> +  DEBUG ((DEBUG_INFO, "RecursiveCccConfiguration %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +
> +  ChildScc = 0;
> +  Base = SbdfToBase(Sbdf);
> +  MyScc = GetScc (SbdfToBase(Sbdf), (UINT8)Sbdf.PcieCap);
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> +    DevType = GetDeviceType (Sbdf);
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +      ChildScc |= RecursiveCccConfiguration (ChildSbdf, WaitForRetrain);
> +    }
> +    if (DevType == DevTypePcieDownstream) {
> +      LinkScc = MyScc & ChildScc;
> +      if (LinkScc) {
> +        EnableCcc (SbdfToBase(Sbdf), (UINT8)Sbdf.PcieCap);
> +        while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +          EnableCcc (SbdfToBase(ChildSbdf), (UINT8)ChildSbdf.PcieCap);
> +        }
> +        RetrainLink(Base, (UINT8)Sbdf.PcieCap, WaitForRetrain);
> +      }
> +    }
> +  }
> +  return MyScc;
> +}
> +
> +/**
> +  Configures Latency Tolerance Reporting in given device and in PCIe tree
> below it.
> +  This function configures Maximum LTR and enables LTR mechanism. It visits
> devices using depth-first search
> +  and skips branches behind devices which do not support LTR.
> +  Maximum LTR:
> +    This function will set LTR's upper bound for every visited device. Max LTR
> value is provided as a parameter
> +  Enable LTR:
> +    LTR should be enabled top-to-bottom in every visited device that supports
> LTR. This function does not
> +    iterate down behind devices with no LTR support. In effect, LTR will be
> enabled in given device if that device
> +    and all devices above it on the way to RootComplex do support LTR.
> +
> +  This function expects that bridges have bus numbers already configured
> +
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +  @param[in] LtrLimit                       Ltr to be programmed to every
> endpoint
> +
> +  @retval MaxLTR programmed in this device
> +**/
> +STATIC
> +VOID
> +RecursiveLtrConfiguration (
> +  SBDF       Sbdf,
> +  LTR_LIMIT  LtrLimit
> +  )
> +{
> +  UINT64  Base;
> +  SBDF    ChildSbdf;
> +  PCI_DEV_TYPE DevType;
> +
> +  DEBUG ((DEBUG_INFO, "RecursiveLtrConfiguration %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +
> +  Base = SbdfToBase(Sbdf);
> +
> +  if (!IsLtrCapable (Sbdf)) {
> +    DEBUG ((DEBUG_INFO, "Not LtrCapable %02x:%02x:%02x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +    return;
> +  }
> +  EnableLtr (Sbdf);
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> +    DevType = GetDeviceType (Sbdf);
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +      RecursiveLtrConfiguration (ChildSbdf, LtrLimit);
> +    }
> +  }
> +  SetLtrLimit (Base, LtrLimit);
> +}
> +
> +/**
> +  In accordance with PCIe spec, devices with no LTR support are considered to
> have no LTR requirements
> +  which means infinite latency tolerance. This was found to cause problems
> with HID and Audio devices without LTR
> +  support placed behind PCIe switches with LTR support, as Switch's upstream
> link would be allowed to enter L1.2
> +  and cause large latency downstream. To work around such issues and to fix
> some devices with broken
> +  LTR reporting, Device Override table was introduced.
> +  This function scans PCIe tree for devices mentioned in override table and
> calculates the strictest
> +  LTR requirement between them. That value will be programmed into
> rootport's LTR override register
> +
> +  This function expects that bridges have bus numbers already configured
> +
> +  @param[in] BusLimit                       maximum Bus number that can be
> assigned below this port
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +  @param[in] AspmOverride                   Device specific ASPM policy
> override items
> +
> +  @retval MaxLTR programmed in this device
> +**/
> +STATIC
> +LTR_OVERRIDE
> +RecursiveLtrOverrideCheck (
> +  SBDF           Sbdf,
> +  OVERRIDE_TABLE *AspmOverride
> +  )
> +{
> +  UINT64       Base;
> +  SBDF         ChildSbdf;
> +  LTR_OVERRIDE MyLtrOverride;
> +  LTR_OVERRIDE ChildLtr;
> +  PCI_DEV_TYPE DevType;
> +
> +  DEBUG ((DEBUG_INFO, "RecursiveLtrOverrideCheck %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> +
> +  Base = SbdfToBase(Sbdf);
> +
> +  MyLtrOverride = GetOverrideLtr (Base, AspmOverride);
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> +    DevType = GetDeviceType (Sbdf);
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> +      ChildLtr = RecursiveLtrOverrideCheck (ChildSbdf, AspmOverride);
> +      MyLtrOverride = CombineLtr (MyLtrOverride, ChildLtr);
> +    }
> +  }
> +  return MyLtrOverride;
> +}
> +
> +/**
> +  Configures rootport packet split.
> +
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +  @param[in] Mps                            maximum packet size
> +**/
> +STATIC
> +VOID
> +ConfigureRpPacketSplit (
> +  SBDF   RpSbdf,
> +  UINT8  Mps
> +  )
> +{
> +  UINT64 RpBase;
> +
> +  RpBase = SbdfToBase (RpSbdf);
> +  PciSegmentAndThenOr32 (RpBase + R_PCH_PCIE_CFG_CCFG, (UINT32)
> ~(B_PCH_PCIE_CFG_CCFG_UNRS), Mps << N_PCH_PCIE_CFG_CCFG_UNRS);
> +}
> +
> +/**
> +  Configures LTR override in rootport's proprietary registers.
> +
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> +  @param[in] RpConfig                       rootport configuration
> +  @param[in] TreeLtr                        combination of LTR override values
> from all devices under this rootport
> +**/
> +STATIC
> +VOID
> +ConfigureRpLtrOverride (
> +  SBDF                      RpSbdf,
> +  PCH_PCIE_ROOT_PORT_CONFIG *RpConfig,
> +  OVERRIDE_TABLE            *AspmOverride
> +  )
> +{
> +  UINT64       RpBase;
> +  UINT32       OvrEn;
> +  UINT32       OvrVal;
> +  LTR_OVERRIDE TreeLtr;
> +
> +  OvrEn = 0;
> +  OvrVal = 0;
> +  RpBase = SbdfToBase (RpSbdf);
> +  //
> +  // LTR settings from LTROVR register only get acknowledged on rising edge of
> LTROVR2[1:0]
> +  // If those bits were already set (that can happen on a
> plug-hotUnplug-hotPlug scenario),
> +  // they need to be toggled
> +  //
> +  if (PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_LTROVR2) != 0) {
> +    PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_LTROVR2, 0);
> +  }
> +  //
> +  // (*)LatencyOverrideMode = 0 -> no override
> +  //                          1 -> override with RP policy values
> +  //                          2 -> override with endpoint's override values
> +  //
> +
> +  TreeLtr = RecursiveLtrOverrideCheck (RpSbdf, AspmOverride);
> +
> +  if (RpConfig->ForceLtrOverride || TreeLtr.ForceOverride) {
> +    OvrEn |= B_PCH_PCIE_CFG_LTROVR2_FORCE_OVERRIDE;
> +  }
> +  if (RpConfig->LtrConfigLock == TRUE) {
> +    OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LOCK;
> +  }
> +
> +  if (RpConfig->SnoopLatencyOverrideMode == 1) {
> +    OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LTRSOVREN;
> +    OvrVal |= RpConfig->SnoopLatencyOverrideValue;
> +    OvrVal |= RpConfig->SnoopLatencyOverrideMultiplier << 10;
> +    OvrVal |= B_PCH_PCIE_CFG_LTROVR_LTRSROVR;
> +  } else if (RpConfig->SnoopLatencyOverrideMode == 2) {
> +    if (TreeLtr.MaxSnoopLatencyRequirement) {
> +      OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LTRSOVREN;
> +      OvrVal |= TreeLtr.MaxSnoopLatencyValue;
> +      OvrVal |= TreeLtr.MaxSnoopLatencyScale << 10;
> +      OvrVal |= B_PCH_PCIE_CFG_LTROVR_LTRSROVR;
> +    }
> +  }
> +  if (RpConfig->NonSnoopLatencyOverrideMode == 1) {
> +    OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LTRNSOVREN;
> +    OvrVal |= RpConfig->NonSnoopLatencyOverrideValue << 16;
> +    OvrVal |= RpConfig->NonSnoopLatencyOverrideMultiplier << 26;
> +    OvrVal |= B_PCH_PCIE_CFG_LTROVR_LTRNSROVR;
> +  } else if (RpConfig->NonSnoopLatencyOverrideMode == 2) {
> +    if (TreeLtr.MaxNoSnoopLatencyRequirement) {
> +      OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LTRNSOVREN;
> +      OvrVal |= TreeLtr.MaxNoSnoopLatencyValue << 16;
> +      OvrVal |= TreeLtr.MaxNoSnoopLatencyScale << 26;
> +      OvrVal |= B_PCH_PCIE_CFG_LTROVR_LTRNSROVR;
> +    }
> +  }
> +  PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_LTROVR, OvrVal);
> +  PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_LTROVR2, OvrEn);
> +  DEBUG ((DEBUG_INFO, "ConfigureRpLtrOverride %x:%x Val %x En %x\n",
> RpSbdf.Dev, RpSbdf.Func, OvrVal, OvrEn));
> +}
> +
> +/**
> +  This function configures EOI message forwarding for PCIe port.
> +  If there's an IoAPIC behind this port, forwarding will be enabled
> +  Otherwise it will be disabled to minimize bus traffic
> +
> +  @param[in] RpSegment      address of rootport on PCIe
> +  @param[in] RpBus          address of rootport on PCIe
> +  @param[in] RpDevice       address of rootport on PCIe
> +  @param[in] RpFunction     address of rootport on PCIe
> +  @param[in] IoApicPresent  TRUE if there's IoAPIC behind this rootprot
> +**/
> +VOID
> +ConfigureEoiForwarding (
> +  UINT8    RpSegment,
> +  UINT8    RpBus,
> +  UINT8    RpDevice,
> +  UINT8    RpFunction,
> +  BOOLEAN  IoApicPresent
> +  )
> +{
> +  UINT64 RpBase;
> +  UINT32 RpIndex;
> +
> +  RpBase = PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice,
> RpFunction, 0);
> +  RpIndex = PciePortIndex (RpBase);
> +
> +  if (IoApicPresent == FALSE) {
> +   PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_MPC2,
> B_PCH_PCIE_CFG_MPC2_EOIFD);
> +  } else {
> +    ///
> +    /// If there is an IOAPIC discovered behind root port program PSF Multicast
> registers
> +    /// accordingly to PCH BWG  PSF EOI Multicast Configuration
> +    ///
> +    PciSegmentAnd32 (RpBase + R_PCH_PCIE_CFG_MPC2,
> (UINT32)~B_PCH_PCIE_CFG_MPC2_EOIFD);
> +    PsfConfigurEoiForPciePort (RpIndex);
> +  }
> +}
> +
> +/**
> +  Configures proprietary parts of L1 substates configuration in rootport
> +
> +  @param[in] RpSbdf   segment:bus:device:function coordinates of rootport
> +**/
> +STATIC
> +VOID
> +L1ssProprietaryConfiguration (
> +  SBDF RpSbdf
> +  )
> +{
> +  BOOLEAN ClkreqSupported;
> +  BOOLEAN L1ssEnabled;
> +  UINT16  PcieCapOffset;
> +  UINT32  Data32;
> +  BOOLEAN L1LowSupported;
> +  UINT64  RpBase;
> +
> +  RpBase = SbdfToBase (RpSbdf);
> +  ClkreqSupported = PcieIsPhyLanePgEnabled (RpBase);
> +
> +  PcieCapOffset = PcieBaseFindExtendedCapId (RpBase, V_PCIE_EX_L1S_CID);
> +  if (PcieCapOffset == 0) {
> +    L1ssEnabled = FALSE;
> +  } else {
> +    Data32 = PciSegmentRead32 (RpBase + PcieCapOffset +
> R_PCIE_EX_L1SCTL1_OFFSET);
> +    L1ssEnabled = Data32 & (B_PCIE_EX_L1SCAP_AL1SS |
> B_PCIE_EX_L1SCAP_AL12S | B_PCIE_EX_L1SCAP_PPL11S
> |B_PCIE_EX_L1SCAP_PPL12S);
> +  }
> +  L1LowSupported = ClkreqSupported && IsLtrCapable (RpSbdf)
> && !L1ssEnabled;
> +
> +  ///
> +  /// If L1.SNOOZ and L1.OFF (L1 Sub-States) are not supported and per-port
> CLKREQ# is supported, and LTR is supported:
> +  /// Enable L1.LOW by setting Dxx:Fn:420[17] = 1b
> +  ///
> +  if (L1LowSupported) {
> +    PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL, (UINT32)
> B_PCH_PCIE_CFG_PCIEPMECTL_L1LE);
> +  } else {
> +    PciSegmentAnd32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL, (UINT32)
> ~B_PCH_PCIE_CFG_PCIEPMECTL_L1LE);
> +  }
> +
> +  if (L1LowSupported || L1ssEnabled) {
> +    ///
> +    /// f.  Set Dxx:Fn:420h[0] to 1b prior to L1 enabling if any L1substate is
> enabled (including L1LOW)
> +    ///
> +    PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL,
> B_PCH_PCIE_CFG_PCIEPMECTL_L1FSOE);
> +  }
> +}
> +
> +/**
> +  Initializes the following features in rootport and devices behind it:
> +  Maximum Payload Size (generic)
> +  Rootport packet split (proprietary)
> +  EonOfInterrupt forwarding (proprietary)
> +  Common Clock Configuration (generic)
> +
> +  Generic: any code written according to PCIE Express base specification can
> do that.
> +  Proprietary: code uses registers and features that are specific to Intel silicon
> +  and probably only this Reference Code knows how to handle that.
> +
> +  If OEM implemented generic feature enabling in his platform code or trusts
> Operating System
> +  to do it, then those features can be deleted from here.
> +
> +  CCC requires link retrain, which takes a while. CCC must happen before
> L0s/L1 programming.
> +  If there was guarantee no code would access PCI while links retrain, it would
> be possible to skip this waiting
> +
> +  @param[in] RpSegment  address of rootport on PCIe
> +  @param[in] RpBus      address of rootport on PCIe
> +  @param[in] RpDevice   address of rootport on PCIe
> +  @param[in] RpFunction address of rootport on PCIe
> +  @param[in] BusMin     minimum Bus number that can be assigned below
> this rootport
> +  @param[in] BusMax     maximum Bus number that can be assigned below
> this rootport
> +**/
> +VOID
> +RootportDownstreamConfiguration (
> +  UINT8                     RpSegment,
> +  UINT8                     RpBus,
> +  UINT8                     RpDevice,
> +  UINT8                     RpFunction,
> +  UINT8                     BusMin,
> +  UINT8                     BusMax
> +  )
> +{
> +  UINT8      Mps;
> +  BOOLEAN    IoApicPresent;
> +  UINT64     RpBase;
> +  SBDF       RpSbdf;
> +  SBDF_TABLE BridgeCleanupList;
> +
> +  RpBase = PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice,
> RpFunction, 0);
> +  if (!(IsDevicePresent (RpBase))) {
> +    return;
> +  }
> +  RpSbdf.Seg = RpSegment;
> +  RpSbdf.Bus = RpBus;
> +  RpSbdf.Dev = RpDevice;
> +  RpSbdf.Func = RpFunction;
> +  RpSbdf.PcieCap = PcieBaseFindCapId (RpBase,
> EFI_PCI_CAPABILITY_ID_PCIEXP);
> +
> +  DEBUG ((DEBUG_INFO, "RootportDownstreamConfiguration %x:%x\n",
> RpDevice, RpFunction));
> +  BridgeCleanupList.Count = 0;
> +  RecursiveBusAssignment (RpSbdf, BusMin, BusMax, &BridgeCleanupList);
> +
> +  Mps = RecursiveMpsCheck (RpSbdf);
> +  RecursiveMpsConfiguration (RpSbdf, Mps);
> +  ConfigureRpPacketSplit (RpSbdf, Mps);
> +  IoApicPresent = RecursiveIoApicCheck (RpSbdf);
> +  ConfigureEoiForwarding (RpSegment, RpBus, RpDevice, RpFunction,
> IoApicPresent);
> +  RecursiveCccConfiguration (RpSbdf, TRUE);
> +
> +  ClearBusFromTable (&BridgeCleanupList);
> +}
> +
> +/**
> +  Configures the following power-management related features in rootport
> and devices behind it:
> +  LTR limit (generic)
> +  LTR override (proprietary)
> +  Clock Power Management (generic)
> +  L1 substates (generic except for the override table)
> +  L1.LOW substate (proprietary)
> +  L0s and L1 (generic)
> +
> +  Generic: any code written according to PCIE Express base specification can
> do that.
> +  Proprietary: code uses registers and features that are specific to Intel silicon
> +  and probably only this Reference Code knows how to handle that.
> +
> +  If OEM implemented generic feature enabling in his platform code or trusts
> Operating System
> +  to do it, then those features can be deleted from here.
> +
> +  @param[in] RpSegment                address of rootport on PCIe
> +  @param[in] RpBus                    address of rootport on PCIe
> +  @param[in] RpDevice                 address of rootport on PCIe
> +  @param[in] RpFunction               address of rootport on PCIe
> +  @param[in] BusLimit                 maximum Bus number that can be
> assigned below this rootport
> +  @param[in] AspmOverrideTableSize    size of override array
> +  @param[in] AspmOverrideTable        array of device that need exceptions
> in configuration
> +  @param[in] PerformAspmConfiguration enables/disables ASPM
> programming
> +**/
> +VOID
> +RootportDownstreamPmConfiguration (
> +  UINT8                     RpSegment,
> +  UINT8                     RpBus,
> +  UINT8                     RpDevice,
> +  UINT8                     RpFunction,
> +  UINT8                     BusMin,
> +  UINT8                     BusMax,
> +  PCH_PCIE_ROOT_PORT_CONFIG *RpConfig,
> +  UINT32                    AspmOverrideTableSize,
> +  PCH_PCIE_DEVICE_OVERRIDE  *AspmOverrideTable
> +  )
> +{
> +  LTR_LIMIT      PolicyLtr;
> +  OVERRIDE_TABLE PmOverrideTable;
> +  UINT64         RpBase;
> +  SBDF           RpSbdf;
> +  SBDF_TABLE     BridgeCleanupList;
> +
> +  RpBase = PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice,
> RpFunction, 0);
> +  if (!(IsDevicePresent (RpBase))) {
> +    return;
> +  }
> +  PmOverrideTable.Size = AspmOverrideTableSize;
> +  PmOverrideTable.Table = AspmOverrideTable;
> +
> +  DEBUG ((DEBUG_INFO, "RootportDownstreamPmConfiguration %x:%x\n",
> RpDevice, RpFunction));
> +  PolicyLtr.MaxNoSnoopLatencyScale = (RpConfig->LtrMaxNoSnoopLatency &
> 0x1c00) >> 10;
> +  PolicyLtr.MaxNoSnoopLatencyValue = RpConfig->LtrMaxNoSnoopLatency &
> 0x3FF;
> +  PolicyLtr.MaxSnoopLatencyScale   = (RpConfig->LtrMaxSnoopLatency &
> 0x1c00) >> 10;
> +  PolicyLtr.MaxSnoopLatencyValue   = RpConfig->LtrMaxSnoopLatency &
> 0x3FF;
> +
> +  RpSbdf.Seg = RpSegment;
> +  RpSbdf.Bus = RpBus;
> +  RpSbdf.Dev = RpDevice;
> +  RpSbdf.Func = RpFunction;
> +  RpSbdf.PcieCap = PcieBaseFindCapId (RpBase,
> EFI_PCI_CAPABILITY_ID_PCIEXP);
> +  //
> +  // This code could execute either before or after enumeration. If before,
> then buses would not yet be assigned to bridges,
> +  // making devices deeper in the hierarchy inaccessible.
> +  // RecursiveBusAssignment will scan whole PCie tree and assign bus
> numbers to uninitialized bridges, if there are any
> +  // List of such bridges will be kept in CleanupList, so that after PM
> programming is done, bus numbers can brought to original state
> +  //
> +  BridgeCleanupList.Count = 0;
> +  RecursiveBusAssignment(RpSbdf, BusMin, BusMax, &BridgeCleanupList);
> +  //
> +  // The 'Recursive...' functions below expect bus numbers to be already
> assigned
> +  //
> +  RecursiveLtrConfiguration (RpSbdf, PolicyLtr);
> +  ConfigureRpLtrOverride (RpSbdf, RpConfig, &PmOverrideTable);
> +  if (RpConfig->EnableCpm) {
> +    RecursiveCpmConfiguration (RpSbdf);
> +  }
> +  //
> +  // L1 substates can be modified only when L1 is disabled, so this function
> must execute
> +  // before Aspm configuration which enables L1
> +  //
> +  RecursiveL1ssConfiguration (RpSbdf, &PmOverrideTable);
> +  L1ssProprietaryConfiguration (RpSbdf);
> +  RecursiveAspmConfiguration (RpSbdf, 0, &PmOverrideTable);
> +  ClearBusFromTable (&BridgeCleanupList);
> +}
> +
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PchPsfPrivateLib.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PchPsfPrivateLib.c
> new file mode 100644
> index 0000000000..f2d20c625a
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PchPsfPrivateLib.c
> @@ -0,0 +1,542 @@
> +/** @file
> +  This file contains PSF routines for RC usage
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/SataLib.h>
> +#include <Library/SaPlatformLib.h>
> +#include <Private/Library/PchPsfPrivateLib.h>
> +#include <PchLimits.h>
> +#include <Register/PchRegsPsf.h>
> +#include <Register/PchRegsPcie.h>
> +#include "PchPsfPrivateLibInternal.h"
> +
> +/**
> +  Disable device at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort  PSF PORT data structure
> +**/
> +VOID
> +PsfDisableDevice (
> +  IN PSF_PORT  PsfPort
> +  )
> +{
> +  if (PSF_IS_PORT_NULL (PsfPort)) {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +
> +  //
> +  // Read back is needed to enforce the sideband and primary ordering.
> +  //
> +  PchPcrAndThenOr32WithReadback (
> +    PsfPort.PsfPid,
> +    PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_PCIEN,
> +    ~0u,
> +    B_PCH_PSFX_PCR_T0_SHDW_PCIEN_FUNDIS
> +    );
> +}
> +
> +/**
> +  Hide PciCfgSpace of device at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort  PSF PORT data structure
> +**/
> +VOID
> +PsfHideDevice (
> +  IN PSF_PORT  PsfPort
> +  )
> +{
> +  if (PSF_IS_PORT_NULL (PsfPort)) {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +
> +  //
> +  // Read back is needed to enforce the sideband and primary ordering.
> +  // If there is PCI access right after the PSF hide device, the device might
> +  // still be accessible since the PSF cycle is not completed yet, and causes
> +  // the race condition between sideband and primary cycles.
> +  //
> +  PchPcrAndThenOr32WithReadback (
> +    PsfPort.PsfPid,
> +    PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_CFG_DIS,
> +    ~0u,
> +    B_PCH_PSFX_PCR_T0_SHDW_CFG_DIS_CFGDIS
> +    );
> +}
> +
> +/**
> +  Unhide PciCfgSpace of device at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort  PSF PORT data structure
> +**/
> +VOID
> +PsfUnhideDevice (
> +  IN PSF_PORT  PsfPort
> +  )
> +{
> +  if (PSF_IS_PORT_NULL (PsfPort)) {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +
> +  //
> +  // Read back is needed to enforce the sideband and primary ordering.
> +  //
> +  PchPcrAndThenOr32WithReadback (
> +    PsfPort.PsfPid,
> +    PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_CFG_DIS,
> +    (UINT32) ~(B_PCH_PSFX_PCR_T0_SHDW_CFG_DIS_CFGDIS),
> +    0
> +    );
> +}
> +
> +/**
> +  Disable device BARs at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +  @param[in] BarDisMask  BIT0-BAR0, BIT1-BAR1,...
> +                         Mask corresponds to 32bit wide BARs
> +**/
> +VOID
> +PsfDisableDeviceBar (
> +  IN PSF_PORT  PsfPort,
> +  IN UINT32    BarDisMask
> +  )
> +{
> +  if (PSF_IS_PORT_NULL (PsfPort)) {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +
> +  //
> +  // BAR0-5 supported
> +  //
> +  ASSERT (BarDisMask < BIT6);
> +
> +  //
> +  // Read back is needed to enforce the sideband and primary ordering.
> +  //
> +  PchPcrAndThenOr32WithReadback (
> +    PsfPort.PsfPid,
> +    PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_PCIEN,
> +    ~0u,
> +    BarDisMask << N_PCH_PSFX_PCR_T0_SHDW_PCIEN_BARXDIS
> +    );
> +}
> +
> +/**
> +  Enable device BARs at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +  @param[in] BarEnMask   BIT0-BAR0, BIT1-BAR1,...
> +                         Mask corresponds to 32bit wide BARs
> +**/
> +VOID
> +PsfEnableDeviceBar (
> +  IN PSF_PORT  PsfPort,
> +  IN UINT32    BarEnMask
> +  )
> +{
> +  if (PSF_IS_PORT_NULL (PsfPort)) {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +
> +  //
> +  // BAR0-5 supported
> +  //
> +  ASSERT (BarEnMask < BIT6);
> +
> +  //
> +  // Read back is needed to enforce the sideband and primary ordering.
> +  //
> +  PchPcrAndThenOr32WithReadback (
> +    PsfPort.PsfPid,
> +    PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_PCIEN,
> +    (UINT32)~(BarEnMask << N_PCH_PSFX_PCR_T0_SHDW_PCIEN_BARXDIS),
> +    0
> +    );
> +}
> +
> +/**
> +  Disable device IOSpace at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +**/
> +VOID
> +PsfDisableDeviceIoSpace (
> +  IN PSF_PORT  PsfPort
> +  )
> +{
> +  if (PSF_IS_PORT_NULL (PsfPort)) {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +
> +  //
> +  // Read back is needed to enforce the sideband and primary ordering.
> +  //
> +  PchPcrAndThenOr32WithReadback (
> +    PsfPort.PsfPid,
> +    PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_PCIEN,
> +    ~(UINT32)(B_PCH_PSFX_PCR_T0_SHDW_PCIEN_IOEN),
> +    0
> +    );
> +}
> +
> +/**
> +  Enable device IOSpace at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +**/
> +VOID
> +PsfEnableDeviceIoSpace (
> +  IN PSF_PORT  PsfPort
> +  )
> +{
> +  if (PSF_IS_PORT_NULL (PsfPort)) {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +
> +  //
> +  // Read back is needed to enforce the sideband and primary ordering.
> +  //
> +  PchPcrAndThenOr32WithReadback (
> +    PsfPort.PsfPid,
> +    PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_PCIEN,
> +    ~0u,
> +    B_PCH_PSFX_PCR_T0_SHDW_PCIEN_IOEN
> +    );
> +}
> +
> +/**
> +  Set device BARx address at PSF level
> +  Method not for bridges (e.g. PCIe Root Port)
> +
> +  @param[in] PsfPort     PSF PORT data structure
> +  @param[in] BarNum      BAR Number (0:BAR0, 1:BAR1, ...)
> +  @param[in] BarValue    32bit BAR value
> +**/
> +VOID
> +PsfSetDeviceBarValue (
> +  IN PSF_PORT  PsfPort,
> +  IN UINT8     BarNum,
> +  IN UINT32    BarValue
> +  )
> +{
> +  ASSERT (BarNum < 6);
> +
> +  if (PSF_IS_PORT_NULL (PsfPort)) {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +
> +  //
> +  // Read back is needed to enforce the sideband and primary ordering.
> +  //
> +  PchPcrAndThenOr32WithReadback (
> +    PsfPort.PsfPid,
> +    PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_BAR0 + BarNum * 0x4,
> +    0,
> +    BarValue
> +    );
> +}
> +
> +/**
> +  Hide PMC device at PSF level
> +**/
> +VOID
> +PsfHidePmcDevice (
> +  VOID
> +  )
> +{
> +  PsfHideDevice (PsfPmcPort ());
> +}
> +
> +/**
> +  Set PMC ABASE value in PSF
> +
> +  @param[in] Address     Address for ACPI base address.
> +**/
> +VOID
> +PsfSetPmcAbase (
> +  IN  UINT16       Address
> +  )
> +{
> +  PSF_PORT PsfPort;
> +
> +  PsfPort = PsfPmcPort ();
> +
> +  ASSERT (PchPcrRead32 (PsfPort.PsfPid, PsfPort.RegBase +
> R_PCH_PSFX_PCR_T0_SHDW_BAR4) != 0xFFFFFFFF);
> +
> +  //
> +  // Disable IOSpace before changing the address
> +  //
> +  PsfDisableDeviceIoSpace (PsfPort);
> +
> +  //
> +  // Program ABASE in PSF PMC space BAR4
> +  //
> +  PsfSetDeviceBarValue (PsfPort, 4, Address);
> +
> +  //
> +  // Enable IOSpace
> +  //
> +  PsfEnableDeviceIoSpace (PsfPort);
> +}
> +
> +/**
> +  Get PMC ABASE value from PSF
> +
> +  @retval Address     Address for ACPI base.
> +**/
> +UINT16
> +PsfGetPmcAbase (
> +  VOID
> +  )
> +{
> +  UINT16    Address;
> +  PSF_PORT  PsfPort;
> +
> +  PsfPort = PsfPmcPort ();
> +  //
> +  // Read ABASE from PSF PMC space BAR4
> +  //
> +  Address = PchPcrRead16 (
> +              PsfPort.PsfPid,
> +              PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_BAR4
> +              );
> +
> +  ASSERT (Address != 0xFFFF);
> +
> +  return Address;
> +}
> +
> +/**
> +  Get PMC PWRMBASE value from PSF
> +
> +  @retval Address     Address for PWRM base.
> +**/
> +UINT32
> +PsfGetPmcPwrmBase (
> +  VOID
> +  )
> +{
> +  UINT32    Address;
> +  PSF_PORT  PsfPort;
> +
> +  PsfPort = PsfPmcPort ();
> +  //
> +  // Read PWRMBASE from PSF PMC space BAR0
> +  //
> +  Address = PchPcrRead32 (
> +              PsfPort.PsfPid,
> +              PsfPort.RegBase + R_PCH_PSFX_PCR_T0_SHDW_BAR0
> +              );
> +
> +  ASSERT (Address != 0xFFFFFFFF);
> +
> +  return Address;
> +}
> +
> +/**
> +  Get PSF SideBand Port ID from PSF ID (1 - PSF1, 2 - PSF2, ...)
> +
> +  @param[in] PsfId             PSF ID (1 - PSF1, 2 - PSF2, ...)
> +
> +  @retval PSF SideBand Port ID
> +**/
> +PCH_SBI_PID
> +PsfSbPortId (
> +  UINT32        PsfId
> +  )
> +{
> +  UINT32          PsfTableIndex;
> +  PSF_SEGMENT     *PsfTable;
> +  UINT32          PsfTableSize;
> +
> +  PsfSegments (&PsfTable, &PsfTableSize);
> +
> +  for (PsfTableIndex = 0; PsfTableIndex < PsfTableSize; PsfTableIndex++) {
> +    if (PsfTable[PsfTableIndex].Id == PsfId) {
> +      return PsfTable[PsfTableIndex].SbPid;
> +    }
> +  }
> +
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +
> +/**
> +  Get PCH Root PSF ID. This is the PSF segment to which OPDMI/DMI is
> connected.
> +
> +  @retval PsfId             Root PSF ID
> +**/
> +UINT32
> +PsfRootId (
> +  VOID
> +  )
> +{
> +  PSF_SEGMENT     *PsfTable;
> +  UINT32          PsfTableSize;
> +
> +  PsfSegments (&PsfTable, &PsfTableSize);
> +
> +  return PsfTable[0].Id;
> +}
> +
> +/**
> +  Add EOI Target in a given PSF
> +
> +  @param[in] PsfId             PSF ID (1 - PSF1, 2 - PSF2, ...)
> +  @param[in] TargetId          EOI Target ID
> +**/
> +STATIC
> +VOID
> +PsfAddEoiTarget (
> +  UINT32           PsfId,
> +  PSF_PORT_DEST_ID TargetId
> +  )
> +{
> +  UINT16      EoiTargetBase;
> +  UINT16      EoiControlBase;
> +  UINT8       NumOfEnabledTargets;
> +  UINT8       MaximalNumberOfTargets;
> +  PCH_SBI_PID PsfSbiPortId;
> +  UINT32      Data32;
> +  UINT8       TargetIndex;
> +
> +  MaximalNumberOfTargets = PsfEoiRegData (PsfId, &EoiTargetBase,
> &EoiControlBase);
> +  PsfSbiPortId = PsfSbPortId (PsfId);
> +
> +  //
> +  // Get number of enabled agents from
> PSF_x_PSF_MC_CONTROL_MCAST0_RS0_EOI register
> +  //
> +  Data32 = PchPcrRead32 (PsfSbiPortId, EoiControlBase);
> +  NumOfEnabledTargets = (UINT8) (Data32 >>
> N_PCH_PSFX_PCR_MC_CONTROL_MCASTX_NUMMC);
> +
> +  //
> +  // Check if target was not already enabled
> +  // Targets from a different PSF segment are aggregated into single
> destination on
> +  // current PSF segment.
> +  //
> +  for (TargetIndex = 0; TargetIndex < NumOfEnabledTargets; TargetIndex++) {
> +    Data32 = PchPcrRead32 (PsfSbiPortId, EoiTargetBase + TargetIndex * 4);
> +    //
> +    // If target already added don't add it again
> +    //
> +    if (Data32 == TargetId.RegVal) {
> +      ASSERT (FALSE);
> +      return;
> +    }
> +    //
> +    // If target is from different PSF segment than currently being analyzed
> +    // it is enough that its PsfID is matching
> +    //
> +    if ((Data32 & B_PCH_PSFX_PCR_TARGET_PSFID) >>
> N_PCH_PSFX_PCR_TARGET_PSFID == TargetId.Fields.PsfId) {
> +      return;
> +    }
> +  }
> +
> +  //
> +  // Check if next one can be added
> +  //
> +  if (NumOfEnabledTargets >= MaximalNumberOfTargets) {
> +    ASSERT (FALSE);
> +    return;
> +  }
> +
> +  //
> +  // Add next target
> +  // Configure Multicast Destination ID register with target device on PSF.
> +  // Configuration must be done in next available
> PSF_MC_AGENT_MCAST0_RS0_TGT<x>_EOI register
> +  // so that other targets  are not overridden. <x> is known from the number
> of multicast agents
> +  // in Multicast Control Register. Value programmed is based on
> +  // PsfID, PortGroupID, PortID and ChannelID of the target
> +  //
> +  PchPcrWrite32 (PsfSbiPortId, EoiTargetBase + NumOfEnabledTargets * 4,
> TargetId.RegVal);
> +
> +  //
> +  // Enable new target
> +  // Configure PSF_x_PSF_MC_CONTROL_MCAST0_RS0_EOI, increase NumMc
> and set MultCEn
> +  //
> +  NumOfEnabledTargets++;
> +  Data32 = (NumOfEnabledTargets <<
> N_PCH_PSFX_PCR_MC_CONTROL_MCASTX_NUMMC) |
> B_PCH_PSFX_PCR_MC_CONTROL_MCASTX_MULTCEN;
> +  PchPcrWrite32 (PsfSbiPortId, EoiControlBase, Data32);
> +}
> +
> +/**
> +  Enable EOI Target
> +
> +  @param[in] TargetId  Target ID
> +**/
> +STATIC
> +VOID
> +PsfEnableEoiTarget (
> +  PSF_PORT_DEST_ID     TargetId
> +  )
> +{
> +  UINT32 RootLevelPsf;
> +
> +  RootLevelPsf = PsfRootId ();
> +
> +  //
> +  // Enable EOI target in root PSF
> +  //
> +  PsfAddEoiTarget (RootLevelPsf, TargetId);
> +
> +  //
> +  // Enable EOI target on other PSF segment if target
> +  // is not located on root PSF
> +  //
> +  if (TargetId.Fields.PsfId != RootLevelPsf) {
> +    PsfAddEoiTarget (TargetId.Fields.PsfId, TargetId);
> +  }
> +}
> +
> +/**
> +  This function enables EOI message forwarding in PSF for PCIe ports
> +  for cases where IOAPIC is present behind this root port.
> +
> +  @param[in] RpIndex        Root port index (0 based)
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +PsfConfigurEoiForPciePort (
> +  IN  UINT32  RpIndex
> +  )
> +{
> +  ASSERT (RpIndex < GetPchMaxPciePortNum ());
> +
> +  //
> +  // If there is an IOAPIC discovered behind root port program PSF Multicast
> registers
> +  // accordingly to PCH BWG PSF EOI Multicast Configuration
> +  // Since there is a device behind RootPort to which EOI needs to be
> forwarded
> +  // enable multicast (MULTCEN) and increase the number of multicast agents
> (NUMMC)
> +  // in Multicast Control Register.
> +  //
> +  PsfEnableEoiTarget (PsfPcieDestinationId (RpIndex));
> +
> +  return EFI_SUCCESS;
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PchPsfPrivateLibCnl.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PchPsfPrivateLibCnl.c
> new file mode 100644
> index 0000000000..d1c87a9e84
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPr
> ivateLib/PchPsfPrivateLibCnl.c
> @@ -0,0 +1,338 @@
> +/** @file
> +  This file contains internal PSF routines for PCH PSF lib usage
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/SataLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Register/PchRegsPsf.h>
> +#include <Register/PchRegsPsfCnl.h>
> +#include <Register/PchRegsPcie.h>
> +#include "PchPsfPrivateLibInternal.h"
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPchLpSerialIoI2cPsfRegs[] =
> +{
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_I2C0_REG_BASE,
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_I2C1_REG_BASE,
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_I2C2_REG_BASE,
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_I2C3_REG_BASE,
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_I2C4_REG_BASE,
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_I2C5_REG_BASE
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPchHSerialIoI2cPsfRegs[] =
> +{
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_I2C0_REG_BASE,
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_I2C1_REG_BASE,
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_I2C2_REG_BASE,
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_I2C3_REG_BASE
> +};
> +
> +/**
> +  Return PSF_PORT for SerialIO I2C device
> +
> +  @param[in] I2cNum  Serial IO I2C device (I2C0, I2C1, ....)
> +
> +  @retval  PsfPort   PSF PORT structure for SerialIO I2C device
> +**/
> +PSF_PORT
> +PsfSerialIoI2cPort (
> +  IN UINT32  I2cNum
> +  )
> +{
> +  PSF_PORT PsfPort;
> +
> +  PsfPort.PsfPid = PID_PSF3;
> +
> +  if (IsPchLp ()) {
> +    if (I2cNum < ARRAY_SIZE(mPchLpSerialIoI2cPsfRegs)) {
> +      PsfPort.RegBase = mPchLpSerialIoI2cPsfRegs[I2cNum];
> +      return PsfPort;
> +    }
> +  } else {
> +    if (I2cNum < ARRAY_SIZE(mPchHSerialIoI2cPsfRegs)) {
> +      PsfPort.RegBase = mPchHSerialIoI2cPsfRegs[I2cNum];
> +      return PsfPort;
> +    }
> +  }
> +
> +  ASSERT(FALSE);
> +  return PSF_PORT_NULL;
> +}
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPchLpSerialIoSpiPsfRegs[] =
> +{
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_SPI0_REG_BASE,
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_SPI1_REG_BASE,
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_SPI2_REG_BASE
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPchHSerialIoSpiPsfRegs[] =
> +{
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_SPI0_REG_BASE,
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_SPI1_REG_BASE,
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_SPI2_REG_BASE
> +};
> +
> +/**
> +  Return PSF_PORT for SerialIO SPI device
> +
> +  @param[in] SpiNum  Serial IO SPI device (SPI0, SPI1, ....)
> +
> +  @retval  PsfPort   PSF PORT structure for SerialIO SPI device
> +**/
> +PSF_PORT
> +PsfSerialIoSpiPort (
> +  IN UINT32  SpiNum
> +  )
> +{
> +  PSF_PORT PsfPort;
> +
> +  PsfPort.PsfPid = PID_PSF3;
> +
> +  if (IsPchLp ()) {
> +    if (SpiNum < ARRAY_SIZE(mPchLpSerialIoSpiPsfRegs)) {
> +      PsfPort.RegBase = mPchLpSerialIoSpiPsfRegs[SpiNum];
> +      return PsfPort;
> +    }
> +  } else {
> +    if (SpiNum < ARRAY_SIZE(mPchHSerialIoSpiPsfRegs)) {
> +      PsfPort.RegBase = mPchHSerialIoSpiPsfRegs[SpiNum];
> +      return PsfPort;
> +    }
> +  }
> +
> +  ASSERT(FALSE);
> +  return PSF_PORT_NULL;
> +}
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPchLpSerialIoUartPsfRegs[] =
> +{
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_UART0_REG_BASE,
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_UART1_REG_BASE,
> +  R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_UART2_REG_BASE
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPchHSerialIoUartPsfRegs[] =
> +{
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_UART0_REG_BASE,
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_UART1_REG_BASE,
> +  R_CNL_PCH_H_PSF3_PCR_T0_SHDW_UART2_REG_BASE
> +};
> +
> +/**
> +  Return PSF_PORT for SerialIO UART device
> +
> +  @param[in] UartNum  Serial IO UART device (UART0, UART1, ....)
> +
> +  @retval  PsfPort    PSF PORT structure for SerialIO UART device
> +**/
> +PSF_PORT
> +PsfSerialIoUartPort (
> +  IN UINT32  UartNum
> +  )
> +{
> +  PSF_PORT PsfPort;
> +
> +  PsfPort.PsfPid = PID_PSF3;
> +
> +  if (IsPchLp ()) {
> +    if (UartNum < ARRAY_SIZE(mPchLpSerialIoUartPsfRegs)) {
> +      PsfPort.RegBase = mPchLpSerialIoUartPsfRegs[UartNum];
> +      return PsfPort;
> +    }
> +  } else {
> +    if (UartNum < ARRAY_SIZE(mPchHSerialIoUartPsfRegs)) {
> +      PsfPort.RegBase = mPchHSerialIoUartPsfRegs[UartNum];
> +      return PsfPort;
> +    }
> +  }
> +
> +  ASSERT(FALSE);
> +  return PSF_PORT_NULL;
> +}
> +
> +/**
> +  Get EOI register data for given PSF ID
> +
> +  @param[in]  PsfId           PSF ID (1 - PSF1, 2 - PSF2, ...)
> +  @param[out] EoiTargetBase   EOI Target register
> +  @param[out] EoiControlBase  EOI Control register
> +
> +  @retval MaxTargets          Number of supported targets
> +
> +**/
> +UINT8
> +PsfEoiRegData (
> +  UINT32        PsfId,
> +  UINT16        *EoiTargetBase,
> +  UINT16        *EoiControlBase
> +  )
> +{
> +  UINT8  MaxTargets;
> +
> +  MaxTargets = 0;
> +  *EoiTargetBase = 0;
> +  *EoiControlBase = 0;
> +
> +  switch (PsfId) {
> +    case 1:
> +      if (IsPchLp ()) {
> +        *EoiTargetBase =
> R_CNL_PCH_LP_PSF1_PCR_PSF_MC_AGENT_MCAST0_TGT0_EOI;
> +        *EoiControlBase =
> R_CNL_PCH_LP_PSF1_PCR_PSF_MC_CONTROL_MCAST0_EOI;
> +        MaxTargets = 17;
> +      } else {
> +        *EoiTargetBase =
> R_CNL_PCH_H_PSF1_PCR_PSF_MC_AGENT_MCAST0_TGT0_EOI;
> +        *EoiControlBase =
> R_CNL_PCH_H_PSF1_PCR_PSF_MC_CONTROL_MCAST0_EOI;
> +        MaxTargets = 7;
> +      }
> +      break;
> +
> +    case 3:
> +      *EoiTargetBase =
> R_CNL_PCH_PSF3_PCR_PSF_MC_AGENT_MCAST0_TGT0_EOI;
> +      *EoiControlBase =
> R_CNL_PCH_PSF3_PCR_PSF_MC_CONTROL_MCAST0_EOI;
> +      MaxTargets = 1;
> +      break;
> +
> +    case 6:
> +      if (IsPchH ()) {
> +        *EoiTargetBase =
> R_CNL_PCH_H_PSF6_PCR_PSF_MC_AGENT_MCAST0_TGT0_EOI;
> +        *EoiControlBase =
> R_CNL_PCH_H_PSF6_PCR_PSF_MC_CONTROL_MCAST0_EOI;
> +        MaxTargets = 8;
> +      }
> +      break;
> +
> +    case 7:
> +      if (IsPchH ()) {
> +        *EoiTargetBase =
> R_CNL_PCH_H_PSF7_PCR_PSF_MC_AGENT_MCAST0_TGT0_EOI;
> +        *EoiControlBase =
> R_CNL_PCH_H_PSF7_PCR_PSF_MC_CONTROL_MCAST0_EOI;
> +        MaxTargets = 8;
> +      }
> +      break;
> +
> +    case 8:
> +      if (IsPchH ()) {
> +        *EoiTargetBase =
> R_CNL_PCH_H_PSF8_PCR_PSF_MC_AGENT_MCAST0_TGT0_EOI;
> +        *EoiControlBase =
> R_CNL_PCH_H_PSF8_PCR_PSF_MC_CONTROL_MCAST0_EOI;
> +        MaxTargets = 8;
> +      }
> +      break;
> +  }
> +  return MaxTargets;
> +}
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED PSF_PORT_DEST_ID PchLpRpDestId[] =
> +{
> +  {0x18000}, {0x18001}, {0x18002}, {0x18003}, // SPA: PSF1, PortID = 0
> +  {0x18200}, {0x18201}, {0x18202}, {0x18203}, // SPB: PSF1, PortID = 2
> +  {0x18400}, {0x18401}, {0x18402}, {0x18403}, // SPC: PSF1, PortID = 4
> +  {0x18600}, {0x18601}, {0x18602}, {0x18603}  // SPD: PSF1, PortID = 6
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED PSF_PORT_DEST_ID PchHRpDestId[] =
> +{
> +  {0x68000}, {0x68001}, {0x68002}, {0x68003}, // SPA: PSF6, PortID = 0
> +  {0x88000}, {0x88001}, {0x88002}, {0x88003}, // SPB: PSF8, PortID = 0
> +  {0x68100}, {0x68101}, {0x68102}, {0x68103}, // SPC: PSF6, PortID = 1
> +  {0x78000}, {0x78001}, {0x78002}, {0x78003}, // SPD: PSF7, PortID = 0
> +  {0x78100}, {0x78101}, {0x78102}, {0x78103}, // SPE: PSF7, PortID = 1
> +  {0x88100}, {0x88101}, {0x88102}, {0x88103}  // SPF: PSF8, PortID = 1
> +};
> +
> +/**
> +  PCIe PSF port destination ID (psf_id:port_group_id:port_id:channel_id)
> +
> +  @param[in] RpIndex        PCIe Root Port Index (0 based)
> +
> +  @retval Destination ID
> +**/
> +PSF_PORT_DEST_ID
> +PsfPcieDestinationId (
> +  IN UINT32  RpIndex
> +  )
> +{
> +  if (IsPchLp ()) {
> +    if (RpIndex < ARRAY_SIZE(PchLpRpDestId)) {
> +      return PchLpRpDestId[RpIndex];
> +    }
> +  } else {
> +    if (RpIndex < ARRAY_SIZE(PchHRpDestId)) {
> +      return PchHRpDestId[RpIndex];
> +    }
> +  }
> +  ASSERT (FALSE);
> +  return (PSF_PORT_DEST_ID){0};
> +}
> +
> +
> +/**
> +  Return PSF_PORT for PMC device
> +
> +  @retval    PsfPort         PSF PORT structure for PMC device
> +**/
> +PSF_PORT
> +PsfPmcPort (
> +  VOID
> +  )
> +{
> +  PSF_PORT PsfPort;
> +
> +  PsfPort.PsfPid = PID_PSF3;
> +
> +  if (IsPchLp ()) {
> +    PsfPort.RegBase = R_CNL_PCH_LP_PSF3_PCR_T0_SHDW_PMC_REG_BASE;
> +  } else {
> +    PsfPort.RegBase = R_CNL_PCH_H_PSF3_PCR_T0_SHDW_PMC_REG_BASE;
> +  }
> +  return PsfPort;
> +}
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED PSF_SEGMENT mPchLpPsfTable[] =
> +{
> +  {1, PID_PSF1},
> +  {2, PID_PSF2},
> +  {3, PID_PSF3},
> +  {4, PID_PSF4},
> +  {5, PID_CSME_PSF}
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED PSF_SEGMENT mPchHPsfTable[]  =
> +{
> +  {1, PID_PSF1},
> +  {2, PID_PSF2},
> +  {3, PID_PSF3},
> +  {4, PID_PSF4},
> +  {5, PID_CSME_PSF},
> +  {6, PID_PSF6},
> +  {7, PID_PSF7},
> +  {8, PID_PSF8}
> +};
> +
> +/**
> +  Get list of supported PSF segments.
> +
> +  @param[out] PsfTable        Array of supported PSF segments
> +  @param[out] PsfTableLength  Length of PsfTable
> +**/
> +VOID
> +PsfSegments (
> +  OUT PSF_SEGMENT  **PsfTable,
> +  OUT UINT32       *PsfTableLength
> +  )
> +{
> +  if (IsPchLp ()) {
> +    *PsfTable = mPchLpPsfTable;
> +    *PsfTableLength = ARRAY_SIZE(mPchLpPsfTable);
> +  } else {
> +    *PsfTable = mPchHPsfTable;
> +    *PsfTableLength = ARRAY_SIZE(mPchHPsfTable);
> +  }
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiPmcPrivateLib.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiPmcPrivateLib.c
> new file mode 100644
> index 0000000000..f88febfa48
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PeiPmcPrivateLib.c
> @@ -0,0 +1,92 @@
> +/** @file
> +  PCH private PEI PMC Library for all PCH generations.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PciSegmentLib.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/ConfigBlockLib.h>
> +#include <Ppi/SiPolicy.h>
> +#include <Library/PmcLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/PchEspiLib.h>
> +#include <Private/Library/GpioPrivateLib.h>
> +#include <Private/Library/PmcPrivateLib.h>
> +#include <Register/PchRegsPmc.h>
> +#include <Register/PchRegsClk.h>
> +#include <Register/PchRegs.h>
> +#include <Register/PchRegsLan.h>
> +#include "PmcPrivateLibInternal.h"
> +
> +/**
> +  Check if PCH PM Timer enabled based on platform policy
> +
> +  @retval TRUE       PCH PM Timer is enabled.
> +  @retval FALSE      PCH PM Timer is disabled.
> +**/
> +BOOLEAN
> +PmcIsPchPmTimerEnabled (
> +  VOID
> +  )
> +{
> +  BOOLEAN           PchPmTimerEnabled;
> +  EFI_STATUS        Status;
> +  SI_POLICY_PPI     *SiPolicy;
> +  PCH_PM_CONFIG     *PmConfig;
> +
> +  Status = PeiServicesLocatePpi (
> +             &gSiPolicyPpiGuid,
> +             0,
> +             NULL,
> +             (VOID **)&SiPolicy
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  Status = GetConfigBlock ((VOID *) SiPolicy, &gPmConfigGuid, (VOID *)
> &PmConfig);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  PchPmTimerEnabled = TRUE;
> +  if (!PmConfig->EnableTcoTimer) {
> +    PchPmTimerEnabled = FALSE;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "PmcIsPchPmTimerEnabled () = %x\n",
> PchPmTimerEnabled));
> +
> +  return PchPmTimerEnabled;
> +}
> +
> +/**
> +  Lock down PMC settings
> +
> +  @param[in] SiPolicy   The SI Policy PPI instance
> +**/
> +VOID
> +PmcLockSettings (
> +  IN  SI_POLICY_PPI     *SiPolicy
> +  )
> +{
> +
> +  UINT32         PchPwrmBase;
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  ///
> +  /// Set PWRMBASE Offset 0x1048 [24]
> +  ///
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_ETR3, BIT24);
> +
> +  ///
> +  /// PM_SYNC_LOCK
> +  /// Set PWRMBASE Offset 0x18C8 [15]
> +  ///
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_PMSYNC_MISC_CFG,
> B_PMC_PWRM_PMSYNC_PM_SYNC_LOCK);
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLib.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLib.c
> new file mode 100644
> index 0000000000..a6ccf4b96b
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLib.c
> @@ -0,0 +1,1033 @@
> +/** @file
> +  PCH private PMC Library for all PCH generations.
> +  All function in this library is available for PEI, DXE, and SMM,
> +  But do not support UEFI RUNTIME environment call.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PmcLib.h>
> +#include <Library/PciSegmentLib.h>
> +#include <Library/PchPcrLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Library/TimerLib.h>
> +#include <Private/Library/PmcPrivateLib.h>
> +#include <Private/Library/PchPsfPrivateLib.h>
> +#include <PchReservedResources.h>
> +#include <Register/PchRegs.h>
> +#include <Register/PchRegsPmc.h>
> +#include <Register/PchRegsItss.h>
> +#include <IndustryStandard/Pci30.h>
> +
> +#include "PmcPrivateLibInternal.h"
> +
> +/**
> +  Send PMC IPC1 Normal Read/Write command
> +
> +  @param[in]  Command           Command to be issued to PMC IPC 1
> interface
> +  @param[in]  SubCmdId          SUB_CMD_ID for provided Command
> +  @param[in]  CmdSize           Total size in byte to be sent via PMC IPC 1
> interface
> +  @param[in]  WriteBufPtr       Pointer to Structure of 4 DWORDs to be
> issued to PMC IPC 1 interface
> +  @param[out] ReadBufPtr        Pointer to Structure of 4 DWORDs to be
> filled by PMC IPC 1 interface
> +
> +  @retval EFI_SUCCESS             Command was executed successfully
> +  @retval EFI_INVALID_PARAMETER   Invalid command size
> +  @retval EFI_DEVICE_ERROR        IPC command failed with an error
> +  @retval EFI_TIMEOUT             IPC command did not complete after 1s
> +**/
> +EFI_STATUS
> +PmcSendCommand (
> +  IN  UINT8                    Command,
> +  IN  UINT8                    SubCmdId,
> +  IN  UINT8                    CmdSize,
> +  IN  PMC_IPC_COMMAND_BUFFER   *WriteBufPtr,
> +  OUT PMC_IPC_COMMAND_BUFFER   *ReadBufPtr
> +  )
> +{
> +  EFI_STATUS             Status;
> +  UINT32                 PchPwrmBase;
> +  UINT32                 IpcSts;
> +  UINTN                  Timeout;
> +
> +  DEBUG ((DEBUG_INFO, "PmcSendCommand(): IPC_COMMAND=0x%02X,
> IPC_SUB_CMD = 0x%02X, IPC_SIZE=0x%02X \n", Command, SubCmdId,
> CmdSize));
> +  DEBUG ((DEBUG_INFO, "WBUF0=0x%08X, WBUF1=0x%08X, WBUF2=0x%08X,
> WBUF3=0x%08X \n", WriteBufPtr->Buf0, WriteBufPtr->Buf1,
> WriteBufPtr->Buf2, WriteBufPtr->Buf3));
> +
> +  if (CmdSize > 16) {
> +    ASSERT (FALSE);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Program the Write Buffer 0 with the Data that needs to be written to PMC
> +  //
> +  PchPwrmBase = PmcGetPwrmBase ();
> +  MmioWrite32 ((PchPwrmBase + R_PMC_PWRM_IPC_WBUF0),
> WriteBufPtr->Buf0);
> +  MmioWrite32 ((PchPwrmBase + R_PMC_PWRM_IPC_WBUF1),
> WriteBufPtr->Buf1);
> +  MmioWrite32 ((PchPwrmBase + R_PMC_PWRM_IPC_WBUF2),
> WriteBufPtr->Buf2);
> +  MmioWrite32 ((PchPwrmBase + R_PMC_PWRM_IPC_WBUF3),
> WriteBufPtr->Buf3);
> +  //
> +  // Program the command register with command and size
> +  //
> +  MmioWrite32 (
> +    PchPwrmBase + R_PMC_PWRM_IPC_CMD,
> +    (UINT32) ((CmdSize << N_PMC_PWRM_IPC_CMD_SIZE) |
> +      (SubCmdId << N_PMC_PWRM_IPC_CMD_CMD_ID) |
> +      (Command << N_PMC_PWRM_IPC_CMD_COMMAND))
> +    );
> +
> +  //
> +  // Read the IPC_STS register to get BUSY or Error status
> +  //
> +  Timeout = 0;
> +  Status = EFI_SUCCESS;
> +  while (TRUE) {
> +    IpcSts = MmioRead32 (PchPwrmBase + R_PMC_PWRM_IPC_STS);
> +    if ((IpcSts & B_PMC_PWRM_IPC_STS_BUSY) == 0) {
> +      break;
> +    }
> +
> +    if (Timeout > (1000 * 100)) {
> +      Status = EFI_TIMEOUT;
> +      break;
> +    }
> +    MicroSecondDelay (10);
> +    Timeout++;
> +  }
> +
> +  if ((IpcSts & B_PMC_PWRM_IPC_STS_ERROR) != 0) {
> +    Status = EFI_DEVICE_ERROR;
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "PmcSendCommand() Error: IPC_STS=0x%08X\n",
> IpcSts));
> +    return Status;
> +  }
> +
> +  if (ReadBufPtr != NULL) {
> +    //
> +    // Fill the  ReadBuffer contents with the Data that needs to be read from
> PMC
> +    //
> +    ReadBufPtr->Buf0 = MmioRead32(PchPwrmBase +
> R_PMC_PWRM_IPC_RBUF0);
> +    ReadBufPtr->Buf1 = MmioRead32(PchPwrmBase +
> R_PMC_PWRM_IPC_RBUF1);
> +    ReadBufPtr->Buf2 = MmioRead32(PchPwrmBase +
> R_PMC_PWRM_IPC_RBUF2);
> +    ReadBufPtr->Buf3 = MmioRead32(PchPwrmBase +
> R_PMC_PWRM_IPC_RBUF3);
> +
> +    DEBUG ((DEBUG_INFO, "RBUF0=0x%08X, RBUF1=0x%08X, RBUF2=0x%08X,
> RBUF3=0x%08X \n", ReadBufPtr->Buf0, ReadBufPtr->Buf1, ReadBufPtr->Buf2,
> ReadBufPtr->Buf3));
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  This function checks if SCI interrupt is enabled
> +
> +  @retval SCI Enable state
> +**/
> +BOOLEAN
> +PmcIsSciEnabled (
> +  VOID
> +  )
> +{
> +  return ((IoRead8 (PmcGetAcpiBase () + R_ACPI_IO_PM1_CNT) &
> B_ACPI_IO_PM1_CNT_SCI_EN) != 0);
> +}
> +
> +/**
> +  This function triggers Software GPE
> +**/
> +VOID
> +PmcTriggerSwGpe (
> +  VOID
> +  )
> +{
> +  IoOr32 (PmcGetAcpiBase () + R_ACPI_IO_GPE_CNTL,
> B_ACPI_IO_GPE_CNTL_SWGPE_CTRL);
> +}
> +
> +/**
> +  Set PCH ACPI base address.
> +  The Address should not be 0 and should be 256 bytes aligned. It is IO space,
> so must not exceed 0xFFFF.
> +  Only address matching PcdAcpiBaseAddress is the acceptable value for ACPI
> IO Base
> +
> +  @param[in] Address                    Address for ACPI base address.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_INVALID_PARAMETER         Invalid base address passed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PmcSetAcpiBase (
> +  IN  UINT16                            Address
> +  )
> +{
> +
> +  if (Address != PcdGet16 (PcdAcpiBaseAddress)) {
> +    DEBUG ((DEBUG_ERROR, "PmcSetAcpiBase Error. Invalid Address: %x.\n",
> Address));
> +    ASSERT (FALSE);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  PsfSetPmcAbase (Address);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Set PCH PWRM base address.
> +  Only 0xFE000000 (PCH_PWRM_BASE_ADDRESS) is the acceptable value for
> PWRMBASE
> +
> +  @param[in] Address                    Address for PWRM base address.
> +
> +  @retval EFI_SUCCESS                   Successfully completed.
> +  @retval EFI_UNSUPPORTED               DMIC.SRL is set.
> +**/
> +EFI_STATUS
> +PmcSetPwrmBase (
> +  IN  UINT32                            Address
> +  )
> +{
> +  UINT64                                PmcBase;
> +
> +  if (Address != PCH_PWRM_BASE_ADDRESS) {
> +    DEBUG ((DEBUG_ERROR, "PmcSetPwrmBase Error. Invalid Address: %x.\n",
> Address));
> +    ASSERT (FALSE);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  PmcBase      = PCI_SEGMENT_LIB_ADDRESS (
> +                   DEFAULT_PCI_SEGMENT_NUMBER_PCH,
> +                   DEFAULT_PCI_BUS_NUMBER_PCH,
> +                   PCI_DEVICE_NUMBER_PCH_PMC,
> +                   PCI_FUNCTION_NUMBER_PCH_PMC,
> +                   0
> +                   );
> +  if (PciSegmentRead16 (PmcBase) == 0xFFFF) {
> +    ASSERT (FALSE);
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Disable PWRMBASE in PMC Device first before changing PWRM base
> address.
> +  //
> +  PciSegmentAnd16 (
> +    PmcBase + PCI_COMMAND_OFFSET,
> +    (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE
> +    );
> +
> +  //
> +  // Program PWRMBASE in PMC Device
> +  //
> +  PciSegmentAndThenOr32 (
> +    PmcBase + R_PMC_CFG_BASE,
> +    (UINT32) (~B_PMC_CFG_PWRM_BASE_MASK),
> +    Address
> +    );
> +
> +  //
> +  // Enable PWRMBASE in PMC Device
> +  //
> +  PciSegmentOr16 (
> +    PmcBase + PCI_COMMAND_OFFSET,
> +    EFI_PCI_COMMAND_MEMORY_SPACE
> +    );
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This function checks if function disable (static and non-static power gating)
> +  configuration is locked
> +
> +  @retval lock state
> +**/
> +BOOLEAN
> +PmcIsFunctionDisableConfigLocked (
> +  VOID
> +  )
> +{
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_ST_PG_FDIS_PMC_1) &
> B_PMC_PWRM_ST_PG_FDIS_PMC_1_ST_FDIS_LK) != 0);
> +}
> +
> +/**
> +  Check if MODPHY SUS PG is supported
> +
> +  @retval  Status of MODPHY SUS PG support
> +**/
> +BOOLEAN
> +PmcIsModPhySusPgSupported (
> +  VOID
> +  )
> +{
> +  if (IsPchLp ()) {
> +    //
> +    // MPHY SUS PG supported on PCH-LP only:
> +    //
> +    return TRUE;
> +  }
> +  return FALSE;
> +}
> +
> +/**
> +  This function checks if ISH is function disabled
> +  by static power gating
> +
> +  @retval ISH device state
> +**/
> +BOOLEAN
> +PmcIsIshFunctionDisabled (
> +  VOID
> +  )
> +{
> +  //
> +  // Get PG info from PWRMBASE + ST_PG_FDIS_PMC_1
> +  //
> +  return ((MmioRead32 ((UINTN) (PmcGetPwrmBase () +
> R_PMC_PWRM_ST_PG_FDIS_PMC_1)) &
> B_PMC_PWRM_ST_PG_FDIS_PMC_1_ISH_FDIS_PMC) != 0);
> +}
> +
> +/**
> +  This function checks if ISH device is supported (not disabled by fuse)
> +
> +  @retval ISH support state
> +**/
> +BOOLEAN
> +PmcIsIshSupported (
> +  VOID
> +  )
> +{
> +  //
> +  // Get fuse info from PWRMBASE + FUSE_DIS_RD_2
> +  //
> +  return ((MmioRead32 ((UINTN) (PmcGetPwrmBase () +
> R_PMC_PWRM_FUSE_DIS_RD_2)) &
> B_PMC_PWRM_FUSE_DIS_RD_2_ISH_FUSE_SS_DIS) == 0);
> +}
> +
> +/**
> +  This function disables ISH device by static power gating.
> +  For static power gating to take place Global Reset, G3 or DeepSx transition
> must happen.
> +**/
> +VOID
> +PmcStaticDisableIsh (
> +  VOID
> +  )
> +{
> +  //
> +  // Set PWRMBASE + ST_PG_FDIS_PMC_1[5] = 1b to statically disable ISH
> Controller
> +  //
> +  MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_ST_PG_FDIS_PMC_1,
> B_PMC_PWRM_ST_PG_FDIS_PMC_1_ISH_FDIS_PMC);
> +}
> +
> +/**
> +  This function enables ISH device by disabling static power gating.
> +  Static power gating disabling takes place after Global Reset, G3 or DeepSx
> transition.
> +**/
> +VOID
> +PmcEnableIsh (
> +  VOID
> +  )
> +{
> +  //
> +  // Set PWRMBASE + ST_PG_FDIS_PMC_1[5] = 0b to enable ISH controller
> +  //
> +  MmioAnd32 (PmcGetPwrmBase () + R_PMC_PWRM_ST_PG_FDIS_PMC_1,
> (UINT32) (~B_PMC_PWRM_ST_PG_FDIS_PMC_1_ISH_FDIS_PMC));
> +}
> +
> +/**
> +  This function checks if GbE is function disabled
> +  by static power gating
> +
> +  @retval GbE device state
> +**/
> +BOOLEAN
> +PmcIsGbeFunctionDisabled (
> +  VOID
> +  )
> +{
> +  //
> +  // Get PG info from PWRMBASE + ST_PG_FDIS_PMC_1
> +  //
> +  return ((MmioRead32 ((UINTN) (PmcGetPwrmBase () +
> R_PMC_PWRM_ST_PG_FDIS_PMC_1)) &
> B_PMC_PWRM_ST_PG_FDIS_PMC_1_GBE_FDIS_PMC) != 0);
> +}
> +
> +/**
> +  This function disables GbE device by static power gating and enables
> ModPHY SPD gating (PCH-LP only).
> +  For static power gating to take place Global Reset, G3 or DeepSx transition
> must happen.
> +**/
> +VOID
> +PmcStaticDisableGbe (
> +  VOID
> +  )
> +{
> +  UINT32 PchPwrmBase;
> +  PchPwrmBase = PmcGetPwrmBase ();
> +  //
> +  // Set PWRMBASE + ST_PG_FDIS_PMC_1[0] = 1b to statically disable GbE
> Controller
> +  //
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_ST_PG_FDIS_PMC_1,
> B_PMC_PWRM_ST_PG_FDIS_PMC_1_GBE_FDIS_PMC);
> +
> +  if (PmcIsModPhySusPgSupported ()) {
> +    //
> +    // Set MSPDRTREQ:
> +    // PWRMBASE + R_PWRM_MODPHY_PM_CFG5[13] = 1 to enable ASL code
> trigger request for ModPHY SPD gating.
> +    //
> +    PmcGbeModPhyPowerGating ();
> +  }
> +}
> +
> +/**
> +  This function enables GbE device by disabling static power gating.
> +  Static power gating disabling takes place after Global Reset, G3 or DeepSx
> transition.
> +**/
> +VOID
> +PmcEnableGbe (
> +  VOID
> +  )
> +{
> +  //
> +  // Set PWRMBASE + ST_PG_FDIS_PMC_1[0] = 0b to enable GbE controller
> +  //
> +  MmioAnd32 (PmcGetPwrmBase () + R_PMC_PWRM_ST_PG_FDIS_PMC_1,
> (UINT32) ~B_PMC_PWRM_ST_PG_FDIS_PMC_1_GBE_FDIS_PMC);
> +}
> +
> +/**
> +  This function checks if GbE device is supported (not disabled by fuse)
> +
> +  @retval GbE support state
> +**/
> +BOOLEAN
> +PmcIsGbeSupported (
> +  VOID
> +  )
> +{
> +  //
> +  // Get fuse info from PWRMBASE + FUSE_SS_DIS_RD_2
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_FUSE_DIS_RD_2) &
> B_PMC_PWRM_FUSE_DIS_RD_2_GBE_FUSE_SS_DIS) == 0);
> +}
> +
> +/**
> +  This function disables (non-static power gating) HDA device
> +**/
> +VOID
> +PmcDisableHda (
> +  VOID
> +  )
> +{
> +  MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_NST_PG_FDIS_1,
> B_PMC_PWRM_NST_PG_FDIS_1_ADSP_FDIS_PMC);
> +}
> +
> +/**
> +  This function checks if Cnvi device is supported (not disabled by fuse)
> +
> +  @retval Cnvi support state
> +**/
> +BOOLEAN
> +PmcIsCnviSupported (
> +  VOID
> +  )
> +{
> +  //
> +  // Get fuse info from PWRMBASE + FUSE_SS_DIS_RD_2
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_FUSE_DIS_RD_2) &
> B_PMC_PWRM_FUSE_DIS_RD_2_CNVI_FUSE_SS_DIS) == 0);
> +}
> +
> +/**
> +  This function checks if CNVi is function disabled
> +  by static power gating
> +
> +  @retval GbE device state
> +**/
> +BOOLEAN
> +PmcIsCnviFunctionDisabled (
> +  VOID
> +  )
> +{
> +  //
> +  // Get PG info from PWRMBASE + ST_PG_FDIS_PMC_1
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_ST_PG_FDIS_PMC_1) &
> B_PMC_PWRM_ST_PG_FDIS_PMC_1_CNVI_FDIS_PMC) != 0);
> +}
> +
> +/**
> +  This function enables CNVi device by disabling static power gating.
> +  Static power gating disabling takes place after Global Reset, G3 or DeepSx
> transition.
> +**/
> +VOID
> +PmcEnableCnvi (
> +  VOID
> +  )
> +{
> +  //
> +  // Set PWRMBASE + ST_PG_FDIS_PMC_1 to enable CNVi controller
> +  //
> +  MmioAnd32 (PmcGetPwrmBase () + R_PMC_PWRM_ST_PG_FDIS_PMC_1,
> (UINT32) ~B_PMC_PWRM_ST_PG_FDIS_PMC_1_CNVI_FDIS_PMC);
> +}
> +
> +/**
> +  This function disables CNVi device by static power gating.
> +  For static power gating to take place Global Reset, G3 or DeepSx transition
> must happen.
> +**/
> +VOID
> +PmcStaticDisableCnvi (
> +  VOID
> +  )
> +{
> +  MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_ST_PG_FDIS_PMC_1,
> B_PMC_PWRM_ST_PG_FDIS_PMC_1_CNVI_FDIS_PMC);
> +}
> +
> +/**
> +  This function disables (non-static power gating) PCIe Root Port and enables
> ModPHY SPD gating (PCH-LP only).
> +
> +  @param[in] RpIndex        PCIe Root Port Index (0 based)
> +**/
> +VOID
> +PmcDisablePcieRootPort (
> +  IN UINT32  RpIndex
> +  )
> +{
> +  UINT32   NstPgFdis1Mask;
> +  UINT32   PchPwrmBase;
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +  //
> +  // Set PchPwrmBase + NST_PG_FDIS_1 to function disable PCIE port in PMC
> +  //
> +  if (IsPchH () && RpIndex >= 20) {
> +    NstPgFdis1Mask =
> B_PCH_H_PMC_PWRM_NST_PG_FDIS_1_PCIE_F0_FDIS_PMC << (RpIndex %
> 20);
> +  } else {
> +    NstPgFdis1Mask = B_PMC_PWRM_NST_PG_FDIS_1_PCIE_A0_FDIS_PMC
> << RpIndex;
> +  }
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_NST_PG_FDIS_1,
> NstPgFdis1Mask);
> +
> +  if (PmcIsModPhySusPgSupported ()) {
> +    //
> +    // Set MSPDRTREQ:
> +    // PWRMBASE + R_PWRM_MODPHY_PM_CFG5[26:0] = 1 to enable ASL
> code trigger request for ModPHY SPD gating.
> +    //
> +    if (RpIndex <= 11) {
> +      MmioOr32 (PchPwrmBase + R_PMC_PWRM_MODPHY_PM_CFG5,
> B_PMC_PWRM_MODPHY_PM_CFG5_MSPDRTREQ_A0 << RpIndex);
> +    } else {
> +      MmioOr32 (PchPwrmBase + R_PMC_PWRM_MODPHY_PM_CFG5,
> B_PMC_PWRM_MODPHY_PM_CFG5_MSPDRTREQ_D0 << (RpIndex - 12));
> +    }
> +  }
> +}
> +
> +/**
> +  This function disables (non-static power gating) xHCI and enables ModPHY
> SPD gating (PCH-LP only).
> +**/
> +VOID
> +PmcDisableXhci (
> +  VOID
> +  )
> +{
> +  UINT32   PchPwrmBase;
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  //
> +  // Set PWRMBASE + NST_PG_FDIS_1 [0] = 1b
> +  //
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_NST_PG_FDIS_1,
> B_PMC_PWRM_NST_PG_FDIS_1_XHCI_FDIS_PMC);
> +
> +  if (PmcIsModPhySusPgSupported ()) {
> +    //
> +    // Set MSPDRTREQ:
> +    // PchPwrmBase + R_PWRM_MODPHY_PM_CFG5[14] = 1 to enable ASL
> code trigger request for ModPHY SPD gating.
> +    //
> +    MmioOr32 (PchPwrmBase + R_PMC_PWRM_MODPHY_PM_CFG5,
> B_PMC_PWRM_MODPHY_PM_CFG5_MSPDRTREQ_XHCI);
> +  }
> +}
> +
> +/**
> +  This function disables (non-static power gating) XDCI and enables ModPHY
> SPD gating (PCH-LP only).
> +**/
> +VOID
> +PmcDisableXdci (
> +  VOID
> +  )
> +{
> +  UINT32 PchPwrmBase;
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  //
> +  // Set PWRMBASE + NST_PG_FDIS_1 [26] = 1b to disable XDCI Controller in
> PMC
> +  //
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_NST_PG_FDIS_1,
> B_PMC_PWRM_NST_PG_FDIS_1_XDCI_FDIS_PMC);
> +
> +  if (PmcIsModPhySusPgSupported ()) {
> +    //
> +    // Set MSPDRTREQ:
> +    // PWRMBASE + R_PWRM_MODPHY_PM_CFG5[15] = 1 to enable ASL code
> trigger request for ModPHY SPD gating.
> +    //
> +    MmioOr32 (PchPwrmBase + R_PMC_PWRM_MODPHY_PM_CFG5,
> B_PMC_PWRM_MODPHY_PM_CFG5_MSPDRTREQ_XDCI);
> +  }
> +}
> +
> +/**
> +  This function checks if XDCI device is supported (not disabled by fuse)
> +
> +  @retval XDCI support state
> +**/
> +BOOLEAN
> +PmcIsXdciSupported (
> +  VOID
> +  )
> +{
> +  //
> +  // Get fuse info from PWRMBASE + FUSE_SS_DIS_RD_2
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_FUSE_DIS_RD_2) &
> B_PMC_PWRM_FUSE_DIS_RD_2_OTG_FUSE_SS_DIS) == 0);
> +}
> +
> +/**
> +  This function locks HOST SW power gating control
> +**/
> +VOID
> +PmcLockHostSwPgCtrl (
> +  VOID
> +  )
> +{
> +  MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_HSWPGCR1,
> B_PMC_PWRM_SW_PG_CTRL_LOCK);
> +}
> +
> +/**
> +  This function checks if HOST SW Power Gating Control is locked
> +
> +  @retval lock state
> +**/
> +BOOLEAN
> +PmcIsHostSwPgCtrlLocked (
> +  VOID
> +  )
> +{
> +  //
> +  // Get lock info from PWRMBASE + HSWPGCR1
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () + R_PMC_PWRM_HSWPGCR1)
> & B_PMC_PWRM_SW_PG_CTRL_LOCK) != 0);
> +}
> +
> +/**
> +  This function checks if LAN wake from DeepSx is enabled
> +
> +  @retval Lan Wake state
> +**/
> +BOOLEAN
> +PmcIsLanDeepSxWakeEnabled (
> +  VOID
> +  )
> +{
> +  //
> +  // Get wake info from PWRMBASE + DSX_CFG
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () + R_PMC_PWRM_DSX_CFG) &
> (UINT32) B_PMC_PWRM_DSX_CFG_LAN_WAKE_EN) != 0);
> +}
> +
> +/**
> +  Disables USB2 Core PHY PowerGating during power on for Chipsetinit table
> update
> +**/
> +VOID
> +PmcUsb2CorePhyPowerGatingDisable (
> +  VOID
> +  )
> +{
> +  MmioAnd32 (PmcGetPwrmBase () + R_PMC_PWRM_CFG, (UINT32)
> ~B_PMC_PWRM_CFG_ALLOW_USB2_CORE_PG);
> +}
> +
> +
> +/**
> +  This function reads CPU Early Power-on Configuration (EPOC)
> +
> +  @retval CPU EPOC value
> +**/
> +UINT32
> +PmcGetCpuEpoc (
> +  VOID
> +  )
> +{
> +  return MmioRead32 (PmcGetPwrmBase () + R_PMC_PWRM_CPU_EPOC);
> +}
> +
> +/**
> +  This function sets CPU Early Power-on Configuration (EPOC)
> +
> +  @param[in] CpuEpocValue      CPU EPOC value
> +**/
> +VOID
> +PmcSetCpuEpoc (
> +  IN UINT32     CpuEpocValue
> +  )
> +{
> +  MmioWrite32 (PmcGetPwrmBase () + R_PMC_PWRM_CPU_EPOC,
> CpuEpocValue);
> +}
> +
> +/**
> +  This function sets DRAM_RESET# Control Pin value
> +
> +  @param[in] DramResetVal      0: Pin output is low
> +                               1: Pin output is tri-stated
> +**/
> +VOID
> +PmcSetDramResetCtlState (
> +  IN UINT32     DramResetVal
> +  )
> +{
> +  ASSERT (DramResetVal < 2);
> +
> +  MmioAndThenOr32 (
> +    PmcGetPwrmBase () + R_PMC_PWRM_CFG2,
> +    (UINT32)~B_PMC_PWRM_CFG2_DRAM_RESET_CTL,
> +    DramResetVal << N_PMC_PWRM_CFG2_DRAM_RESET_CTL
> +    );
> +}
> +
> +/**
> +  This function enables triggering Global Reset of both
> +  the Host and the ME partitions after CF9h write of 6h or Eh
> +**/
> +VOID
> +PmcEnableCf9GlobalReset (
> +  VOID
> +  )
> +{
> +  MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_ETR3, (UINT32)
> (B_PMC_PWRM_ETR3_CF9GR));
> +}
> +
> +/**
> +  This function disables triggering Global Reset of both
> +  the Host and the ME partitions after CF9h write of 6h or Eh.
> +**/
> +VOID
> +PmcDisableCf9GlobalReset (
> +  VOID
> +  )
> +{
> +  MmioAnd32 (PmcGetPwrmBase () + R_PMC_PWRM_ETR3, (UINT32)
> ~B_PMC_PWRM_ETR3_CF9GR);
> +}
> +
> +/**
> +  This function disables triggering Global Reset of both
> +  the Host and the ME partitions after CF9h write of 6h or Eh.
> +  Global Reset configuration is locked after programming
> +**/
> +VOID
> +PmcDisableCf9GlobalResetWithLock (
> +  VOID
> +  )
> +{
> +  MmioAndThenOr32 (
> +    PmcGetPwrmBase () + R_PMC_PWRM_ETR3,
> +    (UINT32) ~B_PMC_PWRM_ETR3_CF9GR,
> +    (UINT32) B_PMC_PWRM_ETR3_CF9LOCK
> +    );
> +}
> +
> +/**
> +  This function disables CF9 reset without Resume Well reset.
> +  Cf9 0x6/0xE reset will also reset resume well logic.
> +**/
> +VOID
> +PmcDisableCf9ResetWithoutResumeWell (
> +  VOID
> +  )
> +{
> +
> +  MmioAnd32 (PmcGetPwrmBase () + R_PMC_PWRM_ETR3, (UINT32)
> ~B_PMC_PWRM_ETR3_CWORWRE);
> +}
> +
> +/**
> +  This function clears RTC Power Failure status (RTC_PWR_FLR)
> +**/
> +VOID
> +PmcClearRtcPowerFailureStatus (
> +  VOID
> +  )
> +{
> +  //
> +  // Set B_PMC_PWRM_GEN_PMCON_B_RTC_PWR_STS to 0 to clear it.
> +  //
> +  MmioAnd8 ((UINTN) (PmcGetPwrmBase () +
> R_PMC_PWRM_GEN_PMCON_B), (UINT8)
> (~B_PMC_PWRM_GEN_PMCON_B_RTC_PWR_STS));
> +}
> +
> +/**
> +  This function enables PCI Express* PME events
> +**/
> +VOID
> +PmcEnablePciExpressPmeEvents (
> +  VOID
> +  )
> +{
> +  MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_GEN_PMCON_B,
> B_PMC_PWRM_GEN_PMCON_B_BIOS_PCI_EXP_EN);
> +}
> +
> +/**
> +  This function sets eSPI SMI Lock
> +**/
> +VOID
> +PmcLockEspiSmi (
> +  VOID
> +  )
> +{
> +  MmioAndThenOr8 (PmcGetPwrmBase () + R_PMC_PWRM_GEN_PMCON_A
> + 1,
> +    (UINT8) ~((B_PMC_PWRM_GEN_PMCON_A_PWR_FLR |
> B_PMC_PWRM_GEN_PMCON_A_HOST_RST_STS) >> 8),
> +    B_PMC_PWRM_GEN_PMCON_A_ESPI_SMI_LOCK >> 8
> +    );
> +}
> +
> +/**
> +  This function checks if eSPI SMI Lock is set
> +
> +  @retval eSPI SMI Lock state
> +**/
> +BOOLEAN
> +PmcIsEspiSmiLockSet (
> +  VOID
> +  )
> +{
> +  return ((MmioRead32 ((UINTN) (PmcGetPwrmBase () +
> R_PMC_PWRM_GEN_PMCON_A)) &
> B_PMC_PWRM_GEN_PMCON_A_ESPI_SMI_LOCK) != 0);
> +}
> +
> +/**
> +  This function sets SW SMI Rate.
> +
> +  @param[in] SwSmiRate        Refer to PMC_SWSMI_RATE for possible
> values
> +**/
> +VOID
> +PmcSetSwSmiRate (
> +  IN PMC_SWSMI_RATE          SwSmiRate
> +  )
> +{
> +  UINT32        PchPwrmBase;
> +  STATIC UINT8  SwSmiRateRegVal[4] = {
> +    V_PMC_PWRM_GEN_PMCON_A_SWSMI_RTSL_1_5MS,
> +    V_PMC_PWRM_GEN_PMCON_A_SWSMI_RTSL_16MS,
> +    V_PMC_PWRM_GEN_PMCON_A_SWSMI_RTSL_32MS,
> +    V_PMC_PWRM_GEN_PMCON_A_SWSMI_RTSL_64MS
> +  };
> +
> +  ASSERT (SwSmiRate <= PmcSwSmiRate64ms);
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  //
> +  // SWSMI_RATE_SEL BIT (PWRMBASE offset 1020h[7:6]) bits are in RTC well
> +  //
> +  MmioAndThenOr8 (
> +    PchPwrmBase + R_PMC_PWRM_GEN_PMCON_A,
> +    (UINT8)~B_PMC_PWRM_GEN_PMCON_A_SWSMI_RTSL,
> +    SwSmiRateRegVal[SwSmiRate]
> +    );
> +}
> +
> +/**
> +  This function sets Periodic SMI Rate.
> +
> +  @param[in] PeriodicSmiRate        Refer to PMC_PERIODIC_SMI_RATE for
> possible values
> +**/
> +VOID
> +PmcSetPeriodicSmiRate (
> +  IN PMC_PERIODIC_SMI_RATE    PeriodicSmiRate
> +  )
> +{
> +  UINT32        PchPwrmBase;
> +  STATIC UINT8  PeriodicSmiRateRegVal[4] = {
> +    V_PMC_PWRM_GEN_PMCON_A_PER_SMI_8S,
> +    V_PMC_PWRM_GEN_PMCON_A_PER_SMI_16S,
> +    V_PMC_PWRM_GEN_PMCON_A_PER_SMI_32S,
> +    V_PMC_PWRM_GEN_PMCON_A_PER_SMI_64S
> +  };
> +
> +  ASSERT (PeriodicSmiRate <= PmcPeriodicSmiRate64s);
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  MmioAndThenOr8 (
> +    PchPwrmBase + R_PMC_PWRM_GEN_PMCON_A,
> +    (UINT8)~B_PMC_PWRM_GEN_PMCON_A_PER_SMI_SEL,
> +    PeriodicSmiRateRegVal[PeriodicSmiRate]
> +    );
> +}
> +
> +/**
> +  This function reads Power Button Level
> +
> +  @retval State of PWRBTN# signal (0: Low, 1: High)
> +**/
> +UINT8
> +PmcGetPwrBtnLevel (
> +  VOID
> +  )
> +{
> +  if (MmioRead32 (PmcGetPwrmBase () + R_PMC_PWRM_GEN_PMCON_B) &
> B_PMC_PWRM_GEN_PMCON_B_PWRBTN_LVL) {
> +    return 1;
> +  } else {
> +    return 0;
> +  }
> +}
> +
> +/**
> +  This function gets Group to GPE0 configuration
> +
> +  @param[out] GpeDw0Value       GPIO Group to GPE_DW0 assignment
> +  @param[out] GpeDw1Value       GPIO Group to GPE_DW1 assignment
> +  @param[out] GpeDw2Value       GPIO Group to GPE_DW2 assignment
> +**/
> +VOID
> +PmcGetGpioGpe (
> +  OUT UINT32    *GpeDw0Value,
> +  OUT UINT32    *GpeDw1Value,
> +  OUT UINT32    *GpeDw2Value
> +  )
> +{
> +  UINT32 Data32;
> +
> +  Data32 = MmioRead32 ((UINTN) (PmcGetPwrmBase () +
> R_PMC_PWRM_GPIO_CFG));
> +
> +  *GpeDw0Value = ((Data32 & B_PMC_PWRM_GPIO_CFG_GPE0_DW0) >>
> N_PMC_PWRM_GPIO_CFG_GPE0_DW0);
> +  *GpeDw1Value = ((Data32 & B_PMC_PWRM_GPIO_CFG_GPE0_DW1) >>
> N_PMC_PWRM_GPIO_CFG_GPE0_DW1);
> +  *GpeDw2Value = ((Data32 & B_PMC_PWRM_GPIO_CFG_GPE0_DW2) >>
> N_PMC_PWRM_GPIO_CFG_GPE0_DW2);
> +}
> +
> +/**
> +  This function sets Group to GPE0 configuration
> +
> +  @param[out] GpeDw0Value       GPIO Group to GPE_DW0 assignment
> +  @param[out] GpeDw1Value       GPIO Group to GPE_DW1 assignment
> +  @param[out] GpeDw2Value       GPIO Group to GPE_DW2 assignment
> +**/
> +VOID
> +PmcSetGpioGpe (
> +  IN UINT32    GpeDw0Value,
> +  IN UINT32    GpeDw1Value,
> +  IN UINT32    GpeDw2Value
> +  )
> +{
> +  UINT32               Data32Or;
> +  UINT32               Data32And;
> +
> +  //
> +  // Program GPIO_CFG register
> +  //
> +  Data32And = (UINT32) ~(B_PMC_PWRM_GPIO_CFG_GPE0_DW2 |
> B_PMC_PWRM_GPIO_CFG_GPE0_DW1 |
> B_PMC_PWRM_GPIO_CFG_GPE0_DW0);
> +  Data32Or  = (UINT32) ((GpeDw2Value <<
> N_PMC_PWRM_GPIO_CFG_GPE0_DW2) |
> +                        (GpeDw1Value << N_PMC_PWRM_GPIO_CFG_GPE0_DW1)
> |
> +                        (GpeDw0Value <<
> N_PMC_PWRM_GPIO_CFG_GPE0_DW0));
> +
> +  MmioAndThenOr32 (
> +    (PmcGetPwrmBase () + R_PMC_PWRM_GPIO_CFG),
> +    Data32And,
> +    Data32Or
> +    );
> +}
> +
> +/**
> +  Disable SLP_S0# assertion when system is in debug mode
> +**/
> +VOID
> +PmcDisableSlpS0AssertionInDebugMode (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                Status;
> +  PMC_IPC_COMMAND_BUFFER    Wbuf;
> +
> +  ZeroMem (&Wbuf, sizeof (PMC_IPC_COMMAND_BUFFER));
> +
> +  Status = PmcSendCommand
> (V_PMC_PWRM_IPC_CMD_COMMAND_SLP_CTRL, 0, 4, &Wbuf, NULL);
> +  ASSERT_EFI_ERROR (Status);
> +}
> +
> +/**
> +  Enable SLP_S0# assertion even when system is in debug mode
> +**/
> +VOID
> +PmcEnableSlpS0AssertionInDebugMode (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                Status;
> +  PMC_IPC_COMMAND_BUFFER    Wbuf;
> +
> +  ZeroMem (&Wbuf, sizeof (PMC_IPC_COMMAND_BUFFER));
> +
> +  Wbuf.Buf0 = 1;
> +  Status = PmcSendCommand
> (V_PMC_PWRM_IPC_CMD_COMMAND_SLP_CTRL, 0, 4, &Wbuf, NULL);
> +  ASSERT_EFI_ERROR (Status);
> +}
> +
> +/**
> +  This function gets NMI regsiter.
> +
> +  @retval  NMI register setting
> +**/
> +UINT32
> +PmcGetNmiControl (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                Status;
> +  PMC_IPC_COMMAND_BUFFER    Wbuf;
> +  PMC_IPC_COMMAND_BUFFER    Rbuf;
> +
> +  ZeroMem (&Wbuf, sizeof (PMC_IPC_COMMAND_BUFFER));
> +  ZeroMem (&Rbuf, sizeof (PMC_IPC_COMMAND_BUFFER));
> +  //
> +  // WBUF0 = 2 for NMI delivery control and status register (entire register
> PCR[ITSS] 0x3330)
> +  //
> +  Wbuf.Buf0 = V_PMC_PWRM_IPC_CMD_WBUF0_PROXY_NMI;
> +  Status = PmcSendCommand (
> +             V_PMC_PWRM_IPC_CMD_COMMAND_PROXY,
> +             V_PMC_PWRM_IPC_CMD_CMD_ID_PROXY_READ,
> +             4,
> +             &Wbuf,
> +             &Rbuf
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +  return Rbuf.Buf0;
> +}
> +
> +/**
> +  This function sets the NMI register
> +
> +  @param[in]  NmiRegister    The whole NMI register
> +**/
> +VOID
> +PmcSetNmiControl (
> +  UINT32   NmiRegister
> +  )
> +{
> +  EFI_STATUS                Status;
> +  PMC_IPC_COMMAND_BUFFER    Wbuf;
> +
> +  ZeroMem (&Wbuf, sizeof (PMC_IPC_COMMAND_BUFFER));
> +  //
> +  // WBUF0 = 2 for NMI delivery control and status register (entire register
> PCR[ITSS] 0x3330)
> +  //
> +  Wbuf.Buf0 = V_PMC_PWRM_IPC_CMD_WBUF0_PROXY_NMI;
> +  Wbuf.Buf1 = NmiRegister;
> +  Status = PmcSendCommand (
> +             V_PMC_PWRM_IPC_CMD_COMMAND_PROXY,
> +             V_PMC_PWRM_IPC_CMD_CMD_ID_PROXY_WRITE,
> +             8,
> +             &Wbuf,
> +             NULL
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +}
> +
> +/**
> +  This function enables GBE ModPHY SPD gating.
> +**/
> +VOID
> +PmcGbeModPhyPowerGating (
> +  VOID
> +  )
> +{
> +  if (PmcIsModPhySusPgSupported ()) {
> +    //
> +    // Set B_PCH_PWRM_MODPHY_PM_CFG5_MSPDRTREQ_GBE ModPHY
> SPD RT Request
> +    //
> +    MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_MODPHY_PM_CFG5,
> B_PMC_PWRM_MODPHY_PM_CFG5_MSPDRTREQ_GBE);
> +  }
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibClient.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibClient.c
> new file mode 100644
> index 0000000000..2411a2be23
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibClient.c
> @@ -0,0 +1,73 @@
> +/** @file
> +  PCH PMC Private Library implementation for Cannon Lake PCH.
> +  All function in this library is available for PEI, DXE, and SMM,
> +  But do not support UEFI RUNTIME environment call.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Private/Library/PmcPrivateLib.h>
> +#include <Library/SataLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Register/PchRegsPmc.h>
> +
> +#include "PmcPrivateLibInternal.h"
> +
> +/**
> +  This function disables (non-static power gating) SATA and enables ModPHY
> SPD gating (PCH-LP only).
> +
> +  @param[in]  SataCtrlIndex     SATA controller index
> +**/
> +VOID
> +PmcDisableSata (
> +  IN UINT32     SataCtrlIndex
> +  )
> +{
> +  UINT32 PchPwrmBase;
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  ASSERT (SataCtrlIndex < GetPchMaxSataControllerNum ());
> +
> +  //
> +  // Set PWRMBASE + NST_PG_FDIS_1 [22] = 1b to disable SATA Controller in
> PMC
> +  //
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_NST_PG_FDIS_1,
> B_PMC_PWRM_NST_PG_FDIS_1_SATA_FDIS_PMC);
> +
> +  if (PmcIsModPhySusPgSupported ()) {
> +    //
> +    // MPHY SUS PG supported on PCH-LP only:
> +    //
> +    // Set MSPDRTREQ:
> +    // PWRMBASE + R_PWRM_MODPHY_PM_CFG5[12] = 1 to enable ASL code
> trigger request for ModPHY SPD gating.
> +    //
> +    MmioOr32 (PchPwrmBase + R_PMC_PWRM_MODPHY_PM_CFG5,
> B_PMC_PWRM_MODPHY_PM_CFG5_MSPDRTREQ_SATA);
> +  }
> +}
> +
> +/**
> +  This function checks if SATA device is supported (not disabled by fuse)
> +
> +  @param[in] SataCtrlIndex SATA controller index
> +
> +  @retval SATA support state
> +**/
> +BOOLEAN
> +PmcIsSataSupported (
> +  UINT32  SataCtrlIndex
> +  )
> +{
> +  ASSERT (SataCtrlIndex < GetPchMaxSataControllerNum ());
> +
> +  //
> +  // Get fuse info from PWRMBASE + FUSE_SS_DIS_RD_2
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_FUSE_DIS_RD_2) &
> B_PMC_PWRM_FUSE_DIS_RD_2_SATA_FUSE_SS_DIS) == 0);
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibCnl.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibCnl.c
> new file mode 100644
> index 0000000000..847be42937
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibCnl.c
> @@ -0,0 +1,360 @@
> +/** @file
> +  PCH PMC Private Library implementation for Cannon Lake PCH.
> +  All function in this library is available for PEI, DXE, and SMM,
> +  But do not support UEFI RUNTIME environment call.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Private/Library/PmcPrivateLib.h>
> +#include <Library/SataLib.h>
> +#include <Library/PchInfoLib.h>
> +#include <Register/PchRegsPmc.h>
> +
> +#include "PmcPrivateLibInternal.h"
> +
> +/**
> +  This function disables Trace Hub by enabling power gating
> +**/
> +VOID
> +PmcDisableTraceHub (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                Status;
> +  PMC_IPC_COMMAND_BUFFER    Wbuf;
> +
> +  ZeroMem (&Wbuf, sizeof (PMC_IPC_COMMAND_BUFFER));
> +
> +  Wbuf.Buf0 = BIT0;
> +  Status = PmcSendCommand
> (V_PMC_PWRM_IPC_CMD_COMMAND_NPK_STATE, 0, 4, &Wbuf, NULL);
> +  ASSERT_EFI_ERROR (Status);
> +}
> +
> +/**
> +  This function enables Trace Hub by disabling power gating
> +**/
> +VOID
> +PmcEnableTraceHub (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                Status;
> +  PMC_IPC_COMMAND_BUFFER    Wbuf;
> +
> +  ZeroMem (&Wbuf, sizeof (PMC_IPC_COMMAND_BUFFER));
> +
> +  Wbuf.Buf0 = BIT1;
> +  Status = PmcSendCommand
> (V_PMC_PWRM_IPC_CMD_COMMAND_NPK_STATE, 0, 4, &Wbuf, NULL);
> +  ASSERT_EFI_ERROR (Status);
> +}
> +
> +/**
> +  This function is part of PMC init and configures which clock wake signals
> should
> +  set the SLOW_RING, SA, FAST_RING_CF and SLOW_RING_CF indication sent
> up to the CPU/PCH
> +**/
> +VOID
> +PmcInitClockWakeEnable (
> +  VOID
> +  )
> +{
> +  UINT32                    PchPwrmBase;
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +  if (IsPchLp () && (PchStepping () < PCH_B0)) {
> +    ///
> +    /// PWRMBASE + 0x1880 = 0x0
> +    ///
> +    MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SLOW_RING,
> 0x0);
> +  } else {
> +    ///
> +    /// PWRMBASE + 0x1880 = 0x2F8FBB01
> +    ///
> +    MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SLOW_RING,
> 0x2F8FBB01);
> +  }
> +
> +  if (IsPchLp ()) {
> +    if (PchStepping () < PCH_B0) {
> +      ///
> +      /// PWRMBASE + 0x1884 = 0x0
> +      ///
> +      MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SLOW_RING2,
> 0x0);
> +    } else {
> +      ///
> +      /// PWRMBASE + 0x1884
> +      ///  PCH-LP: 0x0280C7E1
> +      ///
> +      MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SLOW_RING2,
> 0x0280C7E1);
> +    }
> +  } else {
> +    ///
> +    /// PWRMBASE + 0x1884
> +    ///  PCH-H:  0x0280D7E1
> +    ///
> +    MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SLOW_RING2,
> 0x0280D7E1);
> +  }
> +
> +  if (IsPchLp () && (PchStepping () < PCH_B0)) {
> +    ///
> +    /// PWRMBASE + 0x1888 = 0x0
> +    ///
> +    MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SA, 0x0);
> +    ///
> +    /// PWRMBASE + 0x188C = 0x0
> +    ///
> +    MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SA2, 0x0);
> +  } else {
> +    ///
> +    /// PWRMBASE + 0x1888 = 0x2F8FAB01
> +    ///
> +    MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SA, 0x2F8FAB01);
> +
> +    ///
> +    /// PWRMBASE + 0x188C
> +    ///  PCH-LP: 0x0280C7E1
> +    ///  PCH-H:  0x0280D7E1
> +    ///
> +    if (IsPchLp ()) {
> +      MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SA2,
> 0x0280C7E1);
> +    } else {
> +      MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SA2,
> 0x0280D7E1);
> +    }
> +  }
> +
> +  if (IsPchLp () && (PchStepping () < PCH_B0)) {
> +    ///
> +    /// PWRMBASE + 0x1898 = 0x0
> +    ///
> +    MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SLOW_RING_CF,
> 0x0);
> +  } else {
> +    ///
> +    /// PWRMBASE + 0x1898 = 0x00018000
> +    ///
> +    MmioWrite32 (PchPwrmBase + R_PMC_PWRM_EN_CW_SLOW_RING_CF,
> 0x00018000);
> +  }
> +}
> +
> +/**
> +  This function configures PWRMBASE + 0x1E00 register
> +**/
> +VOID
> +PmcConfigureRegPwrm1E00 (
> +  VOID
> +  )
> +{
> +  ///
> +  /// PWRMBASE + 0x1E00[31,30] = 1,1
> +  /// PWRMBASE + 0x1E00[29] = 0
> +  /// PWRMBASE + 0x1E00[10:6] = 0
> +  /// PWRMBASE + 0x1E00[3:0] = 2
> +  ///
> +  MmioAndThenOr32 (
> +    PmcGetPwrmBase () + R_PMC_PWRM_1E00,
> +    (UINT32) ~(BIT29 | (0x1F << 6) | 0xF),
> +    BIT31 | BIT30 | 2
> +    );
> +}
> +
> +/**
> +  This function configures Misc PM_SYNC events settings
> +**/
> +VOID
> +PmcConfigurePmSyncEventsSettings (
> +  VOID
> +  )
> +{
> +  ///
> +  /// PWRMBASE + 0x18C0 = 0x00000A20
> +  ///
> +  MmioWrite32 (PmcGetPwrmBase () + R_PMC_PWRM_EN_MISC_EVENT,
> 0x00000A20);
> +}
> +
> +/**
> +  This function enables all SerailIo devices.
> +  Static power gating disabling takes place after Global Reset, G3 or DeepSx
> transition.
> +**/
> +VOID
> +PmcEnableSerialIo (
> +  VOID
> +  )
> +{
> +  //
> +  // Set PWRMBASE + ST_PG_FDIS_PMC_2
> +  //
> +  MmioAnd32 (PmcGetPwrmBase () + R_PMC_PWRM_ST_PG_FDIS_PMC_2,
> (UINT32)~B_PMC_PWRM_ST_PG_FDIS_PMC_2_SERIALIO);
> +}
> +
> +/**
> +  This function disables (static power gating) all SerailIo devices.
> +  For SerialIo controllers they can be power gated only if all of them are to be
> disabled.
> +  They cannot be statically power gated separately.
> +  For static power gating to take place Global Reset, G3 or DeepSx transition
> must happen.
> +**/
> +VOID
> +PmcStaticDisableSerialIo (
> +  VOID
> +  )
> +{
> +  //
> +  // Set PWRMBASE + ST_PG_FDIS_PMC_2
> +  //
> +  MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_ST_PG_FDIS_PMC_2,
> B_PMC_PWRM_ST_PG_FDIS_PMC_2_SERIALIO);
> +}
> +
> +/**
> +  This function checks if all SerialIo devices are statically disabled (static
> power gating)
> +
> +  @retval SerialIo disable state
> +**/
> +BOOLEAN
> +PmcIsSerialIoStaticallyDisabled (
> +  VOID
> +  )
> +{
> +  //
> +  // Check if all SerialIo controllers are statically disabled in PMC
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_ST_PG_FDIS_PMC_2) &
> B_PMC_PWRM_ST_PG_FDIS_PMC_2_SERIALIO) ==
> B_PMC_PWRM_ST_PG_FDIS_PMC_2_SERIALIO);
> +}
> +
> +/**
> +  This function checks if SerialIo device is supported (not disabled by fuse)
> +
> +  @retval SerialIo support state
> +**/
> +BOOLEAN
> +PmcIsSerialIoSupported (
> +  VOID
> +  )
> +{
> +  //
> +  // Get fuse info from PWRMBASE + FUSE_SS_DIS_RD_2
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_FUSE_DIS_RD_2) &
> B_PMC_PWRM_FUSE_DIS_RD_2_SERIALIO_FUSE_SS_DIS) == 0);
> +}
> +
> +/**
> +  This function disables (non-static power gating) SCS eMMC controller and
> enables ModPHY SPD gating (PCH-LP only).
> +**/
> +VOID
> +PmcDisableScsEmmc (
> +  VOID
> +  )
> +{
> +  ASSERT (IsPchLp ());
> +
> +  //
> +  // Set PWRMBASE + NST_PG_FDIS_1 to disable SCS Controller in PMC
> +  //
> +  MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_NST_PG_FDIS_1,
> B_PCH_LP_PMC_PWRM_NST_PG_FDIS_1_EMMC_FDIS_PMC);
> +}
> +
> +/**
> +  This function disables (non-static power gating) SCS SD Card controller and
> enables ModPHY SPD gating (PCH-LP only).
> +**/
> +VOID
> +PmcDisableScsSdCard (
> +  VOID
> +  )
> +{
> +  UINT32        ScsDevicePgMask;
> +
> +  if (IsPchLp ()) {
> +    ScsDevicePgMask =
> B_PCH_LP_PMC_PWRM_NST_PG_FDIS_1_SDCARD_FDIS_PMC;
> +  } else {
> +    ScsDevicePgMask =
> B_PCH_H_PMC_PWRM_NST_PG_FDIS_1_SDCARD_FDIS_PMC;
> +  }
> +
> +  //
> +  // Set PWRMBASE + NST_PG_FDIS_1 to disable SCS Controller in PMC
> +  //
> +  MmioOr32 (PmcGetPwrmBase () + R_PMC_PWRM_NST_PG_FDIS_1,
> ScsDevicePgMask);
> +}
> +
> +/**
> +  This function disables (non-static power gating) SCS UFS controller and
> enables ModPHY SPD gating (PCH-LP only).
> +
> +  @param[in] UfsNum     SCS UFS Device
> +**/
> +VOID
> +PmcDisableScsUfs (
> +  IN UINT32   UfsNum
> +  )
> +{
> +  UINT32        PchPwrmBase;
> +
> +  ASSERT ((UfsNum == 0) && IsPchLp ());
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  //
> +  // Set PWRMBASE + NST_PG_FDIS_1 to disable SCS Controller in PMC
> +  //
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_NST_PG_FDIS_1,
> B_PCH_LP_PMC_PWRM_NST_PG_FDIS_1_UFS_FDIS_PMC);
> +
> +  if (PmcIsModPhySusPgSupported ()) {
> +    //
> +    // Set MSPDRTREQ:
> +    // PchPwrmBase + R_PWRM_MODPHY_PM_CFG5[16] = 1 to enable ASL
> code trigger request for ModPHY SPD gating.
> +    //
> +    MmioOr32 (PchPwrmBase + R_PMC_PWRM_MODPHY_PM_CFG5,
> B_PMC_PWRM_MODPHY_PM_CFG5_MSPDRTREQ_UFS2);
> +  }
> +}
> +
> +/**
> +  This function checks if SCS eMMC device is supported (not disabled by fuse)
> +
> +  @retval SCS device support state
> +**/
> +BOOLEAN
> +PmcIsScsEmmcSupported (
> +  VOID
> +  )
> +{
> +  //
> +  // Get fuse info from PWRMBASE + FUSE_SS_DIS_RD_2
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_FUSE_DIS_RD_2) &
> B_PMC_PWRM_FUSE_DIS_RD_2_EMMC_FUSE_SS_DIS) == 0);
> +}
> +
> +/**
> +  This function checks if SCS SD Card device is supported (not disabled by fuse)
> +
> +  @retval SCS device support state
> +**/
> +BOOLEAN
> +PmcIsScsSdCardSupported (
> +  VOID
> +  )
> +{
> +  //
> +  // Get fuse info from PWRMBASE + FUSE_SS_DIS_RD_2
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_FUSE_DIS_RD_2) &
> B_PMC_PWRM_FUSE_DIS_RD_2_SDX_FUSE_SS_DIS) == 0);
> +}
> +
> +/**
> +  This function checks if SCS UFS device is supported (not disabled by fuse)
> +
> +  @param[in] UfsNum     SCS UFS Device
> +
> +  @retval SCS device support state
> +**/
> +BOOLEAN
> +PmcIsScsUfsSupported (
> +  IN UINT32   UfsNum
> +  )
> +{
> +  //
> +  // Get fuse info from PWRMBASE + FUSE_SS_DIS_RD_2
> +  //
> +  return ((MmioRead32 (PmcGetPwrmBase () +
> R_PMC_PWRM_FUSE_DIS_RD_2) &
> B_PMC_PWRM_FUSE_DIS_RD_2_UFSX2_FUSE_SS_DIS) == 0);
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibWithS3.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibWithS3.c
> new file mode 100644
> index 0000000000..bbe944da5c
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPriv
> ateLib/PmcPrivateLibWithS3.c
> @@ -0,0 +1,194 @@
> +/** @file
> +  PCH private PMC Library.
> +  All function in this library is available for PEI, DXE, and SMM,
> +  But do not support UEFI RUNTIME environment call.
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/PchCycleDecodingLib.h>
> +#include <Library/S3BootScriptLib.h>
> +#include <Library/PmcLib.h>
> +#include <Private/Library/PmcPrivateLib.h>
> +
> +/**
> +  This function locks down PMC (DebugModeLock)
> +**/
> +VOID
> +PmcLockWithS3BootScript (
> +  VOID
> +  )
> +{
> +
> +  UINT32 PchPwrmBase;
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  //
> +  // Set PWRM_CFG[27] prior to OS.
> +  //
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_CFG,
> B_PMC_PWRM_CFG_DBG_MODE_LOCK);
> +
> +  S3BootScriptSaveMemWrite (
> +    S3BootScriptWidthUint32,
> +    (PchPwrmBase + R_PMC_PWRM_CFG),
> +    1,
> +    (VOID *) ((UINTN) PchPwrmBase + R_PMC_PWRM_CFG)
> +    );
> +
> +}
> +
> +/**
> +  This S3 BootScript only function disables triggering Global Reset of both
> +  the Host and the ME partitions after CF9h write of 6h or Eh.
> +**/
> +VOID
> +PmcDisableCf9GlobalResetInS3BootScript (
> +  VOID
> +  )
> +{
> +  UINT32                          Data;
> +
> +  UINT32                          PchPwrmBase;
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  Data = MmioRead32 (PchPwrmBase + R_PMC_PWRM_ETR3);
> +
> +  Data &= (UINT32) ~B_PMC_PWRM_ETR3_CF9GR;
> +
> +  S3BootScriptSaveMemWrite (
> +    S3BootScriptWidthUint32,
> +    (UINTN) PchPwrmBase +
> +    R_PMC_PWRM_ETR3,
> +    1,
> +    &Data
> +    );
> +}
> +
> +/**
> +  This S3 BootScript only function disables triggering Global Reset of both
> +  the Host and the ME partitions after CF9h write of 6h or Eh.
> +  Global Reset configuration is locked after programming
> +**/
> +VOID
> +PmcDisableCf9GlobalResetWithLockInS3BootScript (
> +  VOID
> +  )
> +{
> +  UINT32                          Data;
> +
> +  UINT32                          PchPwrmBase;
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  Data = MmioRead32 (PchPwrmBase + R_PMC_PWRM_ETR3);
> +
> +  Data &= (UINT32) ~B_PMC_PWRM_ETR3_CF9GR;
> +  Data |= (UINT32) B_PMC_PWRM_ETR3_CF9LOCK;
> +
> +  S3BootScriptSaveMemWrite (
> +    S3BootScriptWidthUint32,
> +    (UINTN) PchPwrmBase +
> +    R_PMC_PWRM_ETR3,
> +    1,
> +    &Data
> +    );
> +}
> +
> +/**
> +  This function sets SLP_SX Stretching Policy and adds
> +  lock setting to S3 Boot Script
> +**/
> +VOID
> +PmcLockSlpSxStretchingPolicyWithS3BootScript (
> +  VOID
> +  )
> +{
> +  UINT32  PchPwrmBase;
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  MmioOr8 (
> +    (PchPwrmBase + R_PMC_PWRM_GEN_PMCON_B + 2),
> +    (UINT8) ((B_PMC_PWRM_GEN_PMCON_B_SLPSX_STR_POL_LOCK) >> 16)
> +    );
> +
> +  S3BootScriptSaveMemWrite (
> +    S3BootScriptWidthUint8,
> +    (PchPwrmBase + R_PMC_PWRM_GEN_PMCON_B + 2),
> +    1,
> +    (VOID *) ((UINTN) PchPwrmBase + R_PMC_PWRM_GEN_PMCON_B + 2)
> +    );
> +}
> +
> +/**
> +  This function sets SMI Lock with S3 Boot Script programming
> +**/
> +VOID
> +PmcLockSmiWithS3BootScript (
> +  VOID
> +  )
> +{
> +  UINT32  PchPwrmBase;
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  MmioOr8 ((PchPwrmBase + R_PMC_PWRM_GEN_PMCON_B),
> B_PMC_PWRM_GEN_PMCON_B_SMI_LOCK);
> +
> +  S3BootScriptSaveMemWrite (
> +    S3BootScriptWidthUint8,
> +    (PchPwrmBase + R_PMC_PWRM_GEN_PMCON_B),
> +    1,
> +    (VOID *) ((UINTN) PchPwrmBase + R_PMC_PWRM_GEN_PMCON_B)
> +    );
> +}
> +
> +/**
> +  This function locks static power gating configuration with S3 Boot Script
> programming
> +**/
> +VOID
> +PmcLockFunctionDisableConfigWithS3BootScript (
> +  VOID
> +  )
> +{
> +  UINT32  PchPwrmBase;
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  MmioOr32 (PchPwrmBase + R_PMC_PWRM_ST_PG_FDIS_PMC_1, (UINT32)
> (B_PMC_PWRM_ST_PG_FDIS_PMC_1_ST_FDIS_LK));
> +
> +  S3BootScriptSaveMemWrite (
> +    S3BootScriptWidthUint8,
> +    (UINTN) (PchPwrmBase + R_PMC_PWRM_ST_PG_FDIS_PMC_1),
> +    1,
> +    (VOID *) (UINTN) (PchPwrmBase + R_PMC_PWRM_ST_PG_FDIS_PMC_1)
> +    );
> +}
> +
> +/**
> +  This function locks PMC Set Strap Message interface with S3 Boot Script
> programming
> +**/
> +VOID
> +PmcLockSetStrapMsgInterfaceWithS3BootScript (
> +  VOID
> +  )
> +{
> +  UINT32  PchPwrmBase;
> +
> +  PchPwrmBase = PmcGetPwrmBase ();
> +
> +  MmioOr32 ((UINTN) (PchPwrmBase + R_PMC_PWRM_SSML),
> B_PMC_PWRM_SSML_SSL);
> +
> +  S3BootScriptSaveMemWrite (
> +    S3BootScriptWidthUint8,
> +    (UINTN) (PchPwrmBase + R_PMC_PWRM_SSML),
> +    1,
> +    (VOID *) (UINTN) (PchPwrmBase + R_PMC_PWRM_SSML)
> +    );
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/
> PeiGpioHelpersLib.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/
> PeiGpioHelpersLib.c
> new file mode 100644
> index 0000000000..9c722bce07
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/
> PeiGpioHelpersLib.c
> @@ -0,0 +1,356 @@
> +/** @file
> +  This file contains routines for PEI GPIO Helpers Lib
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Library/HobLib.h>
> +#include <Base.h>
> +#include <Uefi/UefiBaseType.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/GpioNativeLib.h>
> +#include <Pch/Library/PeiDxeSmmGpioLib/GpioLibrary.h>
> +#include <Private/Library/GpioHelpersLib.h>
> +
> +extern EFI_GUID gGpioLibUnlockHobGuid;
> +
> +//
> +//  GPIO Lock HOB
> +//  Stores information on GPIO pads that should be left unlocked
> +//
> +typedef struct {
> +  //
> +  // GPIO PadConfig unlock data
> +  //
> +  UINT32  PadConfig;
> +  //
> +  // GPIO Output unlock data
> +  //
> +  UINT32  OutputState;
> +} GPIO_UNLOCK_HOB_DATA;
> +
> +/**
> +  This procedure will get index of GPIO Unlock HOB structure for selected
> GroupIndex and DwNum.
> +
> +  @param[in]  GroupIndex          GPIO group index
> +  @param[in]  DwNum               DWORD index for a group.
> +                                  For group which has less then 32 pads per group
> DwNum must be 0.
> +
> +  @retval GpioUnlockHobIndex
> +**/
> +STATIC
> +UINT32
> +GpioUnlockDataIndex (
> +  IN UINT32                       GroupIndex,
> +  IN UINT32                       DwNum
> +  )
> +{
> +  UINT32         GpioUnlockDataIndex;
> +  UINT32         Index;
> +
> +  GpioUnlockDataIndex = 0;
> +
> +  for (Index = 0; Index < GroupIndex; Index++) {
> +    GpioUnlockDataIndex += GPIO_GET_DW_NUM (GpioGetPadPerGroup
> (GpioGetGroupFromGroupIndex (Index))) + 1;
> +  }
> +
> +  GpioUnlockDataIndex += DwNum;
> +  return GpioUnlockDataIndex;
> +}
> +
> +/**
> +  This procedure will create GPIO HOB for storing unlock data
> +
> +  @retval Pointer to GPIO Unlock data structure
> +**/
> +STATIC
> +GPIO_UNLOCK_HOB_DATA*
> +GpioCreateUnlockData (
> +  VOID
> +  )
> +{
> +  VOID           *HobData;
> +  GPIO_GROUP     Group;
> +  GPIO_GROUP     GroupMin;
> +  GPIO_GROUP     GroupMax;
> +  UINT32         GpioUnlockDataRecords;
> +
> +  GroupMin = GpioGetLowestGroup ();
> +  GroupMax = GpioGetHighestGroup ();
> +  GpioUnlockDataRecords = 0;
> +
> +  for (Group = GroupMin; Group <= GroupMax; Group++) {
> +    GpioUnlockDataRecords += GPIO_GET_DW_NUM (GpioGetPadPerGroup
> (Group)) + 1;
> +  }
> +
> +  HobData = BuildGuidHob (&gGpioLibUnlockHobGuid,
> GpioUnlockDataRecords * sizeof (GPIO_UNLOCK_HOB_DATA));
> +  if (HobData == NULL) {
> +    return NULL;
> +  }
> +
> +  ZeroMem (HobData, GpioUnlockDataRecords * sizeof
> (GPIO_UNLOCK_HOB_DATA));
> +
> +  return (GPIO_UNLOCK_HOB_DATA*)HobData;
> +}
> +
> +/**
> +  This procedure will Get GPIO Unlock data structure for storing unlock data.
> +  If HOB doesn't exist it will be created.
> +
> +  @param[out] GpioUnlockData          pointer to GPIO Unlock data structure
> +
> +  @retval Length                      number of GPIO unlock data records
> +**/
> +STATIC
> +UINT32
> +GpioGetUnlockData (
> +  GPIO_UNLOCK_HOB_DATA  **GpioUnlockData
> +  )
> +{
> +  VOID  *Hob;
> +
> +  Hob = GetFirstGuidHob (&gGpioLibUnlockHobGuid);
> +  if (Hob == NULL) {
> +    //
> +    // It is the first time this function is used so create the HOB
> +    //
> +    *GpioUnlockData = GpioCreateUnlockData ();
> +    if (*GpioUnlockData == NULL) {
> +      return 0;
> +    }
> +    Hob = GetFirstGuidHob (&gGpioLibUnlockHobGuid);
> +  } else {
> +    *GpioUnlockData = (GPIO_UNLOCK_HOB_DATA*) GET_GUID_HOB_DATA
> (Hob);
> +  }
> +  return GET_GUID_HOB_DATA_SIZE (Hob) / sizeof
> (GPIO_UNLOCK_HOB_DATA);
> +}
> +
> +/**
> +  This procedure will get pointer to GPIO Unlock data structure.
> +
> +  @param[out] GpioUnlockData          pointer to GPIO Unlock data structure
> +
> +  @retval Length                      number of GPIO unlock data records
> +**/
> +STATIC
> +UINT32
> +GpioLocateUnlockData (
> +  GPIO_UNLOCK_HOB_DATA  **GpioUnlockData
> +  )
> +{
> +  VOID  *Hob;
> +
> +  Hob = GetFirstGuidHob (&gGpioLibUnlockHobGuid);
> +  if (Hob == NULL) {
> +    *GpioUnlockData = NULL;
> +    return 0;
> +  }
> +
> +  *GpioUnlockData = (GPIO_UNLOCK_HOB_DATA*) GET_GUID_HOB_DATA
> (Hob);
> +  return GET_GUID_HOB_DATA_SIZE (Hob) / sizeof
> (GPIO_UNLOCK_HOB_DATA);
> +}
> +
> +/**
> +  This procedure stores GPIO pad unlock information
> +
> +  @param[in] GpioPad         GPIO pad
> +  @param[in] GpioLockConfig  GPIO Lock Configuration
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioStoreUnlockData (
> +  IN GPIO_PAD             GpioPad,
> +  IN GPIO_LOCK_CONFIG     GpioLockConfig
> +  )
> +{
> +  GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
> +  UINT32               Length;
> +  UINT32               GroupIndex;
> +  UINT32               PadNumber;
> +  UINT32               Index;
> +
> +  if (GpioLockConfig == GpioLockDefault) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Length = GpioGetUnlockData (&GpioUnlockData);
> +  if (Length == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
> +  PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
> +  Index = GpioUnlockDataIndex (GroupIndex, GPIO_GET_DW_NUM
> (PadNumber));
> +
> +  if (Index >= Length) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((GpioLockConfig & B_GPIO_LOCK_CONFIG_PAD_CONF_LOCK_MASK) ==
> GpioPadConfigUnlock) {
> +    GpioUnlockData[Index].PadConfig |= 1 <<
> (GpioGetPadNumberFromGpioPad (GpioPad) % 32);
> +  }
> +
> +  if ((GpioLockConfig & B_GPIO_LOCK_CONFIG_OUTPUT_LOCK_MASK) ==
> GpioOutputStateUnlock) {
> +    GpioUnlockData[Index].OutputState |= 1 <<
> (GpioGetPadNumberFromGpioPad (GpioPad) % 32);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This procedure stores GPIO group data about pads which PadConfig needs
> to be unlocked.
> +
> +  @param[in]  GroupIndex          GPIO group index
> +  @param[in]  DwNum               DWORD index for a group.
> +                                  For group which has less then 32 pads per group
> DwNum must be 0.
> +  @param[in]  UnlockedPads        DWORD bitmask for pads which are going
> to be left unlocked
> +                                  Bit position - PadNumber
> +                                  Bit value - 0: Skip, 1: Leave unlocked
> +
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioStoreGroupDwUnlockPadConfigData (
> +  IN UINT32                       GroupIndex,
> +  IN UINT32                       DwNum,
> +  IN UINT32                       UnlockedPads
> +  )
> +{
> +  GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
> +  UINT32               Length;
> +  UINT32               Index;
> +
> +  if (UnlockedPads == 0) {
> +    //
> +    // No pads to be left unlocked
> +    //
> +    return EFI_SUCCESS;
> +  }
> +
> +  Length = GpioGetUnlockData (&GpioUnlockData);
> +  if (Length == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Index = GpioUnlockDataIndex (GroupIndex, DwNum);
> +  if (Index >= Length) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  GpioUnlockData[Index].PadConfig |= UnlockedPads;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This procedure stores GPIO group data about pads which Output state
> needs to be unlocked.
> +
> +  @param[in]  GroupIndex          GPIO group index
> +  @param[in]  DwNum               DWORD index for a group.
> +                                  For group which has less then 32 pads per group
> DwNum must be 0.
> +  @param[in]  UnlockedPads        DWORD bitmask for pads which are going
> to be left unlocked
> +                                  Bit position - PadNumber
> +                                  Bit value - 0: Skip, 1: Leave unlocked
> +  @retval Status
> +**/
> +EFI_STATUS
> +GpioStoreGroupDwUnlockOutputData (
> +  IN UINT32                       GroupIndex,
> +  IN UINT32                       DwNum,
> +  IN UINT32                       UnlockedPads
> +  )
> +{
> +  GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
> +  UINT32               Length;
> +  UINT32               Index;
> +
> +  if (UnlockedPads == 0) {
> +    //
> +    // No pads to be left unlocked
> +    //
> +    return EFI_SUCCESS;
> +  }
> +
> +  Length = GpioGetUnlockData (&GpioUnlockData);
> +  if (Length == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Index = GpioUnlockDataIndex (GroupIndex, DwNum);
> +  if (Index >= Length) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  GpioUnlockData[Index].OutputState |= UnlockedPads;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This procedure will get GPIO group data with pads, which PadConfig is
> supposed to be left unlock
> +
> +  @param[in]  GroupIndex          GPIO group index
> +  @param[in]  DwNum               DWORD index for a group.
> +                                  For group which has less then 32 pads per group
> DwNum must be 0.
> +  @retval     UnlockedPads        DWORD bitmask for pads which are going to
> be left unlocked
> +                                  Bit position - PadNumber
> +                                  Bit value - 0: to be locked, 1: Leave unlocked
> +**/
> +UINT32
> +GpioGetGroupDwUnlockPadConfigMask (
> +  IN UINT32                       GroupIndex,
> +  IN UINT32                       DwNum
> +  )
> +{
> +  GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
> +  UINT32               Length;
> +  UINT32               Index;
> +
> +  Length = GpioLocateUnlockData (&GpioUnlockData);
> +  if (Length == 0) {
> +    return 0;
> +  }
> +
> +  Index = GpioUnlockDataIndex (GroupIndex, DwNum);
> +  if (Index >= Length) {
> +    return 0;
> +  }
> +
> +  return GpioUnlockData[Index].PadConfig;
> +}
> +
> +/**
> +  This procedure will get GPIO group data with pads, which Output is
> supposed to be left unlock
> +
> +  @param[in]  GroupIndex          GPIO group index
> +  @param[in]  DwNum               DWORD index for a group.
> +                                  For group which has less then 32 pads per group
> DwNum must be 0.
> +  @retval     UnlockedPads        DWORD bitmask for pads which are going to
> be left unlocked
> +                                  Bit position - PadNumber
> +                                  Bit value - 0: to be locked, 1: Leave unlocked
> +**/
> +UINT32
> +GpioGetGroupDwUnlockOutputMask (
> +  IN UINT32                       GroupIndex,
> +  IN UINT32                       DwNum
> +  )
> +{
> +  GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
> +  UINT32               Length;
> +  UINT32               Index;
> +
> +  Length = GpioLocateUnlockData (&GpioUnlockData);
> +  if (Length == 0) {
> +    return 0;
> +  }
> +
> +  Index = GpioUnlockDataIndex (GroupIndex, DwNum);
> +  if (Index >= Length) {
> +    return 0;
> +  }
> +
> +  return GpioUnlockData[Index].OutputState;
> +}
> diff --git
> a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBuffer
> Lib/GpioNameBufferPei.c
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBuffer
> Lib/GpioNameBufferPei.c
> new file mode 100644
> index 0000000000..1b05378799
> --- /dev/null
> +++
> b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBuffer
> Lib/GpioNameBufferPei.c
> @@ -0,0 +1,68 @@
> +/** @file
> +  This file contains GpioMemLib implementation for PEI phase
> +
> +  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Library/HobLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Private/Library/GpioNameBufferLib.h>
> +
> +STATIC CONST EFI_GUID mGpioNamesPrivateHobGuid = {0x9AE3138D, 0x4EBF,
> 0x4E90, {0x87, 0x96, 0x11, 0xD3, 0x10, 0x04, 0x60, 0x0A}};
> +
> +STATIC volatile BOOLEAN mGlobalMemoryWorking = FALSE;
> +
> +STATIC CHAR8 mGpioNameBuffer[GPIO_NAME_LENGTH_MAX];
> +
> +/**
> +  Returns pointer to the buffer taken from GpioLib private HOB
> +
> +  @retval CHAR8*  Pointer to the buffer
> +**/
> +STATIC
> +CHAR8*
> +GetBufferFromHob (
> +  VOID
> +  )
> +{
> +  VOID  *Hob;
> +  CHAR8 *GpioNameBuffer;
> +
> +  Hob = NULL;
> +  GpioNameBuffer = NULL;
> +
> +  Hob = GetFirstGuidHob (&mGpioNamesPrivateHobGuid);
> +  if (Hob != NULL){
> +    GpioNameBuffer = (CHAR8*) GET_GUID_HOB_DATA (Hob);
> +  } else {
> +    GpioNameBuffer = (CHAR8*) BuildGuidHob
> (&mGpioNamesPrivateHobGuid, GPIO_NAME_LENGTH_MAX);
> +    if (GpioNameBuffer == NULL){
> +      DEBUG ((DEBUG_ERROR, "Failed to setup HOB for GPIO names lib\n"));
> +      ASSERT (FALSE);
> +    }
> +  }
> +  return GpioNameBuffer;
> +}
> +
> +/**
> +  Returns pointer to the global buffer to be used by GpioNamesLib
> +
> +  @retval CHAR8*  Pointer to the buffer
> +**/
> +CHAR8*
> +GpioGetStaticNameBuffer (
> +  VOID
> +  )
> +{
> +  mGlobalMemoryWorking = TRUE;
> +
> +  if (mGlobalMemoryWorking) {
> +    return mGpioNameBuffer;
> +  } else {
> +    return GetBufferFromHob ();
> +  }
> +}
> +
> --
> 2.16.2.windows.1


  parent reply	other threads:[~2019-08-17  1:16 UTC|newest]

Thread overview: 121+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-17  0:15 [edk2-platforms][PATCH V1 00/37] Coffee Lake and Whiskey Lake support Kubacki, Michael A
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 01/37] CoffeelakeSiliconPkg: Add package and Include headers Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:08   ` Chiu, Chasel
2019-08-17  1:18   ` Chaganty, Rangasai V
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 02/37] CoffeelakeSiliconPkg/Cpu: Add " Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:08   ` Chiu, Chasel
2019-08-17  6:58   ` Chaganty, Rangasai V
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 03/37] CoffeelakeSiliconPkg/Me: " Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:08   ` Chiu, Chasel
2019-08-17  7:04   ` Chaganty, Rangasai V
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 04/37] CoffeelakeSiliconPkg/Pch: Add include headers Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:08   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 05/37] CoffeelakeSiliconPkg/Pch: Add ConfigBlock headers Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:09   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 06/37] CoffeelakeSiliconPkg/Pch: Add Library include headers Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:09   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 07/37] CoffeelakeSiliconPkg/Pch: Add PPI and Protocol " Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:09   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 08/37] CoffeelakeSiliconPkg/Pch: Add Register " Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:09   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 09/37] CoffeelakeSiliconPkg/Pch: Add Private " Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:12   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 10/37] CoffeelakeSiliconPkg/Pch: Add Private/Library " Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:09   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 11/37] CoffeelakeSiliconPkg/Pch: Add Private/Protocol " Kubacki, Michael A
2019-08-17  0:51   ` Nate DeSimone
2019-08-17  1:10   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 12/37] CoffeelakeSiliconPkg/SampleCode: Add Include headers Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:12   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 13/37] CoffeelakeSiliconPkg/SystemAgent: " Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:12   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 14/37] CoffeelakeSiliconPkg: Add package common library instances Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:12   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 15/37] CoffeelakeSiliconPkg/Cpu: Add " Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:15   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 16/37] CoffeelakeSiliconPkg/Me: " Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:12   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 17/37] CoffeelakeSiliconPkg/Pch: Add Base " Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:13   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 18/37] CoffeelakeSiliconPkg/Pch: Add DXE " Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:13   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 19/37] CoffeelakeSiliconPkg/Pch: Add PEI " Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:13   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 20/37] CoffeelakeSiliconPkg/Pch: Add SMM " Kubacki, Michael A
2019-08-17  0:53   ` Nate DeSimone
2019-08-17  1:16   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 21/37] CoffeelakeSiliconPkg/Pch: Add Base " Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:13   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 22/37] CoffeelakeSiliconPkg/Pch: Add DXE private " Kubacki, Michael A
2019-08-17  0:52   ` Nate DeSimone
2019-08-17  1:13   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 23/37] CoffeelakeSiliconPkg/Pch: Add PEI " Kubacki, Michael A
2019-08-17  0:53   ` Nate DeSimone
2019-08-17  1:14   ` Chiu, Chasel [this message]
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 24/37] CoffeelakeSiliconPkg/Pch: Add SMM " Kubacki, Michael A
2019-08-17  0:53   ` Nate DeSimone
2019-08-17  1:14   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 25/37] CoffeelakeSiliconPkg/SystemAgent: Add " Kubacki, Michael A
2019-08-17  0:53   ` Nate DeSimone
2019-08-17  1:14   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 26/37] CoffeelakeSiliconPkg/Pch: Add modules Kubacki, Michael A
2019-08-17  0:53   ` Nate DeSimone
2019-08-17  1:14   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 27/37] CoffeelakeSiliconPkg/Pch: Add PchSmiDispatcher Kubacki, Michael A
2019-08-17  0:53   ` Nate DeSimone
2019-08-17  1:15   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 28/37] CoffeelakeSiliconPkg/SystemAgent: Add modules Kubacki, Michael A
2019-08-17  0:53   ` Nate DeSimone
2019-08-17  1:15   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 29/37] CoffeelakeSiliconPkg: Add package DSC files Kubacki, Michael A
2019-08-17  0:53   ` Nate DeSimone
2019-08-17  1:14   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 30/37] Maintainers.txt: Add CoffeelakeSiliconPkg maintainers Kubacki, Michael A
2019-08-17  0:53   ` Nate DeSimone
2019-08-17  1:15   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 31/37] WhiskeylakeOpenBoardPkg: Add package and headers Kubacki, Michael A
2019-08-17  0:54   ` Nate DeSimone
2019-08-17  1:16   ` Chiu, Chasel
2019-08-19 18:09   ` Sinha, Ankit
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 32/37] WhiskeylakeOpenBoardPkg/WhiskeylakeURvp: Add headers Kubacki, Michael A
2019-08-17  0:54   ` Nate DeSimone
2019-08-17  1:16   ` Chiu, Chasel
2019-08-17  0:15 ` [edk2-platforms][PATCH V1 33/37] WhiskeylakeOpenBoardPkg: Add library instances Kubacki, Michael A
2019-08-17  0:54   ` Nate DeSimone
2019-08-17  1:16   ` Chiu, Chasel
2019-08-17  0:16 ` [edk2-platforms][PATCH V1 34/37] WhiskeylakeOpenBoardPkg/WhiskeylakeURvp: " Kubacki, Michael A
2019-08-17  0:54   ` Nate DeSimone
2019-08-17  1:17   ` Chiu, Chasel
2019-08-17 20:08   ` Chaganty, Rangasai V
2019-08-17  0:16 ` [edk2-platforms][PATCH V1 35/37] WhiskeylakeOpenBoardPkg: Add modules Kubacki, Michael A
2019-08-17  0:54   ` Nate DeSimone
2019-08-17  1:17   ` Chiu, Chasel
2019-08-17  7:50   ` Chaganty, Rangasai V
2019-08-17  0:16 ` [edk2-platforms][PATCH V1 36/37] WhiskeylakeOpenBoardPkg/WhiskeylakeURvp: Add DSC and build files Kubacki, Michael A
2019-08-17  0:54   ` Nate DeSimone
2019-08-17  1:16   ` Chiu, Chasel
2019-08-17 20:11   ` Chaganty, Rangasai V
2019-08-17  0:16 ` [edk2-platforms][PATCH V1 37/37] Add WhiskeylakeOpenBoardPkg to global build config and documentation Kubacki, Michael A
2019-08-17  0:54   ` Nate DeSimone
2019-08-17  1:17   ` Chiu, Chasel
2019-08-17 20:00   ` Chaganty, Rangasai V
2019-08-19 18:14 ` [edk2-platforms][PATCH V1 00/37] Coffee Lake and Whiskey Lake support Sinha, Ankit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3C3EFB470A303B4AB093197B6777CCEC5046239E@PGSMSX111.gar.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox