public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Nate DeSimone" <nathaniel.l.desimone@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>,
	"Chiu, Chasel" <chasel.chiu@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 00:53:48 +0000	[thread overview]
Message-ID: <02A34F284D1DA44BB705E61F7180EF0AAEE12AA1@ORSMSX114.amr.corp.intel.com> (raw)
In-Reply-To: <20190817001603.30632-24-michael.a.kubacki@intel.com>

Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>

-----Original Message-----
From: Kubacki, Michael A 
Sent: Friday, August 16, 2019 5:16 PM
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/PeiDxeSmmGpioPrivateLib/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/PeiDxeSmmPchInitCommonLib/PeiDxeSmmPchInitCommonLib.inf               |   34 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpressHelpersLib/PeiDxeSmmPchPciExpressHelpersLib.inf |   42 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/PeiDxeSmmPchPsfPrivateLibCnl.inf            |   41 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PeiDxeSmmPmcPrivateLibCnl.inf                  |   48 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PeiDxeSmmPmcPrivateLibWithS3.inf               |   39 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PeiPmcPrivateLibCnl.inf                        |   40 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/PeiGpioHelpersLib.inf                               |   42 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBufferLib/PeiGpioNameBufferLib.inf                         |   35 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/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/PeiDxeSmmPchPciExpressHelpersLib/PchPciExpressHelpersLibrary.h        |   42 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/PchPsfPrivateLibInternal.h                  |  490 ++++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLibInternal.h                        |   47 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioNamesCnl.c                                |  166 ++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioNativePrivateLib.c                        | 1304 +++++++++++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioNativePrivateLibCnl.c                     | 2275 ++++++++++++++++++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioPrivateLib.c                              |  752 ++++++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/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/PeiDxeSmmPchInitCommonLib/PchInitCommon.c                             |  221 ++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpressHelpersLib/PchPciExpressHelpersLibrary.c        | 2407 ++++++++++++++++++++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/PchPsfPrivateLib.c                          |  542 +++++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/PchPsfPrivateLibCnl.c                       |  338 +++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PeiPmcPrivateLib.c                             |   92 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLib.c                                | 1033 +++++++++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLibClient.c                          |   73 +
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLibCnl.c                             |  360 +++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLibWithS3.c                          |  194 ++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioHelpersLib/PeiGpioHelpersLib.c                                 |  356 +++
 Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBufferLib/GpioNameBufferPei.c                              |   68 +
 37 files changed, 12919 insertions(+)

diff --git a/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/PeiDxeSmmGpioPrivateLibCnl.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/PeiDxeSmmGpioPrivateLibCnl.inf
new file mode 100644
index 0000000000..318b54a99c
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/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/PeiDxeSmmPchDmiLib/PeiDxeSmmPchDmiLib.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/PeiDxeSmmPchDmiLib.inf
new file mode 100644
index 0000000000..b36fc15901
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/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/PeiDxeSmmPchDmiLib/PeiDxeSmmPchDmiWithS3Lib.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/PeiDxeSmmPchDmiWithS3Lib.inf
new file mode 100644
index 0000000000..1eda7cdba8
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/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/PeiDxeSmmPchInitCommonLib/PeiDxeSmmPchInitCommonLib.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitCommonLib/PeiDxeSmmPchInitCommonLib.inf
new file mode 100644
index 0000000000..d81c428a1c
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitCommonLib/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/PeiDxeSmmPchPciExpressHelpersLib/PeiDxeSmmPchPciExpressHelpersLib.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpressHelpersLib/PeiDxeSmmPchPciExpressHelpersLib.inf
new file mode 100644
index 0000000000..16b1c019b8
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpressHelpersLib/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/PeiDxeSmmPchPsfPrivateLib/PeiDxeSmmPchPsfPrivateLibCnl.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/PeiDxeSmmPchPsfPrivateLibCnl.inf
new file mode 100644
index 0000000000..0ed9f30dcc
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/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/PeiDxeSmmPmcPrivateLib/PeiDxeSmmPmcPrivateLibCnl.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PeiDxeSmmPmcPrivateLibCnl.inf
new file mode 100644
index 0000000000..adb154dd14
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/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/PeiDxeSmmPmcPrivateLib/PeiDxeSmmPmcPrivateLibWithS3.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PeiDxeSmmPmcPrivateLibWithS3.inf
new file mode 100644
index 0000000000..cd1380dc43
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/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/PeiDxeSmmPmcPrivateLib/PeiPmcPrivateLibCnl.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PeiPmcPrivateLibCnl.inf
new file mode 100644
index 0000000000..ab3645c61d
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/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/PeiGpioNameBufferLib/PeiGpioNameBufferLib.inf b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBufferLib/PeiGpioNameBufferLib.inf
new file mode 100644
index 0000000000..3619a2e6a7
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBufferLib/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/PeiDxeSmmGpioPrivateLib/GpioNativePrivateLibInternal.h b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioNativePrivateLibInternal.h
new file mode 100644
index 0000000000..e081027c40
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/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/PeiDxeSmmPchDmiLib/PchDmi14.h b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/PchDmi14.h
new file mode 100644
index 0000000000..1d50c04b0f
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/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/PeiDxeSmmPchDmiLib/PchDmi15.h b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/PchDmi15.h
new file mode 100644
index 0000000000..744a96fe14
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/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/PeiDxeSmmPchPciExpressHelpersLib/PchPciExpressHelpersLibrary.h b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpressHelpersLib/PchPciExpressHelpersLibrary.h
new file mode 100644
index 0000000000..b14f24b18f
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpressHelpersLib/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/PeiDxeSmmPchPsfPrivateLib/PchPsfPrivateLibInternal.h b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/PchPsfPrivateLibInternal.h
new file mode 100644
index 0000000000..f633df0411
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/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/PeiDxeSmmPmcPrivateLib/PmcPrivateLibInternal.h b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLibInternal.h
new file mode 100644
index 0000000000..c08d1cf10d
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/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/PeiDxeSmmGpioPrivateLib/GpioNamesCnl.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioNamesCnl.c
new file mode 100644
index 0000000000..5a4876bfeb
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/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/PeiDxeSmmGpioPrivateLib/GpioNativePrivateLib.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioNativePrivateLib.c
new file mode 100644
index 0000000000..affecf9ec0
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/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/PeiDxeSmmGpioPrivateLib/GpioNativePrivateLibCnl.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioNativePrivateLibCnl.c
new file mode 100644
index 0000000000..4cff00c27b
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/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_GPIO_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_GPIO_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/PeiDxeSmmGpioPrivateLib/GpioPrivateLib.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioPrivateLib.c
new file mode 100644
index 0000000000..2cf11c6da2
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/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/PeiDxeSmmGpioPrivateLib/GpioPrivateLibCnl.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/GpioPrivateLibCnl.c
new file mode 100644
index 0000000000..a6d260f4ad
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmGpioPrivateLib/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/PeiDxeSmmPchDmiLib/PchDmi14.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/PchDmi14.c
new file mode 100644
index 0000000000..2f9b6a7e6f
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/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/PeiDxeSmmPchDmiLib/PchDmi15.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/PchDmi15.c
new file mode 100644
index 0000000000..c711b3de39
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/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/PeiDxeSmmPchDmiLib/PchDmiLib.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/PchDmiLib.c
new file mode 100644
index 0000000000..f1b2867659
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/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/PeiDxeSmmPchDmiLib/PchDmiWithS3Lib.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/PchDmiWithS3Lib.c
new file mode 100644
index 0000000000..9778c9a252
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchDmiLib/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/PeiDxeSmmPchInitCommonLib/PchInitCommon.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitCommonLib/PchInitCommon.c
new file mode 100644
index 0000000000..14bd51ec43
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchInitCommonLib/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/PeiDxeSmmPchPciExpressHelpersLib/PchPciExpressHelpersLibrary.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpressHelpersLib/PchPciExpressHelpersLibrary.c
new file mode 100644
index 0000000000..dcb43285b7
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPciExpressHelpersLib/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/PeiDxeSmmPchPsfPrivateLib/PchPsfPrivateLib.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/PchPsfPrivateLib.c
new file mode 100644
index 0000000000..f2d20c625a
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/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/PeiDxeSmmPchPsfPrivateLib/PchPsfPrivateLibCnl.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/PchPsfPrivateLibCnl.c
new file mode 100644
index 0000000000..d1c87a9e84
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPchPsfPrivateLib/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/PeiDxeSmmPmcPrivateLib/PeiPmcPrivateLib.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PeiPmcPrivateLib.c
new file mode 100644
index 0000000000..f88febfa48
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/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/PeiDxeSmmPmcPrivateLib/PmcPrivateLib.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLib.c
new file mode 100644
index 0000000000..a6ccf4b96b
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/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/PeiDxeSmmPmcPrivateLib/PmcPrivateLibClient.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLibClient.c
new file mode 100644
index 0000000000..2411a2be23
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/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/PeiDxeSmmPmcPrivateLib/PmcPrivateLibCnl.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLibCnl.c
new file mode 100644
index 0000000000..847be42937
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/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/PeiDxeSmmPmcPrivateLib/PmcPrivateLibWithS3.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/PmcPrivateLibWithS3.c
new file mode 100644
index 0000000000..bbe944da5c
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiDxeSmmPmcPrivateLib/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/PeiGpioNameBufferLib/GpioNameBufferPei.c b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBufferLib/GpioNameBufferPei.c
new file mode 100644
index 0000000000..1b05378799
--- /dev/null
+++ b/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Library/Private/PeiGpioNameBufferLib/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


  reply	other threads:[~2019-08-17  0:53 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 [this message]
2019-08-17  1:14   ` Chiu, Chasel
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=02A34F284D1DA44BB705E61F7180EF0AAEE12AA1@ORSMSX114.amr.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