[edk2-devel] [edk2-platforms: Patch 3/8] Silicon/Intel: Import QuarkSocPkg from edk2

Michael D Kinney michael.d.kinney at intel.com
Fri May 10 03:34:30 UTC 2019


https://bugzilla.tianocore.org/show_bug.cgi?id=1374

Import QuarkSocPkg from edk2/master.

Cc: Kelly Steele <kelly.steele at intel.com>
Cc: Michael Kubacki <michael.a.kubacki at intel.com>
Cc: Leif Lindholm <leif.lindholm at linaro.org>
Cc: Ard Biesheuvel <ard.biesheuvel at linaro.org>
Signed-off-by: Michael D Kinney <michael.d.kinney at intel.com>
---
 .../Include/DdrMemoryController.h             |  251 ++
 .../QuarkNorthCluster/Include/IntelQNCBase.h  |   17 +
 .../Include/IntelQNCConfig.h                  |  100 +
 .../QuarkNorthCluster/Include/IntelQNCDxe.h   |   17 +
 .../QuarkNorthCluster/Include/IntelQNCPeim.h  |   17 +
 .../QuarkNorthCluster/Include/IntelQNCRegs.h  |   48 +
 .../Include/Library/IntelQNCLib.h             |  284 ++
 .../Include/Library/QNCAccessLib.h            |  161 +
 .../Include/Library/QNCSmmLib.h               |   57 +
 .../Include/Ppi/QNCMemoryInit.h               |   36 +
 .../Include/Protocol/PchInfo.h                |   48 +
 .../Include/Protocol/PlatformPolicy.h         |   31 +
 .../Include/Protocol/QncS3Support.h           |   84 +
 .../Include/Protocol/SmmIchnDispatch2.h       |  115 +
 .../QuarkNorthCluster/Include/Protocol/Spi.h  |  345 +++
 .../QuarkNorthCluster/Include/QNCAccess.h     |  177 ++
 .../Include/QNCCommonDefinitions.h            |  350 +++
 .../QuarkNorthCluster/Include/QuarkNcSocId.h  |  751 +++++
 .../Library/IntelQNCLib/CommonHeader.h        |   32 +
 .../Library/IntelQNCLib/IntelQNCLib.c         |  771 +++++
 .../Library/IntelQNCLib/IntelQNCLib.inf       |   57 +
 .../Library/IntelQNCLib/PciExpress.c          |  932 ++++++
 .../Library/MtrrLib/MtrrLib.c                 | 2112 +++++++++++++
 .../Library/MtrrLib/MtrrLib.inf               |   42 +
 .../Library/MtrrLib/MtrrLib.uni               |   18 +
 .../Library/QNCAccessLib/BaseAccess.c         |   28 +
 .../Library/QNCAccessLib/QNCAccessLib.c       |  327 ++
 .../Library/QNCAccessLib/QNCAccessLib.inf     |   37 +
 .../Library/QNCAccessLib/RuntimeAccess.c      |  142 +
 .../QNCAccessLib/RuntimeQNCAccessLib.inf      |   43 +
 .../Library/QNCSmmLib/QNCSmmLib.c             |  313 ++
 .../Library/QNCSmmLib/QNCSmmLib.inf           |   44 +
 .../Library/ResetSystemLib/ResetSystemLib.c   |  379 +++
 .../Library/ResetSystemLib/ResetSystemLib.inf |   46 +
 .../Library/SmbusLib/CommonHeader.h           |   25 +
 .../Library/SmbusLib/SmbusLib.c               |  797 +++++
 .../Library/SmbusLib/SmbusLib.inf             |   47 +
 .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.c     |  446 +++
 .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf   |   30 +
 .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni   |   12 +
 .../MemoryInit/Pei/MemoryInit.c               |   59 +
 .../MemoryInit/Pei/MemoryInit.h               |   35 +
 .../MemoryInit/Pei/MemoryInitPei.inf          |   70 +
 .../MemoryInit/Pei/core_types.h               |   43 +
 .../MemoryInit/Pei/gen5_iosf_sb_definitions.h |  738 +++++
 .../MemoryInit/Pei/general_definitions.h      |   84 +
 .../QuarkNorthCluster/MemoryInit/Pei/hte.c    |  536 ++++
 .../QuarkNorthCluster/MemoryInit/Pei/hte.h    |   66 +
 .../QuarkNorthCluster/MemoryInit/Pei/io.h     |  132 +
 .../QuarkNorthCluster/MemoryInit/Pei/lprint.c |  382 +++
 .../MemoryInit/Pei/meminit.c                  | 2638 +++++++++++++++++
 .../MemoryInit/Pei/meminit.h                  |   22 +
 .../MemoryInit/Pei/meminit_utils.c            | 1574 ++++++++++
 .../MemoryInit/Pei/meminit_utils.h            |   95 +
 .../MemoryInit/Pei/memory_options.h           |   77 +
 .../QuarkNorthCluster/MemoryInit/Pei/mrc.c    |   40 +
 .../QuarkNorthCluster/MemoryInit/Pei/mrc.h    |  160 +
 .../MemoryInit/Pei/platform.c                 |  186 ++
 .../MemoryInit/Pei/prememinit.c               |  187 ++
 .../MemoryInit/Pei/prememinit.h               |   15 +
 .../QNCInit/Dxe/CommonHeader.h                |   49 +
 .../QNCInit/Dxe/DxeQNCSmbus.c                 |  612 ++++
 .../QNCInit/Dxe/DxeQNCSmbus.h                 |  205 ++
 .../QNCInit/Dxe/LegacyRegion.c                |  237 ++
 .../QNCInit/Dxe/LegacyRegion.h                |  198 ++
 .../QuarkNorthCluster/QNCInit/Dxe/QNCInit.c   |  518 ++++
 .../QuarkNorthCluster/QNCInit/Dxe/QNCInit.h   |   49 +
 .../QNCInit/Dxe/QNCInitDxe.inf                |   92 +
 .../QNCInit/Dxe/QNCRootPorts.c                |   76 +
 .../QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h  |   80 +
 .../QNCInit/Dxe/QNCSmbusExec.c                |  246 ++
 .../S3Support/Dxe/QncS3Support.c              |  417 +++
 .../S3Support/Dxe/QncS3Support.h              |  117 +
 .../S3Support/Dxe/QncS3Support.inf            |   64 +
 .../Smm/Dxe/SmmAccessDxe/SmmAccess.inf        |   49 +
 .../Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c    |  405 +++
 .../Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h    |  230 ++
 .../Smm/Dxe/SmmControlDxe/SmmControlDriver.c  |  358 +++
 .../Smm/Dxe/SmmControlDxe/SmmControlDxe.inf   |   55 +
 .../DxeSmm/QncSmmDispatcher/CommonHeader.h    |   45 +
 .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c   |   32 +
 .../QncSmmDispatcher/QNC/QNCSmmHelpers.c      |  549 ++++
 .../QNC/QNCSmmPeriodicTimer.c                 |  424 +++
 .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c  |  211 ++
 .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c    |   90 +
 .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c    |  147 +
 .../Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h      |  868 ++++++
 .../Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c  |  825 ++++++
 .../QncSmmDispatcher/QNCSmmDispatcher.inf     |   81 +
 .../DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c   |  367 +++
 .../DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h   |  219 ++
 .../DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h |   13 +
 .../DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h  |  178 ++
 .../Smm/Pei/SmmAccessPei/SmmAccessPei.c       |  376 +++
 .../Smm/Pei/SmmAccessPei/SmmAccessPei.inf     |   45 +
 .../Smm/Pei/SmmControlPei/SmmControlPei.c     |  274 ++
 .../Smm/Pei/SmmControlPei/SmmControlPei.inf   |   51 +
 .../QuarkNorthCluster/Spi/Common/SpiCommon.c  |  927 ++++++
 .../QuarkNorthCluster/Spi/Common/SpiCommon.h  |  317 ++
 .../QuarkNorthCluster/Spi/PchSpiRuntime.inf   |   84 +
 .../QuarkNorthCluster/Spi/PchSpiSmm.inf       |   50 +
 .../QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c |  205 ++
 .../QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h |   79 +
 .../QuarkNorthCluster/Spi/Smm/PchSpi.c        |  123 +
 .../QuarkNorthCluster/Spi/Smm/PchSpi.h        |   47 +
 Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec     |  234 ++
 Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc     |  254 ++
 .../QuarkSouthCluster/Include/CEATA.h         |  114 +
 .../QuarkSouthCluster/Include/I2cRegs.h       |   95 +
 .../QuarkSouthCluster/Include/Ioh.h           |  248 ++
 .../QuarkSouthCluster/Include/IohAccess.h     |   18 +
 .../Include/IohCommonDefinitions.h            |  342 +++
 .../Include/Library/I2cLib.h                  |  152 +
 .../Include/Library/IohLib.h                  |   36 +
 .../QuarkSouthCluster/Include/MMC.h           |  274 ++
 .../QuarkSouthCluster/Include/SDCard.h        |  146 +
 .../QuarkSouthCluster/Include/SDHostIo.h      |  333 +++
 .../IohInit/Dxe/CommonHeader.h                |   55 +
 .../QuarkSouthCluster/IohInit/Dxe/IohBds.h    |   83 +
 .../QuarkSouthCluster/IohInit/Dxe/IohData.c   |   42 +
 .../QuarkSouthCluster/IohInit/Dxe/IohInit.c   |   37 +
 .../IohInit/Dxe/IohInitDxe.inf                |   76 +
 .../Library/I2cLib/CommonHeader.h             |  214 ++
 .../QuarkSouthCluster/Library/I2cLib/I2cLib.c |  998 +++++++
 .../Library/I2cLib/I2cLib.inf                 |   62 +
 .../Library/IohLib/CommonHeader.h             |   29 +
 .../QuarkSouthCluster/Library/IohLib/IohLib.c |   99 +
 .../Library/IohLib/IohLib.inf                 |   49 +
 .../Sdio/Dxe/SDControllerDxe/ComponentName.c  |  227 ++
 .../Sdio/Dxe/SDControllerDxe/ComponentName.h  |  141 +
 .../Sdio/Dxe/SDControllerDxe/SDController.c   | 1784 +++++++++++
 .../Sdio/Dxe/SDControllerDxe/SDController.h   |  316 ++
 .../Dxe/SDControllerDxe/SDControllerDxe.inf   |   56 +
 .../Sdio/Dxe/SDMediaDeviceDxe/CEATA.c         |  647 ++++
 .../Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c  |  389 +++
 .../Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c |  215 ++
 .../Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h |  139 +
 .../Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c  |  538 ++++
 .../Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c | 1708 +++++++++++
 .../Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c |  317 ++
 .../Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h |  462 +++
 .../Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf |   60 +
 .../QuarkSouthCluster/Usb/Common/Pei/UsbPei.c |  320 ++
 .../QuarkSouthCluster/Usb/Common/Pei/UsbPei.h |   38 +
 .../Usb/Common/Pei/UsbPei.inf                 |   53 +
 .../Usb/Ohci/Dxe/ComponentName.c              |  219 ++
 .../Usb/Ohci/Dxe/ComponentName.h              |  141 +
 .../Usb/Ohci/Dxe/Descriptor.h                 |  132 +
 .../QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c     | 2473 +++++++++++++++
 .../QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h     |  663 +++++
 .../Usb/Ohci/Dxe/OhciDebug.c                  |   78 +
 .../Usb/Ohci/Dxe/OhciDebug.h                  |   42 +
 .../Usb/Ohci/Dxe/OhciDxe.inf                  |   71 +
 .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c  | 1390 +++++++++
 .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h  |  920 ++++++
 .../Usb/Ohci/Dxe/OhciSched.c                  |  528 ++++
 .../Usb/Ohci/Dxe/OhciSched.h                  |  225 ++
 .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c  |  889 ++++++
 .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h  |  387 +++
 .../QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c |  560 ++++
 .../QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h |  152 +
 .../Usb/Ohci/Pei/Descriptor.h                 |  131 +
 .../QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c  | 1386 +++++++++
 .../QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h  |  252 ++
 .../Usb/Ohci/Pei/OhciPei.inf                  |   56 +
 .../QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c  | 1386 +++++++++
 .../QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h  |  875 ++++++
 .../Usb/Ohci/Pei/OhciSched.c                  |  223 ++
 .../Usb/Ohci/Pei/OhciSched.h                  |  108 +
 .../QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c  |  560 ++++
 .../QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h  |  231 ++
 .../QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c |  491 +++
 .../QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h |  134 +
 173 files changed, 53495 insertions(+)
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c
 create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h

diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h
new file mode 100644
index 0000000000..fe96af4405
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h
@@ -0,0 +1,251 @@
+/** @file
+Memory controller configuration.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __DDR_MEMORY_CONTROLLER_H__
+#define __DDR_MEMORY_CONTROLLER_H__
+
+//
+// DDR timing data definitions.
+// These are used to create bitmaps of valid timing configurations.
+//
+
+#define DUAL_CHANNEL_DDR_TIMING_DATA_FREQUENCY_UNKNOWN    0xFF
+#define DUAL_CHANNEL_DDR_TIMING_DATA_REFRESH_RATE_UNKNOWN 0xFF
+
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_20    0x01
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_25    0x00
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_30    0x02
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_ALL   0x03
+
+
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_02   0x02
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_03   0x01
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_04   0x00
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_ALL  0x03
+
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_02    0x02
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_03    0x01
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_04    0x00
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_ALL   0x03
+
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_05   0x05
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_06   0x04
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_07   0x03
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_08   0x02
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_09   0x01
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_10   0x00
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_ALL  0x07
+
+#define DUAL_CHANNEL_DDR_DATA_TYPE_REGISTERED    0x01
+#define DUAL_CHANNEL_DDR_DATA_TYPE_UNREGISTERED  0x02
+#define DUAL_CHANNEL_DDR_DATA_TYPE_BUFFERED      0x04
+#define DUAL_CHANNEL_DDR_DATA_TYPE_UNBUFFERED    0x08
+#define DUAL_CHANNEL_DDR_DATA_TYPE_SDR           0x10
+#define DUAL_CHANNEL_DDR_DATA_TYPE_DDR           0x20
+
+
+//
+// Maximum number of SDRAM channels supported by the memory controller
+//
+#define MAX_CHANNELS 1
+
+//
+// Maximum number of DIMM sockets supported by the memory controller
+//
+#define MAX_SOCKETS 1
+
+//
+// Maximum number of sides supported per DIMM
+//
+#define   MAX_SIDES                         2
+
+//
+// Maximum number of "Socket Sets", where a "Socket Set is a set of matching
+// DIMM's from the various channels
+//
+#define   MAX_SOCKET_SETS                   2
+
+//
+// Maximum number of rows supported by the memory controller
+//
+#define MAX_ROWS (MAX_SIDES * MAX_SOCKETS)
+
+//
+// Maximum number of memory ranges supported by the memory controller
+//
+#define MAX_RANGES (MAX_ROWS + 5)
+
+//
+// Maximum Number of Log entries
+//
+#define   MEMORY_LOG_MAX_INDEX          16
+
+
+typedef struct _MEMORY_LOG_ENTRY {
+  EFI_STATUS_CODE_VALUE                     Event;
+  EFI_STATUS_CODE_TYPE                      Severity;
+  UINT8                                     Data;
+} MEMORY_LOG_ENTRY;
+
+typedef struct _MEMORY_LOG {
+  UINT8                                     Index;
+  MEMORY_LOG_ENTRY                      Entry[MEMORY_LOG_MAX_INDEX];
+} MEMORY_LOG;
+
+
+
+//
+// Defined ECC types
+//
+#define DUAL_CHANNEL_DDR_ECC_TYPE_NONE             0x01   // No error checking
+#define DUAL_CHANNEL_DDR_ECC_TYPE_EC               0x02   // Error checking only
+#define DUAL_CHANNEL_DDR_ECC_TYPE_SECC             0x04   // Software Scrubbing ECC
+#define DUAL_CHANNEL_DDR_ECC_TYPE_HECC             0x08   // Hardware Scrubbing ECC
+#define DUAL_CHANNEL_DDR_ECC_TYPE_CKECC            0x10   // Chip Kill ECC
+
+//
+// Row configuration status values
+//
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_SUCCESS        0x00  // No error
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_UNKNOWN        0x01  // Pattern mismatch, no memory
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_UNSUPPORTED    0x02  // Memory type not supported
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_ADDRESS_ERROR  0x03  // Row/Col/Bnk mismatch
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_ECC_ERROR      0x04  // Received ECC error
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_NOT_PRESENT    0x05  // Row is not present
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_DISABLED       0x06  // Row is disabled
+
+
+//
+// Memory range types
+//
+typedef enum {
+  DualChannelDdrMainMemory,
+  DualChannelDdrSmramCacheable,
+  DualChannelDdrSmramNonCacheable,
+  DualChannelDdrGraphicsMemoryCacheable,
+  DualChannelDdrGraphicsMemoryNonCacheable,
+  DualChannelDdrReservedMemory,
+  DualChannelDdrMaxMemoryRangeType
+} DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE;
+
+//
+// Memory map range information
+//
+typedef struct {
+  EFI_PHYSICAL_ADDRESS                          PhysicalAddress;
+  EFI_PHYSICAL_ADDRESS                          CpuAddress;
+  EFI_PHYSICAL_ADDRESS                          RangeLength;
+  DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE                 Type;
+} DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE;
+typedef struct {
+    unsigned    dramType        :1;                 /**< Type: 0 = RESERVED; 1 = DDR2 */
+    unsigned    dramWidth       :1;                 /**< Width: 0 = x8; 1 = x16 */
+    unsigned    dramDensity     :2;                 /**< Density: 00b = 2Gb; 01b = 1Gb; 10b = 512Mb; 11b = 256Mb */
+    unsigned    dramSpeed       :1;                 /**< Speed Grade: 0 = RESERVED; 1 = 800MT/s;*/
+    unsigned    dramTimings     :3;                 /**< Timings: 4-4-4, 5-5-5, 6-6-6 */
+    unsigned    dramRanks       :1;                 /**< Ranks: 0 = Single Rank; 1 = Dual Rank */
+} DramGeometry;                                     /**< DRAM Geometry Descriptor */
+
+typedef union _RegDRP {
+    UINT32    raw;
+    struct {
+        unsigned rank0Enabled       :1;     /**< Rank 0 Enable */
+        unsigned rank0DevWidth      :2;     /**< DRAM Device Width (x8,x16) */
+        unsigned rank0DevDensity    :2;     /**< DRAM Device Density (256Mb,512Mb,1Gb,2Gb) */
+        unsigned reserved2          :1;
+        unsigned rank1Enabled       :1;     /**< Rank 1 Enable */
+        unsigned reserved3          :5;
+        unsigned dramType           :1;     /**< DRAM Type (0=DDR2) */
+        unsigned reserved4          :5;
+        unsigned reserved5          :14;
+      } field;
+} RegDRP;                                   /**< DRAM Rank Population and Interface Register */
+
+
+typedef union {
+    UINT32    raw;
+    struct {
+        unsigned dramFrequency      :3;     /**< DRAM Frequency (000=RESERVED,010=667,011=800) */
+        unsigned tRP                :2;     /**< Precharge to Activate Delay (3,4,5,6) */
+        unsigned reserved1          :1;
+        unsigned tRCD               :2;     /**< Activate to CAS Delay (3,4,5,6) */
+        unsigned reserved2          :1;
+        unsigned tCL                :2;     /**< CAS Latency (3,4,5,6) */
+        unsigned reserved3          :21;
+      } field;
+} RegDTR0;                                  /**< DRAM Timing Register 0 */
+
+typedef union {
+    UINT32    raw;
+    struct {
+        unsigned tWRRD_dly          :2;     /**< Additional Write to Read Delay (0,1,2,3) */
+        unsigned reserved1          :1;
+        unsigned tRDWR_dly          :2;     /**< Additional Read to Write Delay (0,1,2,3) */
+        unsigned reserved2          :1;
+        unsigned tRDRD_dr_dly       :1;     /**< Additional Read to Read Delay (1,2) */
+        unsigned reserved3          :1;
+        unsigned tRD_dly            :3;     /**< Additional Read Data Sampling Delay (0-7) */
+        unsigned reserved4          :1;
+        unsigned tRCVEN_halfclk_dly :4;     /**< Additional RCVEN Half Clock Delay Control */
+        unsigned reserved5          :1;
+        unsigned readDqDelay        :2;     /**< Read DQ Delay */
+        unsigned reserved6          :13;
+      } field;
+} RegDTR1;                                  /**< DRAM Timing Register 1 */
+
+typedef union {
+    UINT32    raw;
+    struct {
+        unsigned ckStaticDisable    :1;     /**< CK/CK# Static Disable */
+        unsigned reserved1          :3;
+        unsigned ckeStaticDisable   :2;     /**< CKE Static Disable */
+        unsigned reserved2          :8;
+        unsigned refreshPeriod      :2;     /**< Refresh Period (disabled,128clks,3.9us,7.8us) */
+        unsigned refreshQueueDepth  :2;     /**< Refresh Queue Depth (1,2,4,8) */
+        unsigned reserved5          :13;
+        unsigned initComplete       :1;     /**< Initialization Complete */
+      } field;
+} RegDCO;
+
+//
+// MRC Data Structure
+//
+typedef struct {
+    RegDRP          drp;
+    RegDTR0         dtr0;
+    RegDTR1         dtr1;
+    RegDCO          dco;
+    UINT32          reg0104;
+    UINT32          reg0120;
+    UINT32          reg0121;
+    UINT32          reg0123;
+    UINT32          reg0111;
+    UINT32          reg0130;
+    UINT8           refreshPeriod;      /**< Placeholder for the chosen refresh
+                                         *   period.  This value will NOT be
+                                         *   programmed into DCO until all
+                                         *   initialization is done.
+                                         */
+    UINT8           ddr2Odt;            /**< 0 = Disabled, 1 = 75 ohm, 2 = 150ohm, 3 = 50ohm */
+    UINT8           sku;                /**< Detected QuarkNcSocId SKU */
+    UINT8           capabilities;       /**< Capabilities Available on this part */
+    UINT8           state;              /**< NORMAL_BOOT, S3_RESUME */
+    UINT32          memSize;            /**< Memory size */
+    UINT16          pmBase;             /**< PM Base */
+    UINT16          mrcVersion;         /**< MRC Version */
+    UINT32          hecbase;            /**< HECBASE shifted left 16 bits */
+    DramGeometry    geometry;          /**< DRAM Geometry */
+} MRC_DATA_STRUCTURE;             /**< QuarkNcSocId Memory Parameters for MRC */
+
+typedef struct _EFI_MEMINIT_CONFIG_DATA {
+  MRC_DATA_STRUCTURE                        MrcData;
+} EFI_MEMINIT_CONFIG_DATA;
+
+
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h
new file mode 100644
index 0000000000..8c21640f8c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h
@@ -0,0 +1,17 @@
+/** @file
+Public include file for the QNC Base
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __INTEL_QNC_BASE_H__
+#define __INTEL_QNC_BASE_H__
+
+#include <IntelQNCRegs.h>
+#include <IntelQNCConfig.h>
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h
new file mode 100644
index 0000000000..17c03a1c72
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h
@@ -0,0 +1,100 @@
+/** @file
+Some configuration of QNC Package
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __INTEL_QNC_CONFIG_H__
+#define __INTEL_QNC_CONFIG_H__
+
+//
+// QNC Fixed configurations.
+//
+
+//
+// Memory arbiter fixed config values.
+//
+#define QNC_FIXED_CONFIG_ASTATUS  ((UINT32) (\
+          (ASTATUS_PRI_NORMAL << ASTATUS0_DEFAULT_BP) | \
+          (ASTATUS_PRI_NORMAL << ASTATUS1_DEFAULT_BP) | \
+          (ASTATUS_PRI_URGENT << ASTATUS0_RASISED_BP) | \
+          (ASTATUS_PRI_URGENT << ASTATUS1_RASISED_BP) \
+          ))
+
+//
+// Memory Manager fixed config values.
+//
+#define V_DRAM_NON_HOST_RQ_LIMIT                    2
+
+//
+// RMU Thermal config fixed config values for TS in Vref Mode.
+//
+#define V_TSCGF1_CONFIG_ISNSCURRENTSEL_VREF_MODE    0x04
+#define V_TSCGF2_CONFIG2_ISPARECTRL_VREF_MODE       0x01
+#define V_TSCGF1_CONFIG_IBGEN_VREF_MODE             1
+#define V_TSCGF2_CONFIG_IDSCONTROL_VREF_MODE        0x011b
+#define V_TSCGF2_CONFIG2_ICALCOARSETUNE_VREF_MODE   0x34
+
+//
+// RMU Thermal config fixed config values for TS in Ratiometric mode.
+//
+#define V_TSCGF1_CONFIG_ISNSCURRENTSEL_RATIO_MODE   0x04
+#define V_TSCGF1_CONFIG_ISNSCHOPSEL_RATIO_MODE      0x02
+#define V_TSCGF1_CONFIG_ISNSINTERNALVREFEN_RATIO_MODE 1
+#define V_TSCGF2_CONFIG_IDSCONTROL_RATIO_MODE       0x011f
+#define V_TSCGF2_CONFIG_IDSTIMING_RATIO_MODE        0x0001
+#define V_TSCGF2_CONFIG2_ICALCONFIGSEL_RATIO_MODE   0x01
+#define V_TSCGF2_CONFIG2_ISPARECTRL_RATIO_MODE      0x00
+#define V_TSCGF1_CONFIG_IBGEN_RATIO_MODE            0
+#define V_TSCGF1_CONFIG_IBGCHOPEN_RATIO_MODE        0
+#define V_TSCGF3_CONFIG_ITSGAMMACOEFF_RATIO_MODE    0xC8
+#define V_TSCGF2_CONFIG2_ICALCOARSETUNE_RATIO_MODE  0x17
+
+//
+// iCLK fixed config values.
+//
+#define V_MUXTOP_FLEX2                              3
+#define V_MUXTOP_FLEX1                              1
+
+//
+// PCIe Root Port fixed config values.
+//
+#define V_PCIE_ROOT_PORT_SBIC_VALUE                 (B_QNC_PCIE_IOSFSBCTL_SBIC_IDLE_NEVER)
+
+//
+// QNC structures for configuration.
+//
+
+typedef union {
+  struct {
+    UINT32  PortErrorMask               :8;
+    UINT32  SlotImplemented             :1;
+    UINT32  Reserved1                   :1;
+    UINT32  AspmEnable                  :1;
+    UINT32  AspmAutoEnable              :1;
+    UINT32  AspmL0sEnable               :2;
+    UINT32  AspmL1Enable                :1;
+    UINT32  PmeInterruptEnable          :1;
+    UINT32  PhysicalSlotNumber          :13;
+    UINT32  Reserved2                   :1;
+    UINT32  PmSciEnable                 :1;
+    UINT32  HotplugSciEnable            :1;
+  } Bits;
+  UINT32 Uint32;
+} PCIEXP_ROOT_PORT_CONFIGURATION;
+
+typedef union {
+  UINT32 Uint32;
+  struct {
+    UINT32 Pcie_0     :1;   // 0: Disabled; 1: Enabled*
+    UINT32 Pcie_1     :1;   // 0: Disabled; 1: Enabled*
+    UINT32 Smbus      :1;   // 0: Disabled; 1: Enabled*
+    UINT32 Rsvd       :29;  // 0
+  } Bits;
+} QNC_DEVICE_ENABLES;
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h
new file mode 100644
index 0000000000..45725a4976
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h
@@ -0,0 +1,17 @@
+/** @file
+Public include file for the QNC Dxe
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __INTEL_QNC_DXE_H__
+#define __INTEL_QNC_DXE_H__
+
+#include <IntelQNCRegs.h>
+#include <IntelQNCConfig.h>
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h
new file mode 100644
index 0000000000..90cbe35ef9
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h
@@ -0,0 +1,17 @@
+/** @file
+Public include file for the QNC Pei
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __INTEL_QNC_PEIM_H__
+#define __INTEL_QNC_PEIM_H__
+
+#include <IntelQNCRegs.h>
+#include <IntelQNCConfig.h>
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h
new file mode 100644
index 0000000000..6f6dd8b323
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h
@@ -0,0 +1,48 @@
+/** @file
+Registers definition for Intel QuarkNcSocId.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __INTEL_QNC_REGS_H__
+#define __INTEL_QNC_REGS_H__
+
+#include <QNCAccess.h>
+
+//
+// PCI HostBridge Segment number
+//
+#define QNC_PCI_HOST_BRIDGE_SEGMENT_NUMBER    0
+
+//
+// PCI RootBridge resource allocation's attribute
+//
+#define QNC_PCI_ROOT_BRIDGE_RESOURCE_ALLOCATION_ATTRIBUTE \
+  EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM
+
+//
+// PCI HostBridge resource appeture
+//
+#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSBASE     0x0
+#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSLIMIT    0xff
+#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_TSEG_SIZE   0x10000000
+
+//
+// PCI RootBridge configure port
+//
+#define QNC_PCI_ROOT_BRIDGE_CONFIGURATION_ADDRESS_PORT  0xCF8
+#define QNC_PCI_ROOT_BRIDGE_CONFIGURATION_DATA_PORT     0xCFC
+
+//
+// PCI Rootbridge's support feature
+//
+#define QNC_PCI_ROOT_BRIDGE_SUPPORTED                   (EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | \
+                                                         EFI_PCI_ATTRIBUTE_ISA_IO         | \
+                                                         EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | \
+                                                         EFI_PCI_ATTRIBUTE_VGA_MEMORY     | \
+                                                         EFI_PCI_ATTRIBUTE_VGA_IO)
+
+#endif // __INTEL_QNC_REGS_H__
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h
new file mode 100644
index 0000000000..218fa84917
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h
@@ -0,0 +1,284 @@
+/** @file
+Library that provides QNC specific library services in PEI phase
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __INTEL_QNC_LIB_H__
+#define __INTEL_QNC_LIB_H__
+
+/**
+  This function initializes the QNC register before MRC.
+  It sets RCBA, PMBASE, disable Watchdog timer and initialize QNC GPIO.
+  If the function cannot complete it'll ASSERT().
+**/
+VOID
+EFIAPI
+PeiQNCPreMemInit (
+  VOID
+  );
+
+
+/**
+  Used to check SCH if it's S3 state.  Clear the register state after query.
+
+  @retval TRUE if it's S3 state.
+  @retval FALSE if it's not S3 state.
+
+**/
+BOOLEAN
+EFIAPI
+QNCCheckS3AndClearState (
+   VOID
+  );
+
+/**
+  Used to check SCH if system wakes up from power on reset. Clear the register state after query.
+
+  @retval TRUE  if system wakes up from power on reset
+  @retval FALSE if system does not wake up from power on reset
+
+**/
+BOOLEAN
+EFIAPI
+QNCCheckPowerOnResetAndClearState (
+   VOID
+  );
+
+/**
+  This function is used to clear SMI and wake status.
+
+**/
+VOID
+EFIAPI
+QNCClearSmiAndWake (
+  VOID
+  );
+
+/**
+  Used to initialize the QNC register after MRC.
+
+**/
+VOID
+EFIAPI
+PeiQNCPostMemInit (
+  VOID
+  );
+
+/** Send DRAM Ready opcode.
+
+  @param[in]       OpcodeParam  Parameter to DRAM ready opcode.
+
+  @retval          VOID
+**/
+VOID
+EFIAPI
+QNCSendOpcodeDramReady (
+  IN UINT32   OpcodeParam
+  );
+
+/**
+
+  Relocate RMU Main binary to memory after MRC to improve performance.
+
+  @param[in]  DestBaseAddress  - Specify the new memory address for the RMU Main binary.
+  @param[in]  SrcBaseAddress   - Specify the current memory address for the RMU Main binary.
+  @param[in]  Size             - Specify size of the RMU Main binary.
+
+  @retval     VOID
+
+**/
+VOID
+EFIAPI
+RmuMainRelocation (
+  IN CONST UINT32   DestBaseAddress,
+  IN CONST UINT32   SrcBaseAddress,
+  IN CONST UINTN    Size
+  );
+
+/**
+  Get the total memory size
+
+**/
+UINT32
+EFIAPI
+QNCGetTotalMemorysize (
+  VOID
+  );
+
+/**
+  Get the memory range of TSEG.
+  The TSEG's memory is below TOLM.
+
+  @param[out] BaseAddress The base address of TSEG's memory range
+  @param[out] MemorySize  The size of TSEG's memory range
+
+**/
+VOID
+EFIAPI
+QNCGetTSEGMemoryRange (
+  OUT UINT64  *BaseAddress,
+  OUT UINT64  *MemorySize
+  );
+
+/**
+  Updates the PAM registers in the MCH for the requested range and mode.
+
+  @param   Start        The start address of the memory region
+  @param   Length       The length, in bytes, of the memory region
+  @param   ReadEnable   Pointer to the boolean variable on whether to enable read for legacy memory section.
+                        If NULL, then read attribute will not be touched by this call.
+  @param   ReadEnable   Pointer to the boolean variable on whether to enable write for legacy memory section.
+                        If NULL, then write attribute will not be touched by this call.
+  @param   Granularity  A pointer to granularity, in bytes, that the PAM registers support
+
+  @retval  RETURN_SUCCESS            The PAM registers in the MCH were updated
+  @retval  RETURN_INVALID_PARAMETER  The memory range is not valid in legacy region.
+
+**/
+RETURN_STATUS
+EFIAPI
+QNCLegacyRegionManipulation (
+  IN  UINT32                  Start,
+  IN  UINT32                  Length,
+  IN  BOOLEAN                 *ReadEnable,
+  IN  BOOLEAN                 *WriteEnable,
+  OUT UINT32                  *Granularity
+  );
+
+/**
+  Do early init of pci express rootports on Soc.
+
+**/
+VOID
+EFIAPI
+PciExpressEarlyInit (
+  VOID
+  );
+
+/**
+  Complete initialization of all the pci express rootports on Soc.
+**/
+EFI_STATUS
+EFIAPI
+PciExpressInit (
+  );
+
+/**
+  Determine if QNC is supported.
+
+  @retval FALSE  QNC is not supported.
+  @retval TRUE   QNC is supported.
+**/
+BOOLEAN
+EFIAPI
+IsQncSupported (
+  VOID
+  );
+
+/**
+  Get the DeviceId of the SoC
+
+  @retval PCI DeviceId of the SoC
+**/
+UINT16
+EFIAPI
+QncGetSocDeviceId (
+  VOID
+  );
+
+/**
+  Enable SMI detection of legacy flash access violations.
+**/
+VOID
+EFIAPI
+QncEnableLegacyFlashAccessViolationSmi (
+  VOID
+  );
+
+/**
+  Setup RMU Thermal sensor registers for Vref mode.
+**/
+VOID
+EFIAPI
+QNCThermalSensorSetVRefMode (
+  VOID
+  );
+
+/**
+  Setup RMU Thermal sensor registers for Ratiometric mode.
+**/
+VOID
+EFIAPI
+QNCThermalSensorSetRatiometricMode (
+  VOID
+  );
+
+/**
+  Setup RMU Thermal sensor trip point values.
+
+  @param[in]  CatastrophicTripOnDegreesCelsius  - Catastrophic set trip point threshold.
+  @param[in]  HotTripOnDegreesCelsius           - Hot set trip point threshold.
+  @param[in]  HotTripOffDegreesCelsius          - Hot clear trip point threshold.
+
+  @retval     VOID
+**/
+EFI_STATUS
+EFIAPI
+QNCThermalSensorSetTripValues (
+  IN  CONST UINTN             CatastrophicTripOnDegreesCelsius,
+  IN  CONST UINTN             HotTripOnDegreesCelsius,
+  IN  CONST UINTN             HotTripOffDegreesCelsius
+  );
+
+/**
+  Enable RMU Thermal sensor with a Catastrophic Trip point.
+
+  @retval  EFI_SUCCESS            Trip points setup.
+  @retval  EFI_INVALID_PARAMETER  Invalid trip point value.
+
+**/
+EFI_STATUS
+EFIAPI
+QNCThermalSensorEnableWithCatastrophicTrip (
+  IN  CONST UINTN             CatastrophicTripOnDegreesCelsius
+  );
+
+/**
+  Lock all RMU Thermal sensor control & trip point registers.
+
+**/
+VOID
+EFIAPI
+QNCThermalSensorLockAllRegisters (
+  VOID
+  );
+
+/**
+  Set chipset policy for double bit ECC error.
+
+  @param[in]       PolicyValue  Policy to config on double bit ECC error.
+
+**/
+VOID
+EFIAPI
+QNCPolicyDblEccBitErr (
+  IN  CONST UINT32                        PolicyValue
+  );
+
+/**
+  Determine if running on secure Quark hardware Sku.
+
+  @retval FALSE  Base Quark Sku or unprovisioned Secure Sku running.
+  @retval TRUE   Provisioned SecureSku hardware running.
+**/
+BOOLEAN
+EFIAPI
+QncIsSecureProvisionedSku (
+  VOID
+  );
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h
new file mode 100644
index 0000000000..290902c67f
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h
@@ -0,0 +1,161 @@
+/** @file
+Library functions for Setting QNC internal network port
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __QNC_ACCESS_LIB_H__
+#define __QNC_ACCESS_LIB_H__
+
+#include <IntelQNCRegs.h>
+
+#define MESSAGE_READ_DW(Port, Reg)  \
+        (UINT32)((QUARK_OPCODE_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
+
+#define MESSAGE_WRITE_DW(Port, Reg)  \
+        (UINT32)((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
+
+#define ALT_MESSAGE_READ_DW(Port, Reg)  \
+        (UINT32)((QUARK_ALT_OPCODE_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
+
+#define ALT_MESSAGE_WRITE_DW(Port, Reg)  \
+        (UINT32)((QUARK_ALT_OPCODE_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
+
+#define MESSAGE_IO_READ_DW(Port, Reg)  \
+        (UINT32)((QUARK_OPCODE_IO_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
+
+#define MESSAGE_IO_WRITE_DW(Port, Reg)  \
+        (UINT32)((QUARK_OPCODE_IO_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
+
+#define MESSAGE_SHADOW_DW(Port, Reg)  \
+        (UINT32)((QUARK_DRAM_BASE_ADDR_READY << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
+
+
+/**
+  Read required data from QNC internal message network
+**/
+UINT32
+EFIAPI
+QNCPortRead(
+  UINT8 Port,
+  UINT32 RegAddress
+  );
+
+/**
+  Write prepared data into QNC internal message network.
+
+**/
+VOID
+EFIAPI
+QNCPortWrite (
+  UINT8 Port,
+  UINT32 RegAddress,
+  UINT32 WriteValue
+  );
+
+/**
+  Read required data from QNC internal message network
+**/
+UINT32
+EFIAPI
+QNCAltPortRead(
+  UINT8 Port,
+  UINT32 RegAddress
+  );
+
+/**
+  Write prepared data into QNC internal message network.
+
+**/
+VOID
+EFIAPI
+QNCAltPortWrite (
+  UINT8 Port,
+  UINT32 RegAddress,
+  UINT32 WriteValue
+  );
+
+/**
+  Read required data from QNC internal message network
+**/
+UINT32
+EFIAPI
+QNCPortIORead(
+  UINT8 Port,
+  UINT32 RegAddress
+  );
+
+/**
+  Write prepared data into QNC internal message network.
+
+**/
+VOID
+EFIAPI
+QNCPortIOWrite (
+  UINT8 Port,
+  UINT32 RegAddress,
+  UINT32 WriteValue
+  );
+
+/**
+  This is for the special consideration for QNC MMIO write, as required by FWG,
+  a reading must be performed after MMIO writing to ensure the expected write
+  is processed and data is flushed into chipset
+
+**/
+RETURN_STATUS
+EFIAPI
+QNCMmIoWrite (
+  UINT32             MmIoAddress,
+  QNC_MEM_IO_WIDTH    Width,
+  UINT32             DataNumber,
+  VOID               *pData
+  );
+
+UINT32
+EFIAPI
+QncHsmmcRead (
+  VOID
+  );
+
+VOID
+EFIAPI
+QncHsmmcWrite (
+  UINT32 WriteValue
+  );
+
+VOID
+EFIAPI
+QncImrWrite (
+  UINT32 ImrBaseOffset,
+  UINT32 ImrLow,
+  UINT32 ImrHigh,
+  UINT32 ImrReadMask,
+  UINT32 ImrWriteMask
+  );
+
+VOID
+EFIAPI
+QncIClkAndThenOr (
+  UINT32 RegAddress,
+  UINT32 AndValue,
+  UINT32 OrValue
+  );
+
+VOID
+EFIAPI
+QncIClkOr (
+  UINT32 RegAddress,
+  UINT32 OrValue
+  );
+
+UINTN
+EFIAPI
+QncGetPciExpressBaseAddress (
+  VOID
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h
new file mode 100644
index 0000000000..a68ecc4566
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h
@@ -0,0 +1,57 @@
+/** @file
+QNC Smm Library Services header file.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __QNC_SMM_LIB_H__
+#define __QNC_SMM_LIB_H__
+
+/**
+  This routine is the chipset code that accepts a request to "open" a region of SMRAM.
+  The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
+  The use of "open" means that the memory is visible from all boot-service
+  and SMM agents.
+
+  @retval FALSE  Cannot open a locked SMRAM region
+  @retval TRUE   Success to open SMRAM region.
+**/
+BOOLEAN
+EFIAPI
+QNCOpenSmramRegion (
+  VOID
+  );
+
+/**
+  This routine is the chipset code that accepts a request to "close" a region of SMRAM.
+  The region could be legacy AB or TSEG near top of physical memory.
+  The use of "close" means that the memory is only visible from SMM agents,
+  not from BS or RT code.
+
+  @retval FALSE  Cannot open a locked SMRAM region
+  @retval TRUE   Success to open SMRAM region.
+**/
+BOOLEAN
+EFIAPI
+QNCCloseSmramRegion (
+  VOID
+  );
+
+/**
+  This routine is the chipset code that accepts a request to "lock" SMRAM.
+  The region could be legacy AB or TSEG near top of physical memory.
+  The use of "lock" means that the memory can no longer be opened
+  to BS state.
+**/
+VOID
+EFIAPI
+QNCLockSmramRegion (
+  VOID
+  );
+
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h
new file mode 100644
index 0000000000..498a42b18b
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h
@@ -0,0 +1,36 @@
+/** @file
+Memory Initialization PPI used in EFI PEI interface
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __QNC_MEMORY_INIT_H__
+#define __QNC_MEMORY_INIT_H__
+
+#include "mrc.h"
+
+#define PEI_QNC_MEMORY_INIT_PPI_GUID \
+  {0x21ff1fee, 0xd33a, 0x4fce, {0xa6, 0x5e, 0x95, 0x5e, 0xa3, 0xc4, 0x1f, 0x40}}
+
+
+
+
+//
+// PPI Function Declarations
+//
+typedef
+VOID
+(EFIAPI *PEI_QNC_MEMORY_INIT) (
+  IN OUT    MRCParams_t     *MRCDATA
+  );
+
+typedef struct _PEI_QNC_MEMORY_INIT_PPI {
+  PEI_QNC_MEMORY_INIT     MrcStart;
+}PEI_QNC_MEMORY_INIT_PPI;
+
+extern EFI_GUID gQNCMemoryInitPpiGuid;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h
new file mode 100644
index 0000000000..18e7f5c4dd
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h
@@ -0,0 +1,48 @@
+/** @file
+This file defines the QNC Info Protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+#ifndef _PCH_INFO_H_
+#define _PCH_INFO_H_
+
+//
+// Extern the GUID for protocol users.
+//
+extern EFI_GUID                       gEfiQncInfoProtocolGuid;
+
+//
+// Forward reference for ANSI C compatibility
+//
+typedef struct _EFI_QNC_INFO_PROTOCOL EFI_QNC_INFO_PROTOCOL;
+
+//
+// Protocol revision number
+// Any backwards compatible changes to this protocol will result in an update in the revision number
+// Major changes will require publication of a new protocol
+//
+// Revision 1:  Original version
+// Revision 2:   Add RCVersion item to EFI_QNC_INFO_PROTOCOL
+//
+#define QNC_INFO_PROTOCOL_REVISION_1  1
+#define QNC_INFO_PROTOCOL_REVISION_2  2
+
+//
+// RCVersion[7:0] is the release number.
+//
+#define QNC_RC_VERSION                0x01020000
+
+//
+// Protocol definition
+//
+struct _EFI_QNC_INFO_PROTOCOL {
+  UINT8   Revision;
+  UINT8   BusNumber;
+  UINT32  RCVersion;
+};
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h
new file mode 100644
index 0000000000..ad79ae3e87
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h
@@ -0,0 +1,31 @@
+/** @file
+Protocol used for Platform Policy definition.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _PLATFORM_POLICY_H_
+#define _PLATFORM_POLICY_H_
+
+typedef struct _EFI_PLATFORM_POLICY_PROTOCOL EFI_PLATFORM_POLICY_PROTOCOL;
+
+#define EFI_PLATFORM_POLICY_PROTOCOL_GUID \
+  { \
+    0x2977064f, 0xab96, 0x4fa9, { 0x85, 0x45, 0xf9, 0xc4, 0x02, 0x51, 0xe0, 0x7f } \
+  }
+
+//
+// Protocol to describe various platform information. Add to this as needed.
+//
+struct _EFI_PLATFORM_POLICY_PROTOCOL {
+  UINT8 NumRsvdSmbusAddresses;
+  UINT8 *RsvdSmbusAddresses;
+};
+
+extern EFI_GUID gEfiPlatformPolicyProtocolGuid;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h
new file mode 100644
index 0000000000..d9d697d844
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h
@@ -0,0 +1,84 @@
+/** @file
+This file defines the QNC S3 support Protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+#ifndef _QNC_S3_SUPPORT_PROTOCOL_H_
+#define _QNC_S3_SUPPORT_PROTOCOL_H_
+
+//
+// Extern the GUID for protocol users.
+//
+extern EFI_GUID                             gEfiQncS3SupportProtocolGuid;
+
+//
+// Forward reference for ANSI C compatibility
+//
+typedef struct _EFI_QNC_S3_SUPPORT_PROTOCOL EFI_QNC_S3_SUPPORT_PROTOCOL;
+
+typedef enum {
+  QncS3ItemTypeInitPcieRootPortDownstream,
+  QncS3ItemTypeMax
+} EFI_QNC_S3_DISPATCH_ITEM_TYPE;
+
+//
+// It's better not to use pointer here because the size of pointer in DXE is 8, but it's 4 in PEI
+// plug 4 to ParameterSize in PEIM if you really need it
+//
+typedef struct {
+  UINT32                        Reserved;
+} EFI_QNC_S3_PARAMETER_INIT_PCIE_ROOT_PORT_DOWNSTREAM;
+
+typedef union {
+  EFI_QNC_S3_PARAMETER_INIT_PCIE_ROOT_PORT_DOWNSTREAM   PcieRootPortData;
+} EFI_DISPATCH_CONTEXT_UNION;
+
+typedef struct {
+  EFI_QNC_S3_DISPATCH_ITEM_TYPE Type;
+  VOID                          *Parameter;
+} EFI_QNC_S3_DISPATCH_ITEM;
+
+//
+// Member functions
+//
+typedef
+EFI_STATUS
+(EFIAPI *EFI_QNC_S3_SUPPORT_SET_S3_DISPATCH_ITEM) (
+  IN     EFI_QNC_S3_SUPPORT_PROTOCOL   * This,
+  IN     EFI_QNC_S3_DISPATCH_ITEM      * DispatchItem,
+  OUT    VOID                         **S3DispatchEntryPoint,
+  OUT    VOID                         **Context
+  );
+
+/*++
+
+Routine Description:
+
+  Set an item to be dispatched at S3 resume time. At the same time, the entry point
+  of the QNC S3 support image is returned to be used in subsequent boot script save
+  call
+
+Arguments:
+
+  This                    - Pointer to the protocol instance.
+  DispatchItem            - The item to be dispatched.
+  S3DispatchEntryPoint    - The entry point of the QNC S3 support image.
+
+Returns:
+
+  EFI_STATUS
+
+--*/
+
+//
+// Protocol definition
+//
+struct _EFI_QNC_S3_SUPPORT_PROTOCOL {
+  EFI_QNC_S3_SUPPORT_SET_S3_DISPATCH_ITEM SetDispatchItem;
+};
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h
new file mode 100644
index 0000000000..57d919bc5a
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h
@@ -0,0 +1,115 @@
+/** @file
+Intel-only SMM Child Dispatcher Protocol.
+
+This protocol provides a parent dispatch service for a collection of
+chipset-specific SMI source.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __SMM_ICHN_DISPATCH2_H__
+#define __SMM_ICHN_DISPATCH2_H__
+
+//
+// Share some common definitions with Framework SMM
+//
+#include <Protocol/SmmIchnDispatch.h>
+
+#include <PiSmm.h>
+
+//
+// Global ID for the ICH SMI Protocol
+//
+#define EFI_SMM_ICHN_DISPATCH2_PROTOCOL_GUID \
+  { \
+    0xadf3a128, 0x416d, 0x4060, {0x8d, 0xdf, 0x30, 0xa1, 0xd7, 0xaa, 0xb6, 0x99 } \
+  }
+
+typedef struct _EFI_SMM_ICHN_DISPATCH2_PROTOCOL EFI_SMM_ICHN_DISPATCH2_PROTOCOL;
+
+typedef struct {
+  EFI_SMM_ICHN_SMI_TYPE Type;
+} EFI_SMM_ICHN_REGISTER_CONTEXT;
+
+//
+// Member functions
+//
+/**
+  Register a child SMI source dispatch function with a parent SMM driver
+
+  @param  This                  Protocol instance pointer.
+  @param  DispatchFunction      Pointer to dispatch function to be invoked for
+                                this SMI source
+  @param  RegisterContext       Pointer to the dispatch function's context.
+                                The caller fills this context in before calling
+                                the register function to indicate to the register
+                                function the ICHN SMI source for which the dispatch
+                                function should be invoked.
+  @param  DispatchHandle        Handle generated by the dispatcher to track the
+                                function instance.
+
+  @retval EFI_SUCCESS           The dispatch function has been successfully
+                                registered and the SMI source has been enabled.
+  @retval EFI_DEVICE_ERROR      The driver was unable to enable the SMI source.
+  @retval EFI_OUT_OF_RESOURCES  Not enough memory (system or SMM) to manage this
+                                child.
+  @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The ICHN input value
+                                is not within valid range.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SMM_ICHN_DISPATCH2_REGISTER) (
+  IN CONST EFI_SMM_ICHN_DISPATCH2_PROTOCOL   *This,
+  IN       EFI_SMM_HANDLER_ENTRY_POINT2      DispatchFunction,
+  IN OUT   EFI_SMM_ICHN_REGISTER_CONTEXT     *RegisterContext,
+     OUT   EFI_HANDLE                        *DispatchHandle
+  );
+
+/**
+  Unregister a child SMI source dispatch function with a parent SMM driver
+
+  @param  This                  Protocol instance pointer.
+  @param  DispatchHandle        Handle of dispatch function to deregister.
+
+  @retval EFI_SUCCESS           The dispatch function has been successfully
+                                unregistered and the SMI source has been disabled
+                                if there are no other registered child dispatch
+                                functions for this SMI source.
+  @retval EFI_INVALID_PARAMETER Handle is invalid.
+  @retval other
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SMM_ICHN_DISPATCH2_UNREGISTER) (
+  IN EFI_SMM_ICHN_DISPATCH2_PROTOCOL          *This,
+  IN EFI_HANDLE                               DispatchHandle
+  );
+
+//
+// Interface structure for the SMM Ich n specific SMI Dispatch Protocol
+//
+/**
+  @par Protocol Description:
+  Provides a parent dispatch service for ICH SMI sources.
+
+  @param Register
+  Installs a child service to be dispatched by this protocol.
+
+  @param UnRegister
+  Removes a child service dispatched by this protocol.
+
+**/
+struct _EFI_SMM_ICHN_DISPATCH2_PROTOCOL {
+  EFI_SMM_ICHN_DISPATCH2_REGISTER   Register;
+  EFI_SMM_ICHN_DISPATCH2_UNREGISTER UnRegister;
+};
+
+extern EFI_GUID gEfiSmmIchnDispatch2ProtocolGuid;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h
new file mode 100644
index 0000000000..ee549baa9b
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h
@@ -0,0 +1,345 @@
+/** @file
+This file defines the EFI SPI Protocol which implements the
+Intel(R) ICH SPI Host Controller Compatibility Interface.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+#ifndef _SPI_H_
+#define _SPI_H_
+
+//
+// Define the SPI protocol GUID
+//
+// EDK and EDKII have different GUID formats
+//
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#define EFI_SPI_PROTOCOL_GUID \
+  { \
+    0x1156efc6, 0xea32, 0x4396, 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 \
+  }
+#define EFI_SMM_SPI_PROTOCOL_GUID \
+  { \
+    0xD9072C35, 0xEB8F, 0x43ad, 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 \
+  }
+#else
+#define EFI_SPI_PROTOCOL_GUID \
+  { \
+    0x1156efc6, 0xea32, 0x4396, \
+    { \
+      0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 \
+    } \
+  }
+#define EFI_SMM_SPI_PROTOCOL_GUID \
+  { \
+    0xD9072C35, 0xEB8F, 0x43ad, \
+    { \
+      0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 \
+    } \
+  }
+#endif
+//
+// Extern the GUID for protocol users.
+//
+extern EFI_GUID                   gEfiSpiProtocolGuid;
+extern EFI_GUID                   gEfiSmmSpiProtocolGuid;
+
+//
+// Forward reference for ANSI C compatibility
+//
+typedef struct _EFI_SPI_PROTOCOL  EFI_SPI_PROTOCOL;
+
+//
+// SPI protocol data structures and definitions
+//
+//
+// Number of Prefix Opcodes allowed on the SPI interface
+//
+#define SPI_NUM_PREFIX_OPCODE 2
+
+//
+// Number of Opcodes in the Opcode Menu
+//
+#define SPI_NUM_OPCODE  8
+
+#ifdef SERVER_BIOS_FLAG
+//
+// SPI default opcode slots
+//
+#define SPI_OPCODE_JEDEC_ID_INDEX        0
+#endif // SERVER_BIOS_FLAG
+
+//
+// Opcode Type
+//    EnumSpiOpcodeCommand: Command without address
+//    EnumSpiOpcodeRead: Read with address
+//    EnumSpiOpcodeWrite: Write with address
+//
+typedef enum {
+  EnumSpiOpcodeReadNoAddr,
+  EnumSpiOpcodeWriteNoAddr,
+  EnumSpiOpcodeRead,
+  EnumSpiOpcodeWrite,
+  EnumSpiOpcodeMax
+} SPI_OPCODE_TYPE;
+
+typedef enum {
+  EnumSpiCycle20MHz,
+  EnumSpiCycle33MHz,
+  EnumSpiCycle66MHz,  // not supported by PCH
+  EnumSpiCycle50MHz,
+  EnumSpiCycleMax
+} SPI_CYCLE_FREQUENCY;
+
+typedef enum {
+  EnumSpiRegionAll,
+  EnumSpiRegionBios,
+  EnumSpiRegionMe,
+  EnumSpiRegionGbE,
+  EnumSpiRegionDescriptor,
+  EnumSpiRegionPlatformData,
+  EnumSpiRegionMax
+} SPI_REGION_TYPE;
+
+//
+// Hardware Sequencing required operations (as listed in CougarPoint EDS Table 5-55: "Hardware
+// Sequencing Commands and Opcode Requirements"
+//
+typedef enum {
+  EnumSpiOperationWriteStatus,
+  EnumSpiOperationProgramData_1_Byte,
+  EnumSpiOperationProgramData_64_Byte,
+  EnumSpiOperationReadData,
+  EnumSpiOperationWriteDisable,
+  EnumSpiOperationReadStatus,
+  EnumSpiOperationWriteEnable,
+  EnumSpiOperationFastRead,
+  EnumSpiOperationEnableWriteStatus,
+  EnumSpiOperationErase_256_Byte,
+  EnumSpiOperationErase_4K_Byte,
+  EnumSpiOperationErase_8K_Byte,
+  EnumSpiOperationErase_64K_Byte,
+  EnumSpiOperationFullChipErase,
+  EnumSpiOperationJedecId,
+  EnumSpiOperationDualOutputFastRead,
+  EnumSpiOperationDiscoveryParameters,
+  EnumSpiOperationOther,
+  EnumSpiOperationMax
+} SPI_OPERATION;
+
+//
+// Opcode menu entries
+//   Type            Operation Type (value to be programmed to the OPTYPE register)
+//   Code            The opcode (value to be programmed to the OPMENU register)
+//   Frequency       The expected frequency to be used (value to be programmed to the SSFC
+//                   Register)
+//   Operation       Which Hardware Sequencing required operation this opcode respoinds to.
+//                   The required operations are listed in EDS Table 5-55: "Hardware
+//                   Sequencing Commands and Opcode Requirements"
+//                   If the opcode does not corresponds to any operation listed, use
+//                   EnumSpiOperationOther
+//
+typedef struct _SPI_OPCODE_MENU_ENTRY {
+  SPI_OPCODE_TYPE     Type;
+  UINT8               Code;
+  SPI_CYCLE_FREQUENCY Frequency;
+  SPI_OPERATION       Operation;
+} SPI_OPCODE_MENU_ENTRY;
+
+//
+// Initialization data table loaded to the SPI host controller
+//    VendorId        Vendor ID of the SPI device
+//    DeviceId0       Device ID0 of the SPI device
+//    DeviceId1       Device ID1 of the SPI device
+//    PrefixOpcode    Prefix opcodes which are loaded into the SPI host controller
+//    OpcodeMenu      Opcodes which are loaded into the SPI host controller Opcode Menu
+//    BiosStartOffset The offset of the start of the BIOS image relative to the flash device.
+//                    Please note this is a Flash Linear Address, NOT a memory space address.
+//                    This value is platform specific and depends on the system flash map.
+//                    This value is only used on non Descriptor mode.
+//    BiosSize        The the BIOS Image size in flash. This value is platform specific
+//                    and depends on the system flash map. Please note BIOS Image size may
+//                    be smaller than BIOS Region size (in Descriptor Mode) or the flash size
+//                    (in Non Descriptor Mode), and in this case, BIOS Image is supposed to be
+//                    placed at the top end of the BIOS Region (in Descriptor Mode) or the flash
+//                    (in Non Descriptor Mode)
+//
+typedef struct _SPI_INIT_TABLE {
+  UINT8                 VendorId;
+  UINT8                 DeviceId0;
+  UINT8                 DeviceId1;
+  UINT8                 PrefixOpcode[SPI_NUM_PREFIX_OPCODE];
+  SPI_OPCODE_MENU_ENTRY OpcodeMenu[SPI_NUM_OPCODE];
+  UINTN                 BiosStartOffset;
+  UINTN                 BiosSize;
+} SPI_INIT_TABLE;
+
+//
+// Public Info struct to show current initialized state of the spi interface.
+// OpcodeIndex must be less then SPI_NUM_OPCODE for operation to be supported.
+//
+typedef struct _SPI_INIT_INFO {
+  SPI_INIT_TABLE        *InitTable;
+  UINT8                 JedecIdOpcodeIndex;
+  UINT8                 OtherOpcodeIndex;
+  UINT8                 WriteStatusOpcodeIndex;
+  UINT8                 ProgramOpcodeIndex;
+  UINT8                 ReadOpcodeIndex;
+  UINT8                 EraseOpcodeIndex;
+  UINT8                 ReadStatusOpcodeIndex;
+  UINT8                 FullChipEraseOpcodeIndex;
+} SPI_INIT_INFO;
+
+//
+// Protocol member functions
+//
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SPI_INIT) (
+  IN EFI_SPI_PROTOCOL     * This,
+  IN SPI_INIT_TABLE       * InitTable
+  );
+/*++
+
+Routine Description:
+
+  Initializes the host controller to execute SPI commands.
+
+Arguments:
+
+  This                    Pointer to the EFI_SPI_PROTOCOL instance.
+  InitTable               Pointer to caller-allocated buffer containing the SPI
+                          interface initialization table.
+
+Returns:
+
+  EFI_SUCCESS             Opcode initialization on the SPI host controller completed.
+  EFI_ACCESS_DENIED       The SPI configuration interface is locked.
+  EFI_OUT_OF_RESOURCES    Not enough resource available to initialize the device.
+  EFI_DEVICE_ERROR        Device error, operation failed.
+
+--*/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SPI_LOCK) (
+  IN EFI_SPI_PROTOCOL     * This
+  );
+/*++
+
+Routine Description:
+
+  Lock the SPI Static Configuration Interface.
+  Once locked, the interface is no longer open for configuration changes.
+  The lock state automatically clears on next system reset.
+
+Arguments:
+
+  This      Pointer to the EFI_SPI_PROTOCOL instance.
+
+Returns:
+
+  EFI_SUCCESS             Lock operation succeed.
+  EFI_DEVICE_ERROR        Device error, operation failed.
+  EFI_ACCESS_DENIED       The interface has already been locked.
+
+--*/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SPI_EXECUTE) (
+  IN     EFI_SPI_PROTOCOL   * This,
+  IN     UINT8              OpcodeIndex,
+  IN     UINT8              PrefixOpcodeIndex,
+  IN     BOOLEAN            DataCycle,
+  IN     BOOLEAN            Atomic,
+  IN     BOOLEAN            ShiftOut,
+  IN     UINTN              Address,
+  IN     UINT32             DataByteCount,
+  IN OUT UINT8              *Buffer,
+  IN     SPI_REGION_TYPE    SpiRegionType
+  );
+/*++
+
+Routine Description:
+
+  Execute SPI commands from the host controller.
+
+Arguments:
+
+  This                    Pointer to the EFI_SPI_PROTOCOL instance.
+  OpcodeIndex             Index of the command in the OpCode Menu.
+  PrefixOpcodeIndex       Index of the first command to run when in an atomic cycle sequence.
+  DataCycle               TRUE if the SPI cycle contains data
+  Atomic                  TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+  ShiftOut                If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+  Address                 In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+                          Region, this value specifies the offset from the Region Base; for BIOS Region,
+                          this value specifies the offset from the start of the BIOS Image. In Non
+                          Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+                          Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+                          Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+                          supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+                          the flash (in Non Descriptor Mode)
+  DataByteCount           Number of bytes in the data portion of the SPI cycle.
+  Buffer                  Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle.
+  SpiRegionType           SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+                          EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+                          Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+                          and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+                          to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+Returns:
+
+  EFI_SUCCESS             Command succeed.
+  EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  EFI_UNSUPPORTED         Command not supported.
+  EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+--*/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SPI_INFO) (
+  IN EFI_SPI_PROTOCOL     *This,
+  OUT SPI_INIT_INFO      **InitInfoPtr
+  );
+/*++
+
+Routine Description:
+
+  Return info about SPI host controller, to help callers usage of Execute
+  service.
+
+  If 0xff is returned as an opcode index in init info struct
+  then device does not support the operation.
+
+Arguments:
+
+  This                    Pointer to the EFI_SPI_PROTOCOL instance.
+  InitInfoPtr             Pointer to init info written to this memory location.
+
+Returns:
+
+  EFI_SUCCESS             Information returned.
+  EFI_INVALID_PARAMETER   Invalid parameter.
+  EFI_NOT_READY           Required resources not setup.
+  Others                  Unexpected error happened.
+
+--*/
+
+//
+// Protocol definition
+//
+struct _EFI_SPI_PROTOCOL {
+  EFI_SPI_INIT    Init;
+  EFI_SPI_LOCK    Lock;
+  EFI_SPI_EXECUTE Execute;
+  EFI_SPI_INFO    Info;
+};
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h
new file mode 100644
index 0000000000..a03454369c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h
@@ -0,0 +1,177 @@
+/** @file
+Macros to simplify and abstract the interface to PCI configuration.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _QNC_ACCESS_H_
+#define _QNC_ACCESS_H_
+
+#include "QuarkNcSocId.h"
+#include "QNCCommonDefinitions.h"
+
+#define EFI_LPC_PCI_ADDRESS( Register ) \
+  EFI_PCI_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, Register)
+
+//
+// QNC Controller PCI access macros
+//
+#define QNC_RCRB_BASE (QNCMmio32 (PciDeviceMmBase (0, PCI_DEVICE_NUMBER_QNC_LPC, 0), R_QNC_LPC_RCBA) & B_QNC_LPC_RCBA_MASK)
+
+//
+// Device 0x1f, Function 0
+//
+
+#define LpcPciCfg32( Register ) \
+  QNCMmPci32(0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register )
+
+#define LpcPciCfg32Or( Register, OrData ) \
+  QNCMmPci32Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData )
+
+#define LpcPciCfg32And( Register, AndData ) \
+  QNCMmPci32And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData )
+
+#define LpcPciCfg32AndThenOr( Register, AndData, OrData ) \
+  QNCMmPci32AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData )
+
+#define LpcPciCfg16( Register ) \
+  QNCMmPci16( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register )
+
+#define LpcPciCfg16Or( Register, OrData ) \
+  QNCMmPci16Or(  0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData )
+
+#define LpcPciCfg16And( Register, AndData ) \
+  QNCMmPci16And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData )
+
+#define LpcPciCfg16AndThenOr( Register, AndData, OrData ) \
+  QNCMmPci16AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData )
+
+#define LpcPciCfg8( Register ) \
+  QNCMmPci8( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register )
+
+#define LpcPciCfg8Or( Register, OrData ) \
+  QNCMmPci8Or(  0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData )
+
+#define LpcPciCfg8And( Register, AndData ) \
+  QNCMmPci8And(  0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData )
+
+#define LpcPciCfg8AndThenOr( Register, AndData, OrData ) \
+  QNCMmPci8AndThenOr(  0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData )
+
+//
+// Root Complex Register Block
+//
+
+#define MmRcrb32( Register ) \
+  QNCMmio32( QNC_RCRB_BASE, Register )
+
+#define MmRcrb32Or( Register, OrData ) \
+  QNCMmio32Or( QNC_RCRB_BASE, Register, OrData )
+
+#define MmRcrb32And( Register, AndData ) \
+  QNCMmio32And( QNC_RCRB_BASE, Register, AndData )
+
+#define MmRcrb32AndThenOr( Register, AndData, OrData ) \
+  QNCMmio32AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData )
+
+#define MmRcrb16( Register ) \
+  QNCMmio16( QNC_RCRB_BASE, Register )
+
+#define MmRcrb16Or( Register, OrData ) \
+  QNCMmio16Or( QNC_RCRB_BASE, Register, OrData )
+
+#define MmRcrb16And( Register, AndData ) \
+  QNCMmio16And( QNC_RCRB_BASE, Register, AndData )
+
+#define MmRcrb16AndThenOr( Register, AndData, OrData ) \
+  QNCMmio16AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData )
+
+#define MmRcrb8( Register ) \
+  QNCMmio8( QNC_RCRB_BASE, Register )
+
+#define MmRcrb8Or( Register, OrData ) \
+  QNCMmio8Or( QNC_RCRB_BASE, Register, OrData )
+
+#define MmRcrb8And( Register, AndData ) \
+  QNCMmio8And( QNC_RCRB_BASE, Register, AndData )
+
+#define MmRcrb8AndThenOr( Register, AndData, OrData ) \
+  QNCMmio8AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData )
+
+//
+// Memory Controller PCI access macros
+//
+
+//
+// Device 0, Function 0
+//
+
+#define McD0PciCfg64(Register)                              QNCMmPci32           (0, MC_BUS, 0, 0, Register)
+#define McD0PciCfg64Or(Register, OrData)                    QNCMmPci32Or         (0, MC_BUS, 0, 0, Register, OrData)
+#define McD0PciCfg64And(Register, AndData)                  QNCMmPci32And        (0, MC_BUS, 0, 0, Register, AndData)
+#define McD0PciCfg64AndThenOr(Register, AndData, OrData)    QNCMmPci32AndThenOr  (0, MC_BUS, 0, 0, Register, AndData, OrData)
+
+#define McD0PciCfg32(Register)                              QNCMmPci32           (0, MC_BUS, 0, 0, Register)
+#define McD0PciCfg32Or(Register, OrData)                    QNCMmPci32Or         (0, MC_BUS, 0, 0, Register, OrData)
+#define McD0PciCfg32And(Register, AndData)                  QNCMmPci32And        (0, MC_BUS, 0, 0, Register, AndData)
+#define McD0PciCfg32AndThenOr(Register, AndData, OrData)    QNCMmPci32AndThenOr  (0, MC_BUS, 0, 0, Register, AndData, OrData)
+
+#define McD0PciCfg16(Register)                              QNCMmPci16           (0, MC_BUS, 0, 0, Register)
+#define McD0PciCfg16Or(Register, OrData)                    QNCMmPci16Or         (0, MC_BUS, 0, 0, Register, OrData)
+#define McD0PciCfg16And(Register, AndData)                  QNCMmPci16And        (0, MC_BUS, 0, 0, Register, AndData)
+#define McD0PciCfg16AndThenOr(Register, AndData, OrData)    QNCMmPci16AndThenOr  (0, MC_BUS, 0, 0, Register, AndData, OrData)
+
+#define McD0PciCfg8(Register)                               QNCMmPci8            (0, MC_BUS, 0, 0, Register)
+#define McD0PciCfg8Or(Register, OrData)                     QNCMmPci8Or          (0, MC_BUS, 0, 0, Register, OrData)
+#define McD0PciCfg8And(Register, AndData)                   QNCMmPci8And         (0, MC_BUS, 0, 0, Register, AndData)
+#define McD0PciCfg8AndThenOr( Register, AndData, OrData )   QNCMmPci8AndThenOr   (0, MC_BUS, 0, 0, Register, AndData, OrData)
+
+
+//
+// Memory Controller Hub Memory Mapped IO register access ???
+//
+#define MCH_REGION_BASE                     (McD0PciCfg64 (MC_MCHBAR_OFFSET) & ~BIT0)
+#define McMmioAddress(Register)             ((UINTN) MCH_REGION_BASE + (UINTN) (Register))
+
+#define McMmio32Ptr(Register)               ((volatile UINT32*) McMmioAddress (Register))
+#define McMmio64Ptr(Register)               ((volatile UINT64*) McMmioAddress (Register))
+
+#define McMmio64(Register)                            *McMmio64Ptr( Register )
+#define McMmio64Or(Register, OrData)                  (McMmio64 (Register) |= (UINT64)(OrData))
+#define McMmio64And(Register, AndData)                (McMmio64 (Register) &= (UINT64)(AndData))
+#define McMmio64AndThenOr(Register, AndData, OrData)  (McMmio64 ( Register ) = (McMmio64( Register ) & (UINT64)(AndData)) | (UINT64)(OrData))
+
+#define McMmio32(Register)                            *McMmio32Ptr (Register)
+#define McMmio32Or(Register, OrData)                  (McMmio32 (Register) |= (UINT32)(OrData))
+#define McMmio32And(Register, AndData)                (McMmio32 (Register) &= (UINT32)(AndData))
+#define McMmio32AndThenOr(Register, AndData, OrData)  (McMmio32 (Register) = (McMmio32 (Register) & (UINT32) (AndData)) | (UINT32) (OrData))
+
+#define McMmio16Ptr(Register)                         ((volatile UINT16*) McMmioAddress (Register))
+#define McMmio16(Register)                            *McMmio16Ptr (Register)
+#define McMmio16Or(Register, OrData)                  (McMmio16 (Register) |= (UINT16) (OrData))
+#define McMmio16And(Register, AndData)                (McMmio16 (Register) &= (UINT16) (AndData))
+#define McMmio16AndThenOr(Register, AndData, OrData)  (McMmio16 (Register) = (McMmio16 (Register) & (UINT16) (AndData)) | (UINT16) (OrData))
+
+#define McMmio8Ptr(Register)                          ((volatile UINT8 *)McMmioAddress (Register))
+#define McMmio8(Register)                             *McMmio8Ptr (Register)
+#define McMmio8Or(Register, OrData)                   (McMmio8 (Register) |= (UINT8) (OrData))
+#define McMmio8And(Register, AndData)                 (McMmio8 (Register) &= (UINT8) (AndData))
+#define McMmio8AndThenOr(Register, AndData, OrData)   (McMmio8 (Register) = (McMmio8 (Register) & (UINT8) (AndData)) | (UINT8) (OrData))
+
+//
+// QNC memory mapped related data structure deifinition
+//
+typedef enum {
+  QNCMmioWidthUint8  = 0,
+  QNCMmioWidthUint16 = 1,
+  QNCMmioWidthUint32 = 2,
+  QNCMmioWidthUint64 = 3,
+  QNCMmioWidthMaximum
+} QNC_MEM_IO_WIDTH;
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h
new file mode 100644
index 0000000000..1e0451302b
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h
@@ -0,0 +1,350 @@
+/** @file
+This header file provides common definitions just for MCH using to avoid including extra module's file.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _QNC_COMMON_DEFINITIONS_H_
+#define _QNC_COMMON_DEFINITIONS_H_
+
+//
+// PCI CONFIGURATION MAP REGISTER OFFSETS
+//
+#ifndef PCI_VID
+#define PCI_VID             0x0000        // Vendor ID Register
+#define PCI_DID             0x0002        // Device ID Register
+#define PCI_CMD             0x0004        // PCI Command Register
+#define PCI_STS             0x0006        // PCI Status Register
+#define PCI_RID             0x0008        // Revision ID Register
+#define PCI_IFT             0x0009        // Interface Type
+#define PCI_SCC             0x000A        // Sub Class Code Register
+#define PCI_BCC             0x000B        // Base Class Code Register
+#define PCI_CLS             0x000C        // Cache Line Size
+#define PCI_PMLT            0x000D        // Primary Master Latency Timer
+#define PCI_HDR             0x000E        // Header Type Register
+#define PCI_BIST            0x000F        // Built in Self Test Register
+#define PCI_BAR0            0x0010        // Base Address Register 0
+#define PCI_BAR1            0x0014        // Base Address Register 1
+#define PCI_BAR2            0x0018        // Base Address Register 2
+#define PCI_PBUS            0x0018        // Primary Bus Number Register
+#define PCI_SBUS            0x0019        // Secondary Bus Number Register
+#define PCI_SUBUS           0x001A        // Subordinate Bus Number Register
+#define PCI_SMLT            0x001B        // Secondary Master Latency Timer
+#define PCI_BAR3            0x001C        // Base Address Register 3
+#define PCI_IOBASE          0x001C        // I/O base Register
+#define PCI_IOLIMIT         0x001D        // I/O Limit Register
+#define PCI_SECSTATUS       0x001E        // Secondary Status Register
+#define PCI_BAR4            0x0020        // Base Address Register 4
+#define PCI_MEMBASE         0x0020        // Memory Base Register
+#define PCI_MEMLIMIT        0x0022        // Memory Limit Register
+#define PCI_BAR5            0x0024        // Base Address Register 5
+#define PCI_PRE_MEMBASE     0x0024        // Prefetchable memory Base register
+#define PCI_PRE_MEMLIMIT    0x0026        // Prefetchable memory Limit register
+#define PCI_PRE_MEMBASE_U   0x0028        // Prefetchable memory base upper 32 bits
+#define PCI_PRE_MEMLIMIT_U  0x002C        // Prefetchable memory limit upper 32 bits
+#define PCI_SVID            0x002C        // Subsystem Vendor ID
+#define PCI_SID             0x002E        // Subsystem ID
+#define PCI_IOBASE_U        0x0030        // I/O base Upper Register
+#define PCI_IOLIMIT_U       0x0032        // I/O Limit Upper Register
+#define PCI_CAPP            0x0034        // Capabilities Pointer
+#define PCI_EROM            0x0038        // Expansion ROM Base Address
+#define PCI_INTLINE         0x003C        // Interrupt Line Register
+#define PCI_INTPIN          0x003D        // Interrupt Pin Register
+#define PCI_MAXGNT          0x003E        // Max Grant Register
+#define PCI_BRIDGE_CNTL     0x003E        // Bridge Control Register
+#define PCI_MAXLAT          0x003F        // Max Latency Register
+#endif
+//
+// Bit Difinitions
+//
+#ifndef BIT0
+#define BIT0                     0x0001
+#define BIT1                     0x0002
+#define BIT2                     0x0004
+#define BIT3                     0x0008
+#define BIT4                     0x0010
+#define BIT5                     0x0020
+#define BIT6                     0x0040
+#define BIT7                     0x0080
+#define BIT8                     0x0100
+#define BIT9                     0x0200
+#define BIT10                    0x0400
+#define BIT11                    0x0800
+#define BIT12                    0x1000
+#define BIT13                    0x2000
+#define BIT14                    0x4000
+#define BIT15                    0x8000
+#define BIT16                0x00010000
+#define BIT17                0x00020000
+#define BIT18                0x00040000
+#define BIT19                0x00080000
+#define BIT20                0x00100000
+#define BIT21                0x00200000
+#define BIT22                0x00400000
+#define BIT23                0x00800000
+#define BIT24                0x01000000
+#define BIT25                0x02000000
+#define BIT26                0x04000000
+#define BIT27                0x08000000
+#define BIT28                0x10000000
+#define BIT29                0x20000000
+#define BIT30                0x40000000
+#define BIT31                0x80000000
+#endif
+
+
+//
+//  Common Memory mapped Io access macros ------------------------------------------
+//
+#define QNCMmioAddress( BaseAddr, Register ) \
+    ( (UINTN)BaseAddr + \
+      (UINTN)(Register) \
+    )
+
+//
+// UINT64
+//
+#define QNCMmio64Ptr( BaseAddr, Register ) \
+    ( (volatile UINT64 *)QNCMmioAddress( BaseAddr, Register ) )
+
+#define QNCMmio64( BaseAddr, Register ) \
+    *QNCMmio64Ptr( BaseAddr, Register )
+
+#define QNCMmio64Or( BaseAddr, Register, OrData ) \
+    QNCMmio64( BaseAddr, Register ) = \
+      (UINT64) ( \
+        QNCMmio64( BaseAddr, Register ) | \
+        (UINT64)(OrData) \
+      )
+
+#define QNCMmio64And( BaseAddr, Register, AndData ) \
+    QNCMmio64( BaseAddr, Register ) = \
+      (UINT64) ( \
+        QNCMmio64( BaseAddr, Register ) & \
+        (UINT64)(AndData) \
+      )
+
+#define QNCMmio64AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    QNCMmio64( BaseAddr, Register ) = \
+      (UINT64) ( \
+        ( QNCMmio64( BaseAddr, Register ) & \
+            (UINT64)(AndData) \
+        ) | \
+        (UINT64)(OrData) \
+      )
+
+//
+// UINT32
+//
+#define QNCMmio32Ptr( BaseAddr, Register ) \
+    ( (volatile UINT32 *)QNCMmioAddress( BaseAddr, Register ) )
+
+#define QNCMmio32( BaseAddr, Register ) \
+    *QNCMmio32Ptr( BaseAddr, Register )
+
+#define QNCMmio32Or( BaseAddr, Register, OrData ) \
+    QNCMmio32( BaseAddr, Register ) = \
+      (UINT32) ( \
+        QNCMmio32( BaseAddr, Register ) | \
+        (UINT32)(OrData) \
+      )
+
+#define QNCMmio32And( BaseAddr, Register, AndData ) \
+    QNCMmio32( BaseAddr, Register ) = \
+      (UINT32) ( \
+        QNCMmio32( BaseAddr, Register ) & \
+        (UINT32)(AndData) \
+      )
+
+#define QNCMmio32AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    QNCMmio32( BaseAddr, Register ) = \
+      (UINT32) ( \
+        ( QNCMmio32( BaseAddr, Register ) & \
+            (UINT32)(AndData) \
+        ) | \
+        (UINT32)(OrData) \
+      )
+//
+// UINT16
+//
+
+#define QNCMmio16Ptr( BaseAddr, Register ) \
+    ( (volatile UINT16 *)QNCMmioAddress( BaseAddr, Register ) )
+
+#define QNCMmio16( BaseAddr, Register ) \
+    *QNCMmio16Ptr( BaseAddr, Register )
+
+#define QNCMmio16Or( BaseAddr, Register, OrData ) \
+    QNCMmio16( BaseAddr, Register ) = \
+      (UINT16) ( \
+        QNCMmio16( BaseAddr, Register ) | \
+        (UINT16)(OrData) \
+      )
+
+#define QNCMmio16And( BaseAddr, Register, AndData ) \
+    QNCMmio16( BaseAddr, Register ) = \
+      (UINT16) ( \
+        QNCMmio16( BaseAddr, Register ) & \
+        (UINT16)(AndData) \
+      )
+
+#define QNCMmio16AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    QNCMmio16( BaseAddr, Register ) = \
+      (UINT16) ( \
+        ( QNCMmio16( BaseAddr, Register ) & \
+            (UINT16)(AndData) \
+        ) | \
+        (UINT16)(OrData) \
+      )
+//
+// UINT8
+//
+#define QNCMmio8Ptr( BaseAddr, Register ) \
+    ( (volatile UINT8 *)QNCMmioAddress( BaseAddr, Register ) )
+
+#define QNCMmio8( BaseAddr, Register ) \
+    *QNCMmio8Ptr( BaseAddr, Register )
+
+#define QNCMmio8Or( BaseAddr, Register, OrData ) \
+    QNCMmio8( BaseAddr, Register ) = \
+      (UINT8) ( \
+        QNCMmio8( BaseAddr, Register ) | \
+        (UINT8)(OrData) \
+      )
+
+#define QNCMmio8And( BaseAddr, Register, AndData ) \
+    QNCMmio8( BaseAddr, Register ) = \
+      (UINT8) ( \
+        QNCMmio8( BaseAddr, Register ) & \
+        (UINT8)(AndData) \
+      )
+
+#define QNCMmio8AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    QNCMmio8( BaseAddr, Register ) = \
+      (UINT8) ( \
+        ( QNCMmio8( BaseAddr, Register ) & \
+            (UINT8)(AndData) \
+          ) | \
+        (UINT8)(OrData) \
+      )
+
+//
+//  Common Memory mapped Pci access macros ------------------------------------------
+//
+
+#define QNCMmPciAddress( Segment, Bus, Device, Function, Register ) \
+  ( (UINTN) QncGetPciExpressBaseAddress() + \
+    (UINTN)(Bus << 20) + \
+    (UINTN)(Device << 15) + \
+    (UINTN)(Function << 12) + \
+    (UINTN)(Register) \
+  )
+
+//
+// Macro to calculate the Pci device's base memory mapped address
+//
+#define PciDeviceMmBase( Bus, Device, Function) \
+    ( (UINTN) QncGetPciExpressBaseAddress () + \
+      (UINTN)(Bus << 20) + \
+      (UINTN)(Device << 15) + \
+      (UINTN)(Function << 12) \
+    )
+
+//
+// UINT32
+//
+#define QNCMmPci32Ptr( Segment, Bus, Device, Function, Register ) \
+  ( (volatile UINT32 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define QNCMmPci32( Segment, Bus, Device, Function, Register ) \
+  *QNCMmPci32Ptr( Segment, Bus, Device, Function, Register )
+
+#define QNCMmPci32Or( Segment, Bus, Device, Function, Register, OrData ) \
+  QNCMmPci32( Segment, Bus, Device, Function, Register ) = \
+    (UINT32) ( \
+      QNCMmPci32( Segment, Bus, Device, Function, Register ) | \
+      (UINT32)(OrData) \
+    )
+
+#define QNCMmPci32And( Segment, Bus, Device, Function, Register, AndData ) \
+  QNCMmPci32( Segment, Bus, Device, Function, Register ) = \
+    (UINT32) ( \
+      QNCMmPci32( Segment, Bus, Device, Function, Register ) & \
+      (UINT32)(AndData) \
+    )
+
+#define QNCMmPci32AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+  QNCMmPci32( Segment, Bus, Device, Function, Register ) = \
+    (UINT32) ( \
+      ( QNCMmPci32( Segment, Bus, Device, Function, Register ) & \
+          (UINT32)(AndData) \
+      ) | \
+      (UINT32)(OrData) \
+    )
+//
+// UINT16
+//
+#define QNCMmPci16Ptr( Segment, Bus, Device, Function, Register ) \
+  ( (volatile UINT16 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define QNCMmPci16( Segment, Bus, Device, Function, Register ) \
+  *QNCMmPci16Ptr( Segment, Bus, Device, Function, Register )
+
+#define QNCMmPci16Or( Segment, Bus, Device, Function, Register, OrData ) \
+  QNCMmPci16( Segment, Bus, Device, Function, Register ) = \
+    (UINT16) ( \
+      QNCMmPci16( Segment, Bus, Device, Function, Register ) | \
+      (UINT16)(OrData) \
+    )
+
+#define QNCMmPci16And( Segment, Bus, Device, Function, Register, AndData ) \
+  QNCMmPci16( Segment, Bus, Device, Function, Register ) = \
+    (UINT16) ( \
+      QNCMmPci16( Segment, Bus, Device, Function, Register ) & \
+      (UINT16)(AndData) \
+    )
+
+#define QNCMmPci16AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+  QNCMmPci16( Segment, Bus, Device, Function, Register ) = \
+    (UINT16) ( \
+      ( QNCMmPci16( Segment, Bus, Device, Function, Register ) & \
+          (UINT16)(AndData) \
+      ) | \
+      (UINT16)(OrData) \
+    )
+//
+// UINT8
+//
+#define QNCMmPci8Ptr( Segment, Bus, Device, Function, Register ) \
+  ( (volatile UINT8 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define QNCMmPci8( Segment, Bus, Device, Function, Register ) \
+  *QNCMmPci8Ptr( Segment, Bus, Device, Function, Register )
+
+#define QNCMmPci8Or( Segment, Bus, Device, Function, Register, OrData ) \
+  QNCMmPci8( Segment, Bus, Device, Function, Register ) = \
+    (UINT8) ( \
+      QNCMmPci8( Segment, Bus, Device, Function, Register ) | \
+      (UINT8)(OrData) \
+    )
+
+#define QNCMmPci8And( Segment, Bus, Device, Function, Register, AndData ) \
+  QNCMmPci8( Segment, Bus, Device, Function, Register ) = \
+    (UINT8) ( \
+      QNCMmPci8( Segment, Bus, Device, Function, Register ) & \
+      (UINT8)(AndData) \
+    )
+
+#define QNCMmPci8AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+  QNCMmPci8( Segment, Bus, Device, Function, Register ) = \
+    (UINT8) ( \
+      ( QNCMmPci8( Segment, Bus, Device, Function, Register ) & \
+          (UINT8)(AndData) \
+        ) | \
+      (UINT8)(OrData) \
+    )
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h
new file mode 100644
index 0000000000..33aab21f1d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h
@@ -0,0 +1,751 @@
+/** @file
+QuarkNcSocId Register Definitions
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Definitions beginning with "R_" are registers
+Definitions beginning with "B_" are bits within registers
+Definitions beginning with "V_" are meaningful values of bits within the registers
+Definitions beginning with "S_" are register sizes
+Definitions beginning with "N_" are the bit position
+
+**/
+
+#ifndef _QUARK_NC_SOC_ID_H_
+#define _QUARK_NC_SOC_ID_H_
+
+//
+// QNC GMCH Equates
+//
+
+//
+// DEVICE 0 (Memroy Controller Hub)
+//
+#define MC_BUS                  PCI_BUS_NUMBER_QNC
+#define MC_DEV                  0x00
+#define MC_FUN                  0x00
+
+#define   QUARK_MC_VENDOR_ID      V_INTEL_VENDOR_ID
+#define   QUARK_MC_DEVICE_ID      0x0958
+#define   QUARK2_MC_DEVICE_ID     0x12C0
+#define   QNC_MC_REV_ID_A0      0x00
+
+
+//
+// MCR - B0:D0:F0:RD0h (WO)- Message control register
+// [31:24] Message opcode - D0 read; E0 write;
+// [23:16] Message port
+// [15:8 ] Message target register address
+// [ 7:4 ] Message write byte enable : F is enable
+// [ 3:0 ] Reserved
+//
+#define QNC_ACCESS_PORT_MCR              0xD0          // Message Control Register
+// Always Set to 0xF0
+
+//
+//MDR - B0:D0:F0:RD4h (RW)- Message data register
+//
+#define QNC_ACCESS_PORT_MDR              0xD4          // Message Data Register
+
+//
+//MEA - B0:D0:F0:RD8h (RW)- Message extended address register
+//
+#define QNC_ACCESS_PORT_MEA              0xD8          // Message Extended Address Register
+
+#define  QNC_MCR_OP_OFFSET           24           // Offset of the opcode field in MCR
+#define  QNC_MCR_PORT_OFFSET         16           // Offset of the port field in MCR
+#define  QNC_MCR_REG_OFFSET          8            // Offset of the register field in MCR
+
+//
+// Misc Useful Macros
+//
+
+#define LShift16(value) (value << 16)
+
+//
+// QNC Message OpCodes and Attributes
+//
+#define QUARK_OPCODE_READ              0x10         // Quark message bus "read" opcode
+#define QUARK_OPCODE_WRITE             0x11         // Quark message bus "write" opcode
+
+//
+// Alternative opcodes for the SCSS block
+//
+#define QUARK_ALT_OPCODE_READ          0x06         // Quark message bus "read" opcode
+#define QUARK_ALT_OPCODE_WRITE         0x07         // Quark message bus "write" opcode
+
+//
+// QNC Message OpCodes and Attributes for IO
+//
+#define QUARK_OPCODE_IO_READ           0x02         // Quark message bus "IO read" opcode
+#define QUARK_OPCODE_IO_WRITE          0x03         // Quark message bus "IO write" opcode
+
+
+#define QUARK_DRAM_BASE_ADDR_READY     0x78         // Quark message bus "RMU Main binary shadow" opcode
+
+#define QUARK_ECC_SCRUB_RESUME         0xC2         // Quark Remote Management Unit "scrub resume" opcode
+#define QUARK_ECC_SCRUB_PAUSE          0xC3         // Quark Remote Management Unit "scrub pause" opcode
+
+//
+// QNC Message Ports and Registers
+//
+// Start of SB Port IDs
+#define QUARK_NC_MEMORY_ARBITER_SB_PORT_ID    0x00
+#define QUARK_NC_MEMORY_CONTROLLER_SB_PORT_ID 0x01
+#define QUARK_NC_HOST_BRIDGE_SB_PORT_ID       0x03
+#define QUARK_NC_RMU_SB_PORT_ID               0x04
+#define QUARK_NC_MEMORY_MANAGER_SB_PORT_ID    0x05
+#define QUARK_SC_USB_AFE_SB_PORT_ID           0x14
+#define QUARK_SC_PCIE_AFE_SB_PORT_ID          0x16
+#define QUARK_SCSS_SOC_UNIT_SB_PORT_ID        0x31
+#define QUARK_SCSS_FUSE_SB_PORT_ID            0x33
+#define QUARK_ICLK_SB_PORT_ID                 0x32
+#define QUARK_SCSS_CRU_SB_PORT_ID             0x34
+
+//
+// Quark Memory Arbiter Registers.
+//
+#define   QUARK_NC_MEMORY_ARBITER_REG_ASTATUS     0x21        // Memory Arbiter PRI Status encodings register.
+#define   ASTATUS_PRI_CASUAL                    0x0         // Serviced only if convenient
+#define   ASTATUS_PRI_IMPENDING                 0x1         // Serviced if the DRAM is in Self-Refresh.
+#define   ASTATUS_PRI_NORMAL                    0x2         // Normal request servicing.
+#define   ASTATUS_PRI_URGENT                    0x3         // Urgent request servicing.
+#define   ASTATUS1_RASISED_BP                   (10)
+#define   ASTATUS1_RASISED_BP_MASK              (0x03 << ASTATUS1_RASISED_BP)
+#define   ASTATUS0_RASISED_BP                   (8)
+#define   ASTATUS0_RASISED_BP_MASK              (0x03 << ASTATUS1_RASISED_BP)
+#define   ASTATUS1_DEFAULT_BP                   (2)
+#define   ASTATUS1_DEFAULT_BP_MASK              (0x03 << ASTATUS1_RASISED_BP)
+#define   ASTATUS0_DEFAULT_BP                   (0)
+#define   ASTATUS0_DEFAULT_BP_MASK              (0x03 << ASTATUS1_RASISED_BP)
+
+//
+// Quark Memory Controller Registers.
+//
+#define QUARK_NC_MEMORY_CONTROLLER_REG_DFUSESTAT  0x70        // Fuse status register.
+#define   B_DFUSESTAT_ECC_DIS                     (BIT0)    // Disable ECC.
+
+//
+// Quark Remote Management Unit Registers.
+//
+#define QNC_MSG_TMPM_REG_PMBA                   0x70        // Power Management I/O Base Address
+
+#define QUARK_NC_RMU_REG_CONFIG                   0x71        // Remote Management Unit configuration register.
+#define   TS_LOCK_AUX_TRIP_PT_REGS_ENABLE         (BIT6)
+#define   TS_LOCK_THRM_CTRL_REGS_ENABLE           (BIT5)
+
+#define QUARK_NC_RMU_REG_OPTIONS_1              0x72        // Remote Management Unit Options register 1.
+#define   OPTIONS_1_DMA_DISABLE                   (BIT0)
+
+#define QUARK_NC_RMU_REG_WDT_CONTROL              0x74        // Remote Management Unit Watchdog control register.
+#define   B_WDT_CONTROL_DBL_ECC_BIT_ERR_MASK      (BIT19 | BIT18)
+#define   B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP        18
+#define   V_WDT_CONTROL_DBL_ECC_BIT_ERR_NONE      (0x0 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)
+#define   V_WDT_CONTROL_DBL_ECC_BIT_ERR_CAT       (0x1 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)
+#define   V_WDT_CONTROL_DBL_ECC_BIT_ERR_WARM      (0x2 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)
+#define   V_WDT_CONTROL_DBL_ECC_BIT_ERR_SERR      (0x3 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)
+
+#define QUARK_NC_RMU_REG_TS_MODE                  0xB0        // Remote Management Unit Thermal sensor mode register.
+#define   TS_ENABLE                               (BIT15)
+#define QUARK_NC_RMU_REG_TS_TRIP                  0xB2        // Remote Management Unit Thermal sensor programmable trip point register.
+#define   TS_HOT_TRIP_CLEAR_THOLD_BP              24
+#define   TS_HOT_TRIP_CLEAR_THOLD_MASK            (0xFF << TS_HOT_TRIP_CLEAR_THOLD_BP)
+#define   TS_CAT_TRIP_CLEAR_THOLD_BP              16
+#define   TS_CAT_TRIP_CLEAR_THOLD_MASK            (0xFF << TS_CAT_TRIP_CLEAR_THOLD_BP)
+#define   TS_HOT_TRIP_SET_THOLD_BP                8
+#define   TS_HOT_TRIP_SET_THOLD_MASK              (0xFF << TS_HOT_TRIP_SET_THOLD_BP)
+#define   TS_CAT_TRIP_SET_THOLD_BP                0
+#define   TS_CAT_TRIP_SET_THOLD_MASK              (0xFF << TS_CAT_TRIP_SET_THOLD_BP)
+
+#define QUARK_NC_ECC_SCRUB_CONFIG_REG             0x50
+#define   SCRUB_CFG_INTERVAL_SHIFT              0x00
+#define   SCRUB_CFG_INTERVAL_MASK               0xFF
+#define   SCRUB_CFG_BLOCKSIZE_SHIFT             0x08
+#define   SCRUB_CFG_BLOCKSIZE_MASK              0x1F
+#define   SCRUB_CFG_ACTIVE                      (BIT13)
+#define   SCRUB_CFG_INVALID                     0x00000FFF
+
+#define QUARK_NC_ECC_SCRUB_START_MEM_REG          0x76
+#define QUARK_NC_ECC_SCRUB_END_MEM_REG            0x77
+#define QUARK_NC_ECC_SCRUB_NEXT_READ_REG          0x7C
+
+#define SCRUB_RESUME_MSG() ((UINT32)( \
+          (QUARK_ECC_SCRUB_RESUME << QNC_MCR_OP_OFFSET) | \
+          (QUARK_NC_RMU_SB_PORT_ID << QNC_MCR_PORT_OFFSET) | \
+          0xF0))
+
+#define SCRUB_PAUSE_MSG() ((UINT32)( \
+          (QUARK_ECC_SCRUB_PAUSE << QNC_MCR_OP_OFFSET) | \
+          (QUARK_NC_RMU_SB_PORT_ID << QNC_MCR_PORT_OFFSET) | \
+          0xF0))
+
+//
+// Quark Memory Manager Registers
+//
+#define QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK     0x82
+#define   BLOCK_ENABLE_PG                           (1 << 28)
+#define   BLOCK_DISABLE_PG                          (1 << 29)
+#define QUARK_NC_MEMORY_MANAGER_BIMRVCTL              0x19
+#define   EnableIMRInt                                BIT31
+#define QUARK_NC_MEMORY_MANAGER_BSMMVCTL              0x1C
+#define   EnableSMMInt                                BIT31
+#define QUARK_NC_MEMORY_MANAGER_BTHCTRL               0x20
+#define   DRAM_NON_HOST_RQ_LIMIT_BP                   0
+#define   DRAM_NON_HOST_RQ_LIMIT_MASK                 (0x3f << DRAM_NON_HOST_RQ_LIMIT_BP)
+
+#define QUARK_NC_TOTAL_IMR_SET                        0x8
+#define QUARK_NC_MEMORY_MANAGER_IMR0                  0x40
+#define QUARK_NC_MEMORY_MANAGER_IMR1                  0x44
+#define QUARK_NC_MEMORY_MANAGER_IMR2                  0x48
+#define QUARK_NC_MEMORY_MANAGER_IMR3                  0x4C
+#define QUARK_NC_MEMORY_MANAGER_IMR4                  0x50
+#define QUARK_NC_MEMORY_MANAGER_IMR5                  0x54
+#define QUARK_NC_MEMORY_MANAGER_IMR6                  0x58
+#define QUARK_NC_MEMORY_MANAGER_IMR7                  0x5C
+  #define QUARK_NC_MEMORY_MANAGER_IMRXL               0x00
+    #define IMR_LOCK                                BIT31
+    #define IMR_EN                                  BIT30
+    #define IMRL_MASK                               0x00FFFFFC
+    #define IMRL_RESET                              0x00000000
+  #define QUARK_NC_MEMORY_MANAGER_IMRXH               0x01
+    #define IMRH_MASK                               0x00FFFFFC
+    #define IMRH_RESET                              0x00000000
+  #define QUARK_NC_MEMORY_MANAGER_IMRXRM              0x02
+  #define QUARK_NC_MEMORY_MANAGER_IMRXWM              0x03
+    #define IMRX_ALL_ACCESS                         0xFFFFFFFF
+    #define CPU_SNOOP                               BIT30
+    #define RMU                                     BIT29
+    #define CPU0_NON_SMM                            BIT0
+
+//
+// Quark Host Bridge Registers
+//
+#define QNC_MSG_FSBIC_REG_HMISC                0x03       // Host Misellaneous Controls
+#define   SMI_EN                              (BIT19)     // SMI Global Enable (from Legacy Bridge)
+#define QNC_MSG_FSBIC_REG_HSMMC                0x04       // Host SMM Control
+#define   NON_HOST_SMM_WR_OPEN                (BIT18)     // SMM Writes OPEN
+#define   NON_HOST_SMM_RD_OPEN                (BIT17)     // SMM Writes OPEN
+#define   SMM_CODE_RD_OPEN                    (BIT16)     // SMM Code read OPEN
+#define   SMM_CTL_EN                          (BIT3)      // SMM enable
+#define   SMM_WRITE_OPEN                      (BIT2)      // SMM Writes OPEN
+#define   SMM_READ_OPEN                       (BIT1)      // SMM Reads OPEN
+#define   SMM_LOCKED                          (BIT0)      // SMM Locked
+#define   SMM_START_MASK                      0x0000FFF0
+#define   SMM_END_MASK                        0xFFF00000
+#define QUARK_NC_HOST_BRIDGE_HMBOUND_REG              0x08
+#define   HMBOUND_MASK                        0x0FFFFF000
+#define   HMBOUND_LOCK                        BIT0
+#define QUARK_NC_HOST_BRIDGE_HLEGACY_REG              0x0A
+#define   HLEGACY_SMI_PIN_VALUE               BIT12
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP            0x40
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE       0x41
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000        0x42
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000        0x44
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_A0000        0x46
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C0000         0x48
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C8000         0x4A
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D0000         0x4C
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D8000         0x4E
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E0000         0x50
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E8000         0x52
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F0000         0x54
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000         0x56
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSBASE  0x58
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK  0x59
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0      0x5A
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK0      0x5B
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE1      0x5C
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK1      0x5D
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE2      0x5E
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK2      0x5F
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE3      0x60
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK3      0x61
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE4      0x62
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK4      0x63
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE5      0x64
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK5      0x65
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE6      0x66
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK6      0x67
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE7      0x68
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK7      0x69
+
+//
+// System On Chip Unit (SOCUnit) Registers.
+//
+#define QUARK_SCSS_SOC_UNIT_STPDDRCFG           0x00
+#define   B_STPDDRCFG_FORCE_RECOVERY              BIT0
+#define QUARK_SCSS_SOC_UNIT_SPI_ROM_FUSE    0x25
+#define   B_ROM_FUSE_IN_SECURE_SKU              BIT6
+
+#define QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG       0x31
+#define   B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK   (BIT5 | BIT4 | BIT3)
+#define   B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP     3
+#define   B_TSCGF1_CONFIG_ISNSCHOPSEL_MASK      (BIT12 | BIT11 | BIT10 | BIT9 | BIT8)
+#define   B_TSCGF1_CONFIG_ISNSCHOPSEL_BP        8
+#define   B_TSCGF1_CONFIG_IBGEN                 BIT17
+#define   B_TSCGF1_CONFIG_IBGEN_BP              17
+#define   B_TSCGF1_CONFIG_IBGCHOPEN             BIT18
+#define   B_TSCGF1_CONFIG_IBGCHOPEN_BP          18
+#define   B_TSCGF1_CONFIG_ISNSINTERNALVREFEN    BIT14
+#define   B_TSCGF1_CONFIG_ISNSINTERNALVREFEN_BP 14
+
+#define QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG       0x32
+#define   B_TSCGF2_CONFIG_IDSCONTROL_MASK       0x0000FFFF
+#define   B_TSCGF2_CONFIG_IDSCONTROL_BP         0
+#define   B_TSCGF2_CONFIG_IDSTIMING_MASK        0xFFFF0000
+#define   B_TSCGF2_CONFIG_IDSTIMING_BP          16
+
+#define QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2      0x33
+#define   B_TSCGF2_CONFIG2_ISPARECTRL_MASK      0xFF000000
+#define   B_TSCGF2_CONFIG2_ISPARECTRL_BP        24
+#define   B_TSCGF2_CONFIG2_ICALCONFIGSEL_MASK   (BIT9 | BIT8)
+#define   B_TSCGF2_CONFIG2_ICALCONFIGSEL_BP     8
+#define   B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK  0x000000FF
+#define   B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP    0
+
+#define QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG       0x34
+#define   B_TSCGF3_CONFIG_ITSRST                BIT0
+#define   B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP      11
+#define   B_TSCGF3_CONFIG_ITSGAMMACOEFF_MASK    (0xFFF << B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP)
+
+#define QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG     0x36
+#define   SOCCLKEN_CONFIG_PHY_I_SIDE_RST_L      BIT20
+#define   SOCCLKEN_CONFIG_PHY_I_CMNRESET_L      BIT19
+#define   SOCCLKEN_CONFIG_SBI_BB_RST_B          BIT18
+#define   SOCCLKEN_CONFIG_SBI_RST_100_CORE_B    BIT17
+#define   SOCCLKEN_CONFIG_BB_RST_B              BIT16
+
+#define QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG     0x36
+
+#define QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW       0x51
+#define   B_CFG_STICKY_RW_SMM_VIOLATION         BIT0
+#define   B_CFG_STICKY_RW_HMB_VIOLATION         BIT1
+#define   B_CFG_STICKY_RW_IMR_VIOLATION         BIT2
+#define   B_CFG_STICKY_RW_DECC_VIOLATION        BIT3
+#define   B_CFG_STICKY_RW_WARM_RST              BIT4
+#define   B_CFG_STICKY_RW_FORCE_RECOVERY        BIT9
+#define   B_CFG_STICKY_RW_VIOLATION             (B_CFG_STICKY_RW_SMM_VIOLATION | B_CFG_STICKY_RW_HMB_VIOLATION | B_CFG_STICKY_RW_IMR_VIOLATION | B_CFG_STICKY_RW_DECC_VIOLATION)
+#define   B_CFG_STICKY_RW_ALL                   (B_CFG_STICKY_RW_VIOLATION | B_CFG_STICKY_RW_WARM_RST)
+
+//
+// iCLK Registers.
+//
+#define QUARK_ICLK_MUXTOP                       0x0140
+#define   B_MUXTOP_FLEX2_MASK                   (BIT25 | BIT24 | BIT23)
+#define   B_MUXTOP_FLEX2_BP                     23
+#define   B_MUXTOP_FLEX1_MASK                   (BIT22 | BIT21 | BIT20)
+#define   B_MUXTOP_FLEX1_BP                     20
+
+#define QUARK_ICLK_SSC1                         0x0314
+#define QUARK_ICLK_SSC2                         0x0414
+#define QUARK_ICLK_SSC3                         0x0514
+#define QUARK_ICLK_REF2_DBUFF0                  0x2000
+
+//
+// PCIe AFE Unit Registers (QUARK_SC_PCIE_AFE_SB_PORT_ID).
+//
+#define QUARK_PCIE_AFE_PCIE_RXPICTRL0_L0        0x2080
+#define QUARK_PCIE_AFE_PCIE_RXPICTRL0_L1        0x2180
+#define   OCFGPIMIXLOAD_1_0                   BIT6
+#define   OCFGPIMIXLOAD_1_0_MASK              0xFFFFFF3F
+
+//
+// QNC ICH Equates
+//
+#define V_INTEL_VENDOR_ID              0x8086
+
+#define PCI_BUS_NUMBER_QNC              0x00
+
+//
+// PCI to LPC Bridge Registers (D31:F0)
+//
+#define PCI_DEVICE_NUMBER_QNC_LPC       31
+#define PCI_FUNCTION_NUMBER_QNC_LPC     0
+
+#define R_QNC_LPC_VENDOR_ID             0x00
+#define   V_LPC_VENDOR_ID             V_INTEL_VENDOR_ID
+#define R_QNC_LPC_DEVICE_ID             0x02
+#define   QUARK_V_LPC_DEVICE_ID_0           0x095E
+#define R_QNC_LPC_REV_ID                0x08
+
+#define R_QNC_LPC_SMBUS_BASE            0x40 //~0x43
+#define   B_QNC_LPC_SMBUS_BASE_EN         (BIT31)
+#define   B_QNC_LPC_SMBUS_BASE_MASK       0x0000FFC0 //[15:6]
+//
+// SMBus register offsets from SMBA - "SMBA" (D31:F0:R40h)
+//        Suggested Value for SMBA = 0x1040
+//
+#define R_QNC_SMBUS_HCTL                0x00   // Host Control Register R/W
+#define   B_QNC_SMBUS_START               (BIT4)   // Start/Stop
+#define     V_QNC_SMBUS_HCTL_CMD_QUICK               0
+#define     V_QNC_SMBUS_HCTL_CMD_BYTE                1
+#define     V_QNC_SMBUS_HCTL_CMD_BYTE_DATA           2
+#define     V_QNC_SMBUS_HCTL_CMD_WORD_DATA           3
+#define     V_QNC_SMBUS_HCTL_CMD_PROCESS_CALL        4
+#define     V_QNC_SMBUS_HCTL_CMD_BLOCK               5
+
+#define R_QNC_SMBUS_HSTS                0x01   // Host Status Register R/W
+#define   B_QNC_SMBUS_BERR                (BIT2)   // BUS Error
+#define   B_QNC_SMBUS_DERR                (BIT1)   // Device Error
+#define   B_QNC_SMBUS_BYTE_DONE_STS       (BIT0)   // Completion Status
+#define   B_QNC_SMBUS_HSTS_ALL            0x07
+
+#define R_QNC_SMBUS_HCLK                0x02   // Host Clock Divider Register R/W
+#define     V_QNC_SMBUS_HCLK_100KHZ         0x0054
+
+#define R_QNC_SMBUS_TSA                 0x04   // Transmit Slave Address Register R/W
+#define     V_QNC_SMBUS_RW_SEL_READ         1
+#define     V_QNC_SMBUS_RW_SEL_WRITE        0
+
+#define R_QNC_SMBUS_HCMD                0x05   // Host Command Register R/W
+#define R_QNC_SMBUS_HD0                 0x06   // Data 0 Register R/W
+#define R_QNC_SMBUS_HD1                 0x07   // Data 1 Register R/W
+#define R_QNC_SMBUS_HBD                 0x20   // Host Block Data Register R/W [255:0] ~ 3Fh
+
+#define R_QNC_LPC_GBA_BASE              0x44
+#define   B_QNC_LPC_GPA_BASE_MASK         0x0000FFC0
+//
+// GPIO register offsets from GBA - "GPIO" (D31:F0:R44h)
+//        Suggested Value for GBA = 0x1080
+//
+#define R_QNC_GPIO_CGEN_CORE_WELL       0x00
+#define R_QNC_GPIO_CGIO_CORE_WELL       0x04
+#define R_QNC_GPIO_CGLVL_CORE_WELL      0x08
+#define R_QNC_GPIO_CGTPE_CORE_WELL      0x0C   // Core well GPIO Trigger Positive Edge Enable
+#define R_QNC_GPIO_CGTNE_CORE_WELL      0x10   // Core well GPIO Trigger Negative Edge Enable
+#define R_QNC_GPIO_CGGPE_CORE_WELL      0x14   // Core well GPIO GPE Enable
+#define R_QNC_GPIO_CGSMI_CORE_WELL      0x18   // Core well GPIO SMI Enable
+#define R_QNC_GPIO_CGTS_CORE_WELL       0x1C   // Core well GPIO Trigger Status
+#define R_QNC_GPIO_RGEN_RESUME_WELL     0x20
+#define R_QNC_GPIO_RGIO_RESUME_WELL     0x24
+#define R_QNC_GPIO_RGLVL_RESUME_WELL    0x28
+#define R_QNC_GPIO_RGTPE_RESUME_WELL    0x2C   // Resume well GPIO Trigger Positive Edge Enable
+#define R_QNC_GPIO_RGTNE_RESUME_WELL    0x30   // Resume well GPIO Trigger Negative Edge Enable
+#define R_QNC_GPIO_RGGPE_RESUME_WELL    0x34   // Resume well GPIO GPE Enable
+#define R_QNC_GPIO_RGSMI_RESUME_WELL    0x38   // Resume well GPIO SMI Enable
+#define R_QNC_GPIO_RGTS_RESUME_WELL     0x3C   // Resume well GPIO Trigger Status
+#define R_QNC_GPIO_CNMIEN_CORE_WELL     0x40   // Core well GPIO NMI Enable
+#define R_QNC_GPIO_RNMIEN_RESUME_WELL   0x44   // Resume well GPIO NMI Enable
+
+#define R_QNC_LPC_PM1BLK                0x48
+#define   B_QNC_LPC_PM1BLK_MASK           0x0000FFF0
+//
+// ACPI register offsets from PM1BLK - "ACPI PM1 Block" (D31:F0:R48h)
+//        Suggested Value for PM1BLK = 0x1000
+//
+#define R_QNC_PM1BLK_PM1S               0x00
+#define  S_QNC_PM1BLK_PM1S               2
+#define   B_QNC_PM1BLK_PM1S_ALL           (BIT15+BIT14+BIT10+BIT5+BIT0)
+#define   B_QNC_PM1BLK_PM1S_WAKE          (BIT15)
+#define   B_QNC_PM1BLK_PM1S_PCIEWSTS      (BIT14)
+#define   B_QNC_PM1BLK_PM1S_RTC           (BIT10)
+#define   B_QNC_PM1BLK_PM1S_GLOB          (BIT5)
+#define   B_QNC_PM1BLK_PM1S_TO            (BIT0)
+#define    N_QNC_PM1BLK_PM1S_RTC           10
+
+
+#define R_QNC_PM1BLK_PM1E               0x02
+#define  S_QNC_PM1BLK_PM1E               2
+#define   B_QNC_PM1BLK_PM1E_PWAKED        (BIT14)
+#define   B_QNC_PM1BLK_PM1E_RTC           (BIT10)
+#define   B_QNC_PM1BLK_PM1E_GLOB          (BIT5)
+#define    N_QNC_PM1BLK_PM1E_RTC           10
+
+#define R_QNC_PM1BLK_PM1C               0x04
+#define   B_QNC_PM1BLK_PM1C_SLPEN         (BIT13)
+#define   B_QNC_PM1BLK_PM1C_SLPTP         (BIT12+BIT11+BIT10)
+#define    V_S0                           0x00000000
+#define    V_S3                           0x00001400
+#define    V_S4                           0x00001800
+#define    V_S5                           0x00001C00
+#define   B_QNC_PM1BLK_PM1C_SCIEN         (BIT0)
+
+#define R_QNC_PM1BLK_PM1T               0x08
+
+#define R_QNC_LPC_GPE0BLK               0x4C
+#define   B_QNC_LPC_GPE0BLK_MASK          0x0000FFC0
+//        Suggested Value for GPE0BLK = 0x10C0
+//
+#define R_QNC_GPE0BLK_GPE0S             0x00          // General Purpose Event 0 Status
+#define  S_QNC_GPE0BLK_GPE0S             4
+#define   B_QNC_GPE0BLK_GPE0S_ALL         0x00003F800 // used to clear the status reg
+#define   B_QNC_GPE0BLK_GPE0S_PCIE        (BIT17)     // PCIE
+#define   B_QNC_GPE0BLK_GPE0S_GPIO        (BIT14)     // GPIO
+#define   B_QNC_GPE0BLK_GPE0S_EGPE        (BIT13)     // External GPE
+#define    N_QNC_GPE0BLK_GPE0S_THRM        12
+
+#define R_QNC_GPE0BLK_GPE0E             0x04          // General Purpose Event 0 Enable
+#define  S_QNC_GPE0BLK_GPE0E             4
+#define   B_QNC_GPE0BLK_GPE0E_PCIE        (BIT17)     // PCIE
+#define   B_QNC_GPE0BLK_GPE0E_GPIO        (BIT14)     // GPIO
+#define   B_QNC_GPE0BLK_GPE0E_EGPE        (BIT13)     // External GPE
+#define    N_QNC_GPE0BLK_GPE0E_THRM        12
+
+#define R_QNC_GPE0BLK_SMIE              0x10          // SMI_B Enable
+#define  S_QNC_GPE0BLK_SMIE              4
+#define   B_QNC_GPE0BLK_SMIE_ALL          0x0003871F
+#define   B_QNC_GPE0BLK_SMIE_APM          (BIT4)      // APM
+#define   B_QNC_GPE0BLK_SMIE_SLP          (BIT2)      // Sleep
+#define   B_QNC_GPE0BLK_SMIE_SWT          (BIT1)      // Software Timer
+#define    N_QNC_GPE0BLK_SMIE_GPIO         9
+#define    N_QNC_GPE0BLK_SMIE_ESMI         8
+#define    N_QNC_GPE0BLK_SMIE_APM          4
+#define    N_QNC_GPE0BLK_SMIE_SPI          3
+#define    N_QNC_GPE0BLK_SMIE_SLP          2
+#define    N_QNC_GPE0BLK_SMIE_SWT          1
+
+#define R_QNC_GPE0BLK_SMIS              0x14           // SMI Status Register.
+#define  S_QNC_GPE0BLK_SMIS              4
+#define   B_QNC_GPE0BLK_SMIS_ALL          0x0003871F
+#define   B_QNC_GPE0BLK_SMIS_EOS          (BIT31)      // End of SMI
+#define   B_QNC_GPE0BLK_SMIS_APM          (BIT4)       // APM
+#define   B_QNC_GPE0BLK_SMIS_SPI          (BIT3)       // SPI
+#define   B_QNC_GPE0BLK_SMIS_SLP          (BIT2)       // Sleep
+#define   B_QNC_GPE0BLK_SMIS_SWT          (BIT1)       // Software Timer
+#define   B_QNC_GPE0BLK_SMIS_BIOS         (BIT0)       // BIOS
+#define    N_QNC_GPE0BLK_SMIS_GPIO         9
+#define    N_QNC_GPE0BLK_SMIS_APM          4
+#define    N_QNC_GPE0BLK_SMIS_SPI          3
+#define    N_QNC_GPE0BLK_SMIS_SLP          2
+#define    N_QNC_GPE0BLK_SMIS_SWT          1
+
+#define R_QNC_GPE0BLK_PMCW              0x28            // Power Management Configuration Core Well
+#define   B_QNC_GPE0BLK_PMCW_PSE          (BIT31)       // Periodic SMI Enable
+
+#define R_QNC_GPE0BLK_PMSW              0x2C            // Power Management Configuration Suspend/Resume Well
+#define    B_QNC_GPE0BLK_PMSW_DRAM_INIT   (BIT0)        // Dram Initialization Sctrachpad
+
+#define R_QNC_LPC_ACTL                  0x58
+#define    V_QNC_LPC_ACTL_SCIS_IRQ9        0x00
+
+//
+// Number of PIRQs supported. PIRQA~PIRQH
+//
+#define QNC_NUMBER_PIRQS                8
+#define R_QNC_LPC_PIRQA_ROUT            0x60
+#define R_QNC_LPC_PIRQB_ROUT            0x61
+#define R_QNC_LPC_PIRQC_ROUT            0x62
+#define R_QNC_LPC_PIRQD_ROUT            0x63
+#define R_QNC_LPC_PIRQE_ROUT            0x64
+#define R_QNC_LPC_PIRQF_ROUT            0x65
+#define R_QNC_LPC_PIRQG_ROUT            0x66
+#define R_QNC_LPC_PIRQH_ROUT            0x67
+
+//
+// Bit values are the same for R_TNC_LPC_PIRQA_ROUT to
+//                             R_TNC_LPC_PIRQH_ROUT
+#define   B_QNC_LPC_PIRQX_ROUT            (BIT3+BIT2+BIT1+BIT0)
+
+#define R_QNC_LPC_WDTBA                 0x84
+// Watchdog Timer register offsets from WDTBASE (in R_QNC_LPC_WDTBA)------------BEGIN
+#define R_QNC_LPC_WDT_WDTCR             0x10
+#define R_QNC_LPC_WDT_WDTLR             0x18
+// Watchdog Timer register offsets from WDTBASE (in R_QNC_LPC_WDTBA)--------------END
+
+#define R_QNC_LPC_FWH_BIOS_DEC          0xD4
+#define   B_QNC_LPC_FWH_BIOS_DEC_F8       (BIT31)
+#define   B_QNC_LPC_FWH_BIOS_DEC_F0       (BIT30)
+#define   B_QNC_LPC_FWH_BIOS_DEC_E8       (BIT29)
+#define   B_QNC_LPC_FWH_BIOS_DEC_E0       (BIT28)
+#define   B_QNC_LPC_FWH_BIOS_DEC_D8       (BIT27)
+#define   B_QNC_LPC_FWH_BIOS_DEC_D0       (BIT26)
+#define   B_QNC_LPC_FWH_BIOS_DEC_C8       (BIT25)
+#define   B_QNC_LPC_FWH_BIOS_DEC_C0       (BIT24)
+
+#define R_QNC_LPC_BIOS_CNTL             0xD8
+#define  S_QNC_LPC_BIOS_CNTL             4
+#define   B_QNC_LPC_BIOS_CNTL_PFE         (BIT8)
+#define   B_QNC_LPC_BIOS_CNTL_SMM_BWP     (BIT5)
+#define   B_QNC_LPC_BIOS_CNTL_BCD         (BIT2)
+#define   B_QNC_LPC_BIOS_CNTL_BLE         (BIT1)
+#define   B_QNC_LPC_BIOS_CNTL_BIOSWE      (BIT0)
+#define    N_QNC_LPC_BIOS_CNTL_BLE         1
+#define    N_QNC_LPC_BIOS_CNTL_BIOSWE      0
+
+#define R_QNC_LPC_RCBA                  0xF0
+#define   B_QNC_LPC_RCBA_MASK             0xFFFFC000
+#define   B_QNC_LPC_RCBA_EN               (BIT0)
+
+//---------------------------------------------------------------------------
+//  Fixed IO Decode on QuarkNcSocId
+//
+//  20h(2B) 24h(2B) 28h(2B) 2Ch(2B) 30h(2B) 34h(2B) 38h(2B) 3Ch(2B) : R/W 8259 master
+//  40h(3B): R/W 8254
+//  43h(1B): W   8254
+//  50h(3B): R/W 8254
+//  53h(1B): W   8254
+//  61h(1B): R/W NMI Controller
+//  63h(1B): R/W NMI Controller - can be disabled
+//  65h(1B): R/W NMI Controller - can be disabled
+//  67h(1B): R/W NMI Controller - can be disabled
+//  70h(1B): W   NMI & RTC
+//  71h(1B): R/W RTC
+//  72h(1B): R RTC; W NMI&RTC
+//  73h(1B): R/W RTC
+//  74h(1B): R RTC; W NMI&RTC
+//  75h(1B): R/W RTC
+//  76h(1B): R RTC; W NMI&RTC
+//  77h(1B): R/W RTC
+//  84h(3B): R/W Internal/LPC
+//  88h(1B): R/W Internal/LPC
+//  8Ch(3B): R/W Internal/LPC
+//  A0h(2B) A4h(2B) A8h(2B) ACh(2B) B0h(2B) B4h(2B) B8h(2B) BCh(2B): R/W 8259 slave
+//  B2h(1B) B3h(1B): R/W Power management
+//  3B0h-3BBh: R/W VGA
+//  3C0h-3DFh: R/W VGA
+//  CF8h(4B): R/W Internal
+//  CF9h(1B): R/W LPC
+//  CFCh(4B): R/W Internal
+//---------------------------------------------------------------------------
+
+#define R_APM_CNT                                       0xB2
+
+//
+// Reset Generator I/O Port
+//
+#define RST_CNT                                       0xCF9
+#define   B_RST_CNT_COLD_RST                            (BIT3)     // Cold reset
+#define   B_RST_CNT_WARM_RST                            (BIT1)     // Warm reset
+
+//
+// Processor interface registers (NMI)
+//
+
+#define  PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0                20
+#define  PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1                21
+#define  PCI_FUNCTION_NUMBER_QNC_IOSF2AHB                 0
+
+//
+// Pci Express Root Ports (D23:F0/F1)
+//
+#define PCI_DEVICE_NUMBER_PCIE_ROOTPORT                 23
+#define PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0             0
+#define PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1             1
+
+#define MAX_PCI_EXPRESS_ROOT_PORTS                      2
+
+#define R_QNC_PCIE_BNUM                             0x18
+#define R_QNC_PCIE_CAP_PTR                          0x34
+
+#define PCIE_CAPID                                  0x10  //PCIE Capability ID
+#define PCIE_CAP_EXT_HEARDER_OFFSET                 0x100 //PCIE Capability ID
+#define PCIE_DEV_CAP_OFFSET                         0x04 //PCIE Device Capability reg offset
+#define PCIE_LINK_CAP_OFFSET                        0x0C //PCIE Link Capability reg offset
+#define PCIE_LINK_CNT_OFFSET                        0x10 //PCIE Link control reg offset
+#define PCIE_LINK_STS_OFFSET                        0x12 //PCIE Link status reg offset
+#define PCIE_SLOT_CAP_OFFSET                        0x14 //PCIE Link Capability reg offset
+
+#define R_QNC_PCIE_XCAP                             0x42  //~ 43h
+#define   B_QNC_PCIE_XCAP_SI                          (BIT8)  //slot implemented
+#define R_QNC_PCIE_DCAP                             0x44  //~ 47h
+#define   B_QNC_PCIE_DCAP_E1AL                        (BIT11 | BIT10 | BIT9) // L1 Acceptable exit latency
+#define   B_QNC_PCIE_DCAP_E0AL                        (BIT8 | BIT7 | BIT6)   // L0 Acceptable exit latency
+#define R_QNC_PCIE_DCTL                             0x48  //~ 49h
+#define   B_QNC_PCIE_DCTL_URE                         (BIT3)  //Unsupported Request Reporting Enable
+#define   B_QNC_PCIE_DCTL_FEE                         (BIT2)  //Fatal error Reporting Enable
+#define   B_QNC_PCIE_DCTL_NFE                         (BIT1)  //Non Fatal error Reporting Enable
+#define   B_QNC_PCIE_DCTL_CEE                         (BIT0)  //Correctable error Reporting Enable
+#define R_QNC_PCIE_LCAP                             0x4C  //~ 4Fh
+#define   B_QNC_PCIE_LCAP_CPM                         (BIT18)  //clock power management supported
+#define   B_QNC_PCIE_LCAP_EL1_MASK                   (BIT17 | BIT16 | BIT15)  //L1 Exit latency mask
+#define   B_QNC_PCIE_LCAP_EL0_MASK                   (BIT14 | BIT13 | BIT12)  //L0 Exit latency mask
+#define   B_QNC_PCIE_LCAP_APMS_MASK                   (BIT11 | BIT10)  //Active state link PM support mask
+#define   V_QNC_PCIE_LCAP_APMS_OFFSET                 10  //Active state link PM support mask
+#define R_QNC_PCIE_LCTL                             0x50  //~ 51h
+#define   B_QNC_PCIE_LCTL_CCC                         (BIT6)  // Clock clock configuration
+#define   B_QNC_PCIE_LCTL_RL                          (BIT5)  // Retrain link
+#define R_QNC_PCIE_LSTS                             0x52  //~ 53h
+#define   B_QNC_PCIE_LSTS_SCC                         (BIT12) //Slot clock configuration
+#define   B_QNC_PCIE_LSTS_LT                          (BIT11) //Link training
+#define R_QNC_PCIE_SLCAP                            0x54  //~ 57h
+#define   B_QNC_PCIE_SLCAP_MASK_RSV_VALUE             0x0006007F
+#define   V_QNC_PCIE_SLCAP_SLV                        0x0A  //Slot power limit value [14:7]
+#define   V_QNC_PCIE_SLCAP_SLV_OFFSET                 7     //Slot power limit value offset is 7 [14:7]
+#define   V_QNC_PCIE_SLCAP_PSN_OFFSET                 19    //Slot number offset is 19 [31:19]
+#define R_QNC_PCIE_SLCTL                            0x58    //~ 59h
+#define   B_QNC_PCIE_SLCTL_HPE                        (BIT5)  // Hot plug interrupt enable
+#define   B_QNC_PCIE_SLCTL_PDE                        (BIT3)  // Presense detect change enable
+#define   B_QNC_PCIE_SLCTL_ABE                        (BIT0)  // Attention Button Pressed Enable
+#define R_QNC_PCIE_SLSTS                            0x5A    //~ 5Bh
+#define   B_QNC_PCIE_SLSTS_PDS                        (BIT6)  // Present Detect State = 1b : has device connected
+#define   B_QNC_PCIE_SLSTS_PDC                        (BIT3)  // Present Detect changed = 1b : PDS state has changed
+#define   B_QNC_PCIE_SLSTS_ABP                        (BIT0)  // Attention Button Pressed
+#define R_QNC_PCIE_RCTL                             0x5C    //~ 5Dh
+#define   B_QNC_PCIE_RCTL_PIE                         (BIT3)  //Root PCI-E PME Interrupt Enable
+#define   B_QNC_PCIE_RCTL_SFE                         (BIT2)  //Root PCI-E System Error on Fatal Error Enable
+#define   B_QNC_PCIE_RCTL_SNE                         (BIT1)  //Root PCI-E System Error on Non-Fatal Error Enable
+#define   B_QNC_PCIE_RCTL_SCE                         (BIT0)  //Root PCI-E System Error on Correctable Error Enable
+#define R_QNC_PCIE_SVID                             0x94  //~ 97h
+#define R_QNC_PCIE_CCFG                             0xD0  //~ D3h
+#define   B_QNC_PCIE_CCFG_UPSD                        (BIT24)  // Upstream Posted Split Disable
+#define   B_QNC_PCIE_CCFG_UNRS                        (BIT15)  // Upstream Non-Posted Request Size
+#define   B_QNC_PCIE_CCFG_UPRS                        (BIT14)  // Upstream Posted Request Size
+#define R_QNC_PCIE_MPC2                             0xD4  //~ D7h
+#define   B_QNC_PCIE_MPC2_IPF                         (BIT11)  // ISOF Packet Fast Transmit Mode
+#define R_QNC_PCIE_MPC                              0xD8  //~ DBh
+#define   B_QNC_PCIE_MPC_PMCE                         (BIT31)  // PM SCI Enable
+#define   B_QNC_PCIE_MPC_HPCE                         (BIT30)  // Hot plug SCI enable
+
+#define   B_QNC_PCIE_MPC_HPME                         (BIT1)   // Hot plug SMI enable
+#define   B_QNC_PCIE_MPC_PMME                         (BIT0)   // PM SMI Enable
+#define R_QNC_PCIE_IOSFSBCTL                        0xF6
+#define   B_QNC_PCIE_IOSFSBCTL_SBIC_MASK              (BIT1 | BIT0) // IOSF Sideband ISM Idle Counter.
+#define   B_QNC_PCIE_IOSFSBCTL_SBIC_IDLE_NEVER        (BIT1 | BIT0) // Never transition to IDLE.
+
+#define V_PCIE_MAX_TRY_TIMES                       200
+
+//
+// Misc PCI register offsets and sizes
+//
+#define R_EFI_PCI_SVID                              0x2C
+
+//
+// IO_APIC
+//
+#define IOAPIC_BASE                                 0xFEC00000
+#define IOAPIC_SIZE                                 0x1000
+
+//
+// Chipset configuration registers RCBA - "Root Complex Base Address" (D31:F0:RF0h)
+//            Suggested Value for  RCBA = 0xFED1C000
+//
+
+#define R_QNC_RCRB_SPIBASE                          0x3020       // SPI (Serial Peripheral Interface) in RCRB
+#define R_QNC_RCRB_SPIS                             (R_QNC_RCRB_SPIBASE + 0x00)  // SPI Status
+#define   B_QNC_RCRB_SPIS_SCL                       (BIT15)    // SPI Configuration Lockdown
+#define   B_QNC_RCRB_SPIS_BAS                       (BIT3)     // Blocked Access Status
+#define   B_QNC_RCRB_SPIS_CDS                       (BIT2)     // Cycle Done Status
+#define   B_QNC_RCRB_SPIS_SCIP                      (BIT0)     // SPI Cycle in Progress
+
+#define R_QNC_RCRB_SPIC                             (R_QNC_RCRB_SPIBASE + 0x02)  // SPI Control
+#define   B_QNC_RCRB_SPIC_DC                          (BIT14)    // SPI Data Cycle Enable
+#define   B_QNC_RCRB_SPIC_DBC                         0x3F00     // SPI Data Byte Count (1..8,16,24,32,40,48,56,64)
+#define   B_QNC_RCRB_SPIC_COP                         (BIT6+BIT5+BIT4)          // SPI Cycle Opcode Pointer
+#define   B_QNC_RCRB_SPIC_SPOP                        (BIT3)     // Sequence Prefix Opcode Pointer
+#define   B_QNC_RCRB_SPIC_ACS                         (BIT2)     // SPI Atomic Cycle Sequence
+#define   B_QNC_RCRB_SPIC_SCGO                        (BIT1)     // SPI Cycle Go
+
+#define R_QNC_RCRB_SPIA                             (R_QNC_RCRB_SPIBASE + 0x04)  // SPI Address
+#define   B_QNC_RCRB_SPIA_MASK                      0x00FFFFFF     // SPI Address mask
+#define R_QNC_RCRB_SPID0                            (R_QNC_RCRB_SPIBASE + 0x08)  // SPI Data 0
+#define R_QNC_RCRB_SPIPREOP                         (R_QNC_RCRB_SPIBASE + 0x54)  // Prefix Opcode Configuration
+#define R_QNC_RCRB_SPIOPTYPE                        (R_QNC_RCRB_SPIBASE + 0x56)  // Opcode Type Configuration
+#define   B_QNC_RCRB_SPIOPTYPE_NOADD_READ             0
+#define   B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE            (BIT0)
+#define   B_QNC_RCRB_SPIOPTYPE_ADD_READ               (BIT1)
+#define   B_QNC_RCRB_SPIOPTYPE_ADD_WRITE              (BIT0 + BIT1)
+#define R_QNC_RCRB_SPIOPMENU                        (R_QNC_RCRB_SPIBASE + 0x58)  // Opcode Menu Configuration //R_OPMENU
+
+#define R_QNC_RCRB_SPIPBR0                          (R_QNC_RCRB_SPIBASE + 0x60)  // Protected BIOS Range 0.
+#define R_QNC_RCRB_SPIPBR1                          (R_QNC_RCRB_SPIBASE + 0x64)  // Protected BIOS Range 1.
+#define R_QNC_RCRB_SPIPBR2                          (R_QNC_RCRB_SPIBASE + 0x68)  // Protected BIOS Range 2.
+#define   B_QNC_RCRB_SPIPBRn_WPE                      (BIT31)                    // Write Protection Enable for above 3 registers.
+
+#define R_QNC_RCRB_AGENT0IR                         0x3140   // AGENT0 interrupt route
+#define R_QNC_RCRB_AGENT1IR                         0x3142   // AGENT1 interrupt route
+#define R_QNC_RCRB_AGENT2IR                         0x3144   // AGENT2 interrupt route
+#define R_QNC_RCRB_AGENT3IR                         0x3146   // AGENT3 interrupt route
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h
new file mode 100644
index 0000000000..0024218afc
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h
@@ -0,0 +1,32 @@
+/** @file
+Common header file shared by all source files.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __COMMON_HEADER_H_
+#define __COMMON_HEADER_H_
+
+
+
+#include <PiPei.h>
+#include <IntelQNCBase.h>
+
+#include <Library/IntelQNCLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CpuLib.h>
+#include <Library/PciCf8Lib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/QNCAccessLib.h>
+#include <IndustryStandard/Pci22.h>
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c
new file mode 100644
index 0000000000..fbb89f9904
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c
@@ -0,0 +1,771 @@
+/** @file
+Lib function for Pei QNC.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "CommonHeader.h"
+
+/**
+  This function provides the necessary SOC initialization
+  before MRC running. It sets RCBA, GPIO, PMBASE
+  and some parts of SOC through SOC message method.
+  If the function cannot complete it'll ASSERT().
+**/
+VOID
+EFIAPI
+PeiQNCPreMemInit (
+  VOID
+  )
+{
+  UINT32                            RegValue;
+
+  // QNCPortWrite(Port#, Offset, Value)
+
+  //
+  // Set the fixed PRI Status encodings config.
+  //
+  QNCPortWrite (
+    QUARK_NC_MEMORY_ARBITER_SB_PORT_ID,
+    QUARK_NC_MEMORY_ARBITER_REG_ASTATUS,
+    QNC_FIXED_CONFIG_ASTATUS
+    );
+
+  // Sideband register write to Remote Management Unit
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QNC_MSG_TMPM_REG_PMBA, (BIT31 | PcdGet16 (PcdPmbaIoBaseAddress)));
+
+  // Configurable I/O address in iLB (legacy block)
+
+  LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) = BIT31 | PcdGet16 (PcdSmbaIoBaseAddress);
+  LpcPciCfg32 (R_QNC_LPC_GBA_BASE) = BIT31 | PcdGet16 (PcdGbaIoBaseAddress);
+  LpcPciCfg32 (R_QNC_LPC_PM1BLK) = BIT31 | PcdGet16 (PcdPm1blkIoBaseAddress);
+  LpcPciCfg32 (R_QNC_LPC_GPE0BLK) = BIT31 | PcdGet16 (PcdGpe0blkIoBaseAddress);
+  LpcPciCfg32 (R_QNC_LPC_WDTBA) = BIT31 | PcdGet16 (PcdWdtbaIoBaseAddress);
+
+  //
+  // Program RCBA Base Address
+  //
+  LpcPciCfg32AndThenOr (R_QNC_LPC_RCBA, (~B_QNC_LPC_RCBA_MASK), (((UINT32)(PcdGet64 (PcdRcbaMmioBaseAddress))) | B_QNC_LPC_RCBA_EN));
+
+  //
+  // Program Memory Manager fixed config values.
+  //
+
+  RegValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL);
+  RegValue &= ~(DRAM_NON_HOST_RQ_LIMIT_MASK);
+  RegValue |= (V_DRAM_NON_HOST_RQ_LIMIT << DRAM_NON_HOST_RQ_LIMIT_BP);
+  QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL, RegValue);
+
+  //
+  // Program iCLK fixed config values.
+  //
+  QncIClkAndThenOr (
+    QUARK_ICLK_MUXTOP,
+    (UINT32) ~(B_MUXTOP_FLEX2_MASK | B_MUXTOP_FLEX1_MASK),
+    (V_MUXTOP_FLEX2 << B_MUXTOP_FLEX2_BP) | (V_MUXTOP_FLEX1 << B_MUXTOP_FLEX1_BP)
+    );
+  QncIClkAndThenOr (
+    QUARK_ICLK_REF2_DBUFF0,
+    (UINT32) ~(BIT0), // bit[0] cleared
+    0
+    );
+  QncIClkOr (
+    QUARK_ICLK_SSC1,
+    BIT0              // bit[0] set
+    );
+  QncIClkOr (
+    QUARK_ICLK_SSC2,
+    BIT0              // bit[0] set
+    );
+  QncIClkOr (
+    QUARK_ICLK_SSC3,
+    BIT0              // bit[0] set
+    );
+
+  //
+  // Set RMU DMA disable bit post boot.
+  //
+  RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1);
+  RegValue |= OPTIONS_1_DMA_DISABLE;
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1, RegValue);
+}
+
+/**
+  Do north cluster init which needs to be done AFTER MRC init.
+
+  @param   VOID
+
+  @retval  VOID
+**/
+
+VOID
+EFIAPI
+PeiQNCPostMemInit (
+  VOID
+  )
+{
+  //
+  // Program SVID/SID the same as VID/DID for all devices except root ports.
+  //
+  QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, R_EFI_PCI_SVID) = QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, PCI_VENDOR_ID_OFFSET);
+  QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, PCI_VENDOR_ID_OFFSET);
+  QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, PCI_VENDOR_ID_OFFSET);
+  QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, PCI_VENDOR_ID_OFFSET);
+  return;
+}
+
+/**
+  Used to check QNC if it's S3 state.  Clear the register state after query.
+
+  @retval TRUE if it's S3 state.
+  @retval FALSE if it's not S3 state.
+
+**/
+BOOLEAN
+EFIAPI
+QNCCheckS3AndClearState (
+   VOID
+  )
+{
+  BOOLEAN       S3WakeEventFound;
+  UINT16        Pm1Sts;
+  UINT16        Pm1En;
+  UINT16        Pm1Cnt;
+  UINT32        Gpe0Sts;
+  UINT32        Gpe0En;
+  UINT32        NewValue;
+  CHAR8         *EventDescStr;
+
+  S3WakeEventFound = FALSE;
+  EventDescStr = NULL;
+
+  //
+  // Read the ACPI registers,
+  //
+  Pm1Sts  = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S);
+  Pm1En   = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);
+  Pm1Cnt  = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+  Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S);
+  Gpe0En  = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E);
+
+  //
+  // Clear Power Management 1 Enable Register and
+  // General Purpost Event 0 Enables Register
+  //
+  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0);
+  IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0);
+
+  if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S3) {
+
+    //
+    // Detect the actual WAKE event
+    //
+    if ((Pm1Sts & B_QNC_PM1BLK_PM1S_RTC) && (Pm1En & B_QNC_PM1BLK_PM1E_RTC)) {
+      EventDescStr = "RTC Alarm";
+      S3WakeEventFound = TRUE;
+    }
+    if ((Pm1Sts & B_QNC_PM1BLK_PM1S_PCIEWSTS) && !(Pm1En & B_QNC_PM1BLK_PM1E_PWAKED)) {
+      EventDescStr = "PCIe WAKE";
+      S3WakeEventFound = TRUE;
+    }
+    if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_PCIE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_PCIE)) {
+      EventDescStr = "PCIe";
+      S3WakeEventFound = TRUE;
+    }
+    if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_GPIO) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_GPIO)) {
+      EventDescStr = "GPIO";
+      S3WakeEventFound = TRUE;
+    }
+    if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_EGPE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_EGPE)) {
+      EventDescStr = "Ext. GPE";
+      S3WakeEventFound = TRUE;
+    }
+    if (S3WakeEventFound == FALSE) {
+      EventDescStr = "Unknown";
+    }
+    DEBUG ((EFI_D_INFO, "S3 Wake Event - %a\n", EventDescStr));
+
+    //
+    // If no Power Button Override event occurs and one enabled wake event occurs,
+    // just do S3 resume and clear the state.
+    //
+    IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP)));
+
+    //
+    // Set EOS to de Assert SMI
+    //
+    IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS,  B_QNC_GPE0BLK_SMIS_EOS);
+
+    //
+    // Enable SMI globally
+    //
+    NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+    NewValue |= SMI_EN;
+    QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+    return  TRUE;
+  }
+
+  return  FALSE;
+}
+
+/**
+  Used to check QNC if system wakes up from power on reset. Clear the register state after query.
+
+  @retval TRUE  if system wakes up from power on reset
+  @retval FALSE if system does not wake up from power on reset
+
+**/
+BOOLEAN
+EFIAPI
+QNCCheckPowerOnResetAndClearState (
+   VOID
+  )
+{
+  UINT16                Pm1Sts;
+  UINT16                Pm1Cnt;
+
+  //
+  // Read the ACPI registers,
+  // PM1_STS information cannot be lost after power down, unless CMOS is cleared.
+  //
+  Pm1Sts  = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S);
+  Pm1Cnt  = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+
+  //
+  // If B_SLP_TYP is S5
+  //
+  if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S5) {
+    IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP)));
+    return  TRUE;
+  }
+
+  return  FALSE;
+}
+
+/**
+  This function is used to clear SMI and wake status.
+
+**/
+VOID
+EFIAPI
+QNCClearSmiAndWake (
+  VOID
+  )
+{
+  UINT32    Gpe0Sts;
+  UINT32    SmiSts;
+
+  //
+  // Read the ACPI registers
+  //
+  Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S);
+  SmiSts  = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
+
+  //
+  // Clear any SMI or wake state from the boot
+  //
+  Gpe0Sts |= B_QNC_GPE0BLK_GPE0S_ALL;
+  SmiSts  |= B_QNC_GPE0BLK_SMIS_ALL;
+
+  //
+  // Write them back
+  //
+  IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S, Gpe0Sts);
+  IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS,  SmiSts);
+}
+
+/** Send DRAM Ready opcode.
+
+  @param[in]       OpcodeParam  Parameter to DRAM ready opcode.
+
+  @retval          VOID
+**/
+VOID
+EFIAPI
+QNCSendOpcodeDramReady (
+  IN UINT32   OpcodeParam
+  )
+{
+
+  //
+  // Before sending DRAM ready place invalid value in Scrub Config.
+  //
+  QNCPortWrite (
+    QUARK_NC_RMU_SB_PORT_ID,
+    QUARK_NC_ECC_SCRUB_CONFIG_REG,
+    SCRUB_CFG_INVALID
+    );
+
+  //
+  // Send opcode and use param to notify HW of new RMU firmware location.
+  //
+  McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = OpcodeParam;
+  McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_SHADOW_DW (QUARK_NC_RMU_SB_PORT_ID, 0);
+
+  //
+  // HW completed tasks on DRAM ready when scrub config read back as zero.
+  //
+  while (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG) != 0) {
+    MicroSecondDelay (10);
+  }
+}
+
+/**
+
+  Relocate RMU Main binary to memory after MRC to improve performance.
+
+  @param[in]  DestBaseAddress  - Specify the new memory address for the RMU Main binary.
+  @param[in]  SrcBaseAddress   - Specify the current memory address for the RMU Main binary.
+  @param[in]  Size             - Specify size of the RMU Main binary.
+
+  @retval     VOID
+
+**/
+VOID
+EFIAPI
+RmuMainRelocation (
+  IN CONST UINT32   DestBaseAddress,
+  IN CONST UINT32   SrcBaseAddress,
+  IN CONST UINTN    Size
+  )
+{
+  //
+  // Shadow RMU Main binary into main memory.
+  //
+  CopyMem ((VOID *)(UINTN)DestBaseAddress,(VOID *)(UINTN) SrcBaseAddress, Size);
+}
+
+
+/**
+  Get the total memory size
+
+**/
+UINT32
+EFIAPI
+QNCGetTotalMemorysize (
+  VOID
+  )
+{
+  return  QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG) & HMBOUND_MASK;
+}
+
+
+/**
+  Get the memory range of TSEG.
+  The TSEG's memory is below TOLM.
+
+  @param[out] BaseAddress The base address of TSEG's memory range
+  @param[out] MemorySize  The size of TSEG's memory range
+
+**/
+VOID
+EFIAPI
+QNCGetTSEGMemoryRange (
+  OUT UINT64  *BaseAddress,
+  OUT UINT64  *MemorySize
+  )
+{
+  UINT64 Register = 0;
+  UINT64 SMMAddress = 0;
+
+  Register = QncHsmmcRead ();
+
+  //
+  // Get the SMRAM Base address
+  //
+  SMMAddress = Register & SMM_START_MASK;
+  *BaseAddress = LShift16 (SMMAddress);
+
+  //
+  // Get the SMRAM size
+  //
+  SMMAddress = ((Register & SMM_END_MASK) | (~SMM_END_MASK)) + 1;
+  *MemorySize = SMMAddress - (*BaseAddress);
+
+  DEBUG ((
+    EFI_D_INFO,
+    "TSEG's memory range: BaseAddress = 0x%x, Size = 0x%x\n",
+    (UINT32)*BaseAddress,
+    (UINT32)*MemorySize
+    ));
+}
+
+/**
+  Updates the PAM registers in the MCH for the requested range and mode.
+
+  @param   Start        The start address of the memory region
+  @param   Length       The length, in bytes, of the memory region
+  @param   ReadEnable   Pointer to the boolean variable on whether to enable read for legacy memory section.
+                        If NULL, then read attribute will not be touched by this call.
+  @param   ReadEnable   Pointer to the boolean variable on whether to enable write for legacy memory section.
+                        If NULL, then write attribute will not be touched by this call.
+  @param   Granularity  A pointer to granularity, in bytes, that the PAM registers support
+
+  @retval  RETURN_SUCCESS            The PAM registers in the MCH were updated
+  @retval  RETURN_INVALID_PARAMETER  The memory range is not valid in legacy region.
+
+**/
+EFI_STATUS
+EFIAPI
+QNCLegacyRegionManipulation (
+  IN  UINT32                  Start,
+  IN  UINT32                  Length,
+  IN  BOOLEAN                 *ReadEnable,
+  IN  BOOLEAN                 *WriteEnable,
+  OUT UINT32                  *Granularity
+  )
+{
+  //
+  // Do nothing cos no such support on QNC
+  //
+  return RETURN_SUCCESS;
+}
+
+/**
+  Determine if QNC is supported.
+
+  @retval FALSE  QNC is not supported.
+  @retval TRUE   QNC is supported.
+**/
+BOOLEAN
+EFIAPI
+IsQncSupported (
+  VOID
+  )
+{
+  UINT16  SocVendorId;
+  UINT16  SocDeviceId;
+
+  SocVendorId = MmioRead16 (
+                  PciDeviceMmBase (MC_BUS,
+                  MC_DEV,
+                  MC_FUN) + PCI_VENDOR_ID_OFFSET
+                  );
+
+  SocDeviceId = QncGetSocDeviceId();
+
+  //
+  // Verify that this is a supported chipset
+  //
+  if ((SocVendorId != QUARK_MC_VENDOR_ID) || ((SocDeviceId != QUARK_MC_DEVICE_ID) && (SocDeviceId != QUARK2_MC_DEVICE_ID))) {
+    DEBUG ((DEBUG_ERROR, "QNC code doesn't support the Soc VendorId:0x%04x Soc DeviceId:0x%04x!\n", SocVendorId, SocDeviceId));
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+  Get the DeviceId of the SoC
+
+  @retval PCI DeviceId of the SoC
+**/
+UINT16
+EFIAPI
+QncGetSocDeviceId (
+  VOID
+  )
+{
+  UINT16  SocDeviceId;
+
+  SocDeviceId = MmioRead16 (
+                  PciDeviceMmBase (
+                    MC_BUS,
+                    MC_DEV,
+                    MC_FUN
+                    ) + PCI_DEVICE_ID_OFFSET
+                  );
+
+  return SocDeviceId;
+}
+
+/**
+  Enable SMI detection of legacy flash access violations.
+**/
+VOID
+EFIAPI
+QncEnableLegacyFlashAccessViolationSmi (
+  VOID
+  )
+{
+  UINT32  BcValue;
+
+  BcValue = LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL);
+
+  //
+  // Clear BIOSWE & set BLE.
+  //
+  BcValue &= (~B_QNC_LPC_BIOS_CNTL_BIOSWE);
+  BcValue |= (B_QNC_LPC_BIOS_CNTL_BLE);
+
+  LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL) = BcValue;
+
+  DEBUG ((EFI_D_INFO, "BIOS Control Lock Enabled!\n"));
+}
+
+/**
+  Setup RMU Thermal sensor registers for Vref mode.
+**/
+VOID
+EFIAPI
+QNCThermalSensorSetVRefMode (
+  VOID
+  )
+{
+  UINT32                             Tscgf1Config;
+  UINT32                             Tscgf2Config;
+  UINT32                             Tscgf2Config2;
+
+  Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG);
+  Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG);
+  Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2);
+
+  Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK);
+  Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_VREF_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP);
+
+  Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN);
+  Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_VREF_MODE << B_TSCGF1_CONFIG_IBGEN_BP);
+
+  Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK);
+  Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_VREF_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP);
+
+  Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK);
+  Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_VREF_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP);
+
+  Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK);
+  Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_VREF_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP);
+
+  QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config);
+  QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config);
+  QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2);
+}
+
+/**
+  Setup RMU Thermal sensor registers for Ratiometric mode.
+**/
+VOID
+EFIAPI
+QNCThermalSensorSetRatiometricMode (
+  VOID
+  )
+{
+  UINT32                             Tscgf1Config;
+  UINT32                             Tscgf2Config;
+  UINT32                             Tscgf2Config2;
+  UINT32                             Tscgf3Config;
+
+  Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG);
+  Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG);
+  Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2);
+  Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG);
+
+  Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK);
+  Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_RATIO_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP);
+
+  Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCHOPSEL_MASK);
+  Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCHOPSEL_RATIO_MODE  << B_TSCGF1_CONFIG_ISNSCHOPSEL_BP);
+
+  Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSINTERNALVREFEN);
+  Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSINTERNALVREFEN_RATIO_MODE << B_TSCGF1_CONFIG_ISNSINTERNALVREFEN_BP);
+
+  Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN);
+  Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGEN_BP);
+
+  Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGCHOPEN);
+  Tscgf1Config |= (V_TSCGF1_CONFIG_IBGCHOPEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGCHOPEN_BP);
+
+  Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCONFIGSEL_MASK);
+  Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCONFIGSEL_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCONFIGSEL_BP);
+
+  Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK);
+  Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_RATIO_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP);
+
+  Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK);
+  Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP);
+
+  Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK);
+  Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_RATIO_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP);
+
+  Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSTIMING_MASK);
+  Tscgf2Config |= (V_TSCGF2_CONFIG_IDSTIMING_RATIO_MODE << B_TSCGF2_CONFIG_IDSTIMING_BP);
+
+  Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSGAMMACOEFF_MASK);
+  Tscgf3Config |= (V_TSCGF3_CONFIG_ITSGAMMACOEFF_RATIO_MODE << B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP);
+
+  QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config);
+  QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config);
+  QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2);
+  QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config);
+}
+
+/**
+  Setup RMU Thermal sensor trip point values.
+
+  @param[in]  CatastrophicTripOnDegreesCelsius  - Catastrophic set trip point threshold.
+  @param[in]  HotTripOnDegreesCelsius           - Hot set trip point threshold.
+  @param[in]  HotTripOffDegreesCelsius          - Hot clear trip point threshold.
+
+  @retval  EFI_SUCCESS            Trip points setup.
+  @retval  EFI_INVALID_PARAMETER  Invalid trip point value.
+
+**/
+EFI_STATUS
+EFIAPI
+QNCThermalSensorSetTripValues (
+  IN  CONST UINTN             CatastrophicTripOnDegreesCelsius,
+  IN  CONST UINTN             HotTripOnDegreesCelsius,
+  IN  CONST UINTN             HotTripOffDegreesCelsius
+  )
+{
+  UINT32 RegisterValue;
+
+  //
+  // Register fields are 8-bit temperature values of granularity 1 degree C
+  // where 0x00 corresponds to -50 degrees C
+  // and 0xFF corresponds to 205 degrees C.
+  //
+  // User passes unsigned values in degrees Celsius so trips < 0 not supported.
+  //
+  // Add 50 to user values to get values for register fields.
+  //
+
+  if ((CatastrophicTripOnDegreesCelsius > 205) || (HotTripOnDegreesCelsius > 205) || (HotTripOffDegreesCelsius > 205)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Set new values.
+  //
+  RegisterValue =
+    ((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP) | // Cat Trip Clear value must be less than Cat Trip Set Value.
+    ((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP) |
+    ((HotTripOnDegreesCelsius + 50) << TS_HOT_TRIP_SET_THOLD_BP) |
+    ((HotTripOffDegreesCelsius + 50) << TS_HOT_TRIP_CLEAR_THOLD_BP)
+    ;
+
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, RegisterValue);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enable RMU Thermal sensor with a Catastrophic Trip point.
+
+  @retval  EFI_SUCCESS            Trip points setup.
+  @retval  EFI_INVALID_PARAMETER  Invalid trip point value.
+
+**/
+EFI_STATUS
+EFIAPI
+QNCThermalSensorEnableWithCatastrophicTrip (
+  IN  CONST UINTN             CatastrophicTripOnDegreesCelsius
+  )
+{
+  UINT32                             Tscgf3Config;
+  UINT32                             TsModeReg;
+  UINT32                             TsTripReg;
+
+  //
+  // Trip Register fields are 8-bit temperature values of granularity 1 degree C
+  // where 0x00 corresponds to -50 degrees C
+  // and 0xFF corresponds to 205 degrees C.
+  //
+  // User passes unsigned values in degrees Celsius so trips < 0 not supported.
+  //
+  // Add 50 to user values to get values for register fields.
+  //
+
+  if (CatastrophicTripOnDegreesCelsius > 205) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG);
+  TsModeReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE);
+  TsTripReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP);
+
+  //
+  // Setup Catastrophic Trip point.
+  //
+  TsTripReg &= ~(TS_CAT_TRIP_SET_THOLD_MASK);
+  TsTripReg |= ((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP);
+  TsTripReg &= ~(TS_CAT_TRIP_CLEAR_THOLD_MASK);
+  TsTripReg |= ((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP);  // Cat Trip Clear value must be less than Cat Trip Set Value.
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, TsTripReg);
+
+  //
+  // To enable the TS do the following:
+  //    1)  Take the TS out of reset by setting itsrst to 0x0.
+  //    2)  Enable the TS using RMU Thermal sensor mode register.
+  //
+
+  Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSRST);
+  TsModeReg |= TS_ENABLE;
+
+  QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config);
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE, TsModeReg);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Lock all RMU Thermal sensor control & trip point registers.
+
+**/
+VOID
+EFIAPI
+QNCThermalSensorLockAllRegisters (
+  VOID
+  )
+{
+  UINT32                             RegValue;
+  UINT32                             LockMask;
+
+  LockMask = TS_LOCK_THRM_CTRL_REGS_ENABLE | TS_LOCK_AUX_TRIP_PT_REGS_ENABLE;
+
+  RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG);
+  RegValue |= LockMask;
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG, RegValue);
+
+  ASSERT ((LockMask == (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG) & LockMask)));
+}
+
+/**
+  Set chipset policy for double bit ECC error.
+
+  @param[in]       PolicyValue  Policy to config on double bit ECC error.
+
+**/
+VOID
+EFIAPI
+QNCPolicyDblEccBitErr (
+  IN  CONST UINT32                        PolicyValue
+  )
+{
+  UINT32 Register;
+  Register = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_WDT_CONTROL);
+  Register &= ~(B_WDT_CONTROL_DBL_ECC_BIT_ERR_MASK);
+  Register |= PolicyValue;
+  QNCPortWrite (
+    QUARK_NC_RMU_SB_PORT_ID,
+    QUARK_NC_RMU_REG_WDT_CONTROL,
+    Register
+    );
+}
+
+/**
+  Determine if running on secure Quark hardware Sku.
+
+  @retval FALSE  Base Quark Sku or unprovisioned Secure Sku running.
+  @retval TRUE   Provisioned SecureSku hardware running.
+**/
+BOOLEAN
+EFIAPI
+QncIsSecureProvisionedSku (
+  VOID
+  )
+{
+  // Read QUARK Secure SKU Fuse
+  return ((QNCAltPortRead (QUARK_SCSS_FUSE_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_SPI_ROM_FUSE) & BIT6) == BIT6);
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf
new file mode 100644
index 0000000000..b3e8fbf2d2
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf
@@ -0,0 +1,57 @@
+## @file
+# Intel QNC Library Instance
+#
+# Intel QNC Library Instance
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = IntelQNCLib
+  FILE_GUID                      = F5B2EA6C-8148-4a4e-88EA-38A4A51F389F
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = IntelQNCLib
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  PciExpress.c
+  IntelQNCLib.c
+  CommonHeader.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  TimerLib
+  DebugLib
+  PcdLib
+  PciLib
+  IoLib
+  PciCf8Lib
+  BaseLib
+  CpuLib
+  QNCAccessLib
+
+[Pcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdWdtbaIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPcieRootPortConfiguration
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c
new file mode 100644
index 0000000000..ac00572ce4
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c
@@ -0,0 +1,932 @@
+/** @file
+QNC PCI Express initialization entry
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CommonHeader.h"
+
+#define PCIEXP_ROOT_PORT_URE_ENABLE    BIT0   //  unsupported request reporting enable
+#define PCIEXP_ROOT_PORT_FEE_ENABLE    BIT1   //  Fatal Error Reporting Enable
+#define PCIEXP_ROOT_PORT_NFE_ENABLE    BIT2   //  Non-Fatal Error Reporting Enable
+#define PCIEXP_ROOT_PORT_CEE_ENABLE    BIT3   //  Correctable Error Reporting Enable
+#define PCIEXP_ROOT_PORT_SFE_ENABLE    BIT4   //  System Error on Fatal Error Enable
+#define PCIEXP_ROOT_PORT_SNE_ENABLE    BIT5   //  System Error on Non-Fatal Error Enable
+#define PCIEXP_ROOT_PORT_SCE_ENABLE    BIT6   //  System Error on Correctable Error Enable
+
+EFI_STATUS
+PcieStall (
+  IN UINTN              Microseconds
+  )
+{
+  MicroSecondDelay (Microseconds);
+  return EFI_SUCCESS;
+}
+
+/**
+
+  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]  Bus                     Bus number of the interested device
+  @param[in]  Device                  Device number of the interested device
+  @param[in]  Function                Function number of the interested device
+  @param[in]  CapId                   Capability ID to be scanned
+
+  @retval Offset of desired CAPID
+
+**/
+UINT32
+PcieFindCapId (
+  UINT8   Bus,
+  UINT8   Device,
+  UINT8   Function,
+  UINT8   CapId
+  )
+{
+  UINT8    CapHeader;
+
+  //
+  // Always start at Offset 0x34
+  //
+  CapHeader = QNCMmPci8 (0, Bus, Device, Function, R_QNC_PCIE_CAP_PTR);
+
+  if (CapHeader == 0xFF) {
+     return 0;
+  }
+
+  while (CapHeader != 0) {
+    if (QNCMmPci8 (0, Bus, Device, Function, CapHeader) == CapId) {
+      return CapHeader;
+    }
+    CapHeader = QNCMmPci8 (0, Bus, Device, Function, CapHeader + 1);
+  }
+  return 0;
+}
+
+/**
+
+  Search and return the offset of desired Pci Express Capability ID
+    CAPID list:
+      0x0001 = Advanced Error Rreporting Capability
+      0x0002 = Virtual Channel Capability
+      0x0003 = Device Serial Number Capability
+      0x0004 = Power Budgeting Capability
+
+  @param[in]  Bus                     Bus number of the interested device
+  @param[in]  Device                  Device number of the interested device
+  @param[in]  Function                Function number of the interested device
+  @param[in]  CapId                   Capability ID to be scanned
+
+  @retval Offset of desired CAPID
+
+**/
+UINT32
+PcieFindExtendedCapId (
+  UINT8   Bus,
+  UINT8   Device,
+  UINT8   Function,
+  UINT16  CapId
+  )
+{
+  UINT16    CapHeaderOffset;
+  UINT16    CapHeaderId;
+
+  // Start to search at Offset 0x100
+  // Get Capability Header
+  CapHeaderId = 0;
+  CapHeaderOffset = PCIE_CAP_EXT_HEARDER_OFFSET;
+
+  while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) {
+    CapHeaderId = QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset);
+    if (CapHeaderId == CapId) {
+      return CapHeaderOffset;
+    }
+    CapHeaderOffset = (QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset + 2) >> 4);
+  }
+  return 0;
+}
+
+/**
+
+  Map Vc on both root port and downstream device
+
+  @param[in]  Bus1                    Bus number of the root port
+  @param[in]  Device1                 Device number of the root port
+  @param[in]  Function1               Function number of the root port
+  @param[in]  Bus2                    Bus number of the downstream device
+  @param[in]  Device2                 Device number of the downstream device
+  @param[in]  Function2               Function number of the downstream device
+
+  @retval EFI_SUCCESS    Map Vc successful
+
+**/
+EFI_STATUS
+PcieInitTcxVc0 (
+  IN UINT8   Bus1,
+  IN UINT8   Device1,
+  IN UINT8   Function1,
+  IN UINT8   Bus2,
+  IN UINT8   Device2,
+  IN UINT8   Function2
+  )
+{
+  UINT32  Offset;
+
+  //
+  // Initialize TCx-VC0 value on the port to only use TC0
+  //
+  Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);
+  if (Offset == 0) {
+    return EFI_UNSUPPORTED;
+  }
+  QNCMmPci8AndThenOr (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);
+
+  // Set TCx-VC0 value on the Endpoint
+
+  Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);
+  if (Offset == 0) {
+    return EFI_UNSUPPORTED;
+  }
+  QNCMmPci8AndThenOr (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Map Traffic Class x to Vc0 on both root port and downstream device
+
+  @param[in]  Bus1                    Bus number of the root port
+  @param[in]  Device1                 Device number of the root port
+  @param[in]  Function1               Function number of the root port
+  @param[in]  Bus2                    Bus number of the downstream device
+  @param[in]  Device2                 Device number of the downstream device
+  @param[in]  Function2               Function number of the downstream device
+  @param[in]  TCx                     Traffic Class to be mapped to vc0
+
+  @retval EFI_SUCCESS    Map Tcx to Vc0 successful
+
+**/
+EFI_STATUS
+PcieMapTcxVc0 (
+  IN UINT8   Bus1,
+  IN UINT8   Device1,
+  IN UINT8   Function1,
+  IN UINT8   Bus2,
+  IN UINT8   Device2,
+  IN UINT8   Function2,
+  IN UINT8   TCx
+  )
+{
+  UINT32  Offset;
+
+  //
+  // Set TCx-VC0 value on the port
+  //
+
+  Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);
+  if (Offset == 0) {
+    return EFI_UNSUPPORTED;
+  }
+  QNCMmPci8 (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);
+
+  // Set TCx-VC0 value on the Endpoint
+
+  Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);
+  if (Offset == 0) {
+    return EFI_UNSUPPORTED;
+  }
+  QNCMmPci8 (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Set common clock for both root port and downstream device.
+
+  @param[in]  Bus1                    Bus number of the root port
+  @param[in]  Device1                 Device number of the root port
+  @param[in]  Function1               Function number of the root port
+  @param[in]  Bus2                    Device number of the downstream device
+  @param[in]  Device2                 Function number of the downstream device
+
+  @retval EFI_SUCCESS    Set common clock successful
+
+**/
+EFI_STATUS
+PcieSetCommonClock (
+  IN UINT8   Bus1,
+  IN UINT8   Device1,
+  IN UINT8   Function1,
+  IN UINT8   Bus2,
+  IN UINT8   Device2
+ )
+{
+  UINT32      CapOffset1;
+  UINT32      CapOffset2;
+  UINT8       Function2;
+  UINT8       CommonClock;
+  EFI_STATUS  Status;
+
+  //
+  // Get the pointer to the Port PCI Express Capability Structure.
+  //
+  CommonClock = 0;
+  CapOffset1 = PcieFindCapId (Bus1, Device1, Function1, PCIE_CAPID);
+  if (CapOffset1 == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Step 1
+  // Read the Slot Clock Configuration bit of the Link status register of the root port and the endpoint device connected to the port
+  // If both components have this bit set to 1, then System BIOS should set the "Common Clock Configuration" bit in the Link Control Registers
+  // for both components at both sides of the link to indicate that components at both ends
+  // of the link use a common clock source
+  //
+
+  //
+  // Check the Port Slot Clock Configuration Bit.
+  //
+  if ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  for (Function2 = 0; Function2 < 8; Function2++) {
+    //
+    // Check the Endpoint Slot Clock Configuration Bit.
+    //
+    CapOffset2 = PcieFindCapId (Bus2, Device2, Function2, PCIE_CAPID);
+    if ((CapOffset2 != 0) &&
+       ((QNCMmPci16 (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) != 0)) {
+
+      //
+      // Common clock is supported, set common clock bit on root port
+      // and the endpoint
+      //
+      if (CommonClock == 0) {
+        QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);
+        CommonClock++;
+      }
+      QNCMmPci8Or (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);
+    }
+  }
+
+  //
+  // Step 2   If the Common Clock Configuration bit was changed by BIOS in step 1,
+  // System BIOS should initiate a link training by setting the Retrain Link bit
+  // in the Link Control register of the root port (D28:F0/F1 offset
+  // 50h [5]) to "1b" and then poll the Link Training bit in the Link Status
+  // register of the root port (D28:F0/F1/F2/F3/F4/F5 offset 52h [11]) until it is
+  // "0b".
+  //
+  if (CommonClock == 0) {
+    Status = EFI_UNSUPPORTED;
+  } else {
+    //
+    // Retrain the Link per PCI Express Specification.
+    //
+    QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_RL);
+
+    //
+    // Wait until Re-Training has completed.
+    //
+    while ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_LT) != 0);
+    Status = EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+/**
+
+  Enables the CLKREQ# PM on all the end point functions
+
+  @param[in]  Bus                Bus number of the downstream device
+  @param[in]  Device             Device number of the downstream device
+
+  @retval None
+
+**/
+VOID
+PcieSetClkreq (
+  IN  UINT8   Bus,
+  IN  UINT8   Device
+ )
+{
+  UINT8  Function;
+  UINT32 CapOffset;
+
+  //
+  // Parse thro all the functions of the endpoint and find the PCIe Cap ID (offset 10h) and if
+  // exists then enable the CLKREQ# bit (BIT8) on that function
+  //
+  for (Function = 0; Function < 8; Function++) {
+    //
+    // Find the PCIe Cap Id (offset 10h)
+    //
+    CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
+    if (CapOffset == 0) {
+       continue;
+    }
+
+    //
+    // Check if CLKREQ# is supported by the endpoints
+    //
+    if ((QNCMmPci32 (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CAP_OFFSET))
+      & B_QNC_PCIE_LCAP_CPM) != B_QNC_PCIE_LCAP_CPM) {
+      //
+      // CLKREQ# is not supported so dont do anything
+      //
+      return;
+    }
+  }
+
+  //
+  // Now enable the CLKREQ#
+  //
+  for (Function = 0; Function < 8; Function++) {
+    //
+    // Find the PCIe Cap Id (offset 10h)
+    //
+    CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
+    if (CapOffset == 0) {
+       continue;
+    }
+
+    QNCMmPci16Or (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CNT_OFFSET), BIT8);
+  }
+}
+
+/**
+
+  Configure ASPM automatically for both root port and downstream device.
+
+  @param[in]  RootBus                    Bus number of the root port
+  @param[in]  RootDevice                 Device number of the root port
+  @param[in]  RootFunction               Function number of the root port
+  @param[in]  EndpointBus                Bus number of the downstream device
+  @param[in]  EndpointDevice             Device number of the downstream device
+  @param[in]  EndpointFunction           Function number of the downstream device
+  @param[in]  LinkAspmVal                Currently used ASPM setting
+
+  @retval EFI_SUCCESS    Configure ASPM successful
+
+**/
+EFI_STATUS
+PcieSetAspmAuto (
+  IN  UINT8   RootBus,
+  IN  UINT8   RootDevice,
+  IN  UINT8   RootFunction,
+  IN  UINT8   EndpointBus,
+  IN  UINT8   EndpointDevice,
+  IN  UINT8   EndpointFunction,
+  OUT UINT16  *LinkAspmVal
+ )
+{
+  UINT32    RootPcieCapOffset;
+  UINT32    EndpointPcieCapOffset;
+  UINT16    RootPortAspm;
+  UINT16    EndPointAspm;
+  UINT16    AspmVal;
+  UINT32    PortLxLat;
+  UINT32    EndPointLxLat;
+  UINT32    LxLat;
+
+  //
+  // Get the pointer to the Port PCI Express Capability Structure.
+  //
+  RootPcieCapOffset = PcieFindCapId (RootBus, RootDevice, RootFunction, PCIE_CAPID);
+  if (RootPcieCapOffset == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get the pointer to the Endpoint PCI Express Capability Structure.
+  //
+  EndpointPcieCapOffset = PcieFindCapId (EndpointBus, EndpointDevice, EndpointFunction, PCIE_CAPID);
+  if (EndpointPcieCapOffset == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Obtain initial ASPM settings from respective port capability registers.
+  //
+  RootPortAspm  = (QNCMmPci16 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
+
+  //
+  // Configure downstream device if present.
+  //
+  EndPointAspm  = (QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
+
+  //
+  // TODO: Mask APMC with values from lookup table.
+  // RevID of 0xFF applies to all steppings.
+  //
+
+  // TODO: Mask with latency/acceptable latency comparison results.
+
+  AspmVal = RootPortAspm;
+  if (RootPortAspm > EndPointAspm) {
+    AspmVal = EndPointAspm;
+  }
+
+  //
+  // Check if L1 should be enabled based on port and endpoint L1 exit latency.
+  //
+  if(AspmVal & BIT1) {
+    PortLxLat      = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;
+    EndPointLxLat  = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;
+
+    LxLat = PortLxLat;
+    if(PortLxLat < EndPointLxLat) {
+      LxLat = EndPointLxLat;
+    }
+
+    //
+    // check if the value is bigger than endpoint L1 acceptable exit latency, if it is
+    // larger than accepted value, then we should disable L1
+    //
+    LxLat >>= 6;
+    if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E1AL)) {
+      AspmVal &= ~BIT1;
+    }
+  }
+
+  //
+  // Check if L0s should be enabled based on port and endpoint L0s exit latency.
+  //
+  if(AspmVal & BIT0) {
+    PortLxLat      = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset+ PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;
+    EndPointLxLat  = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;
+
+    LxLat = PortLxLat;
+    if(PortLxLat < EndPointLxLat) {
+      LxLat = EndPointLxLat;
+    }
+
+    //
+    // check if the value is bigger than endpoint L0s acceptable exit latency, if it is
+    // larger than accepted value, then we should disable L0s
+    //
+    LxLat >>= 6;
+    if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E0AL)) {
+      AspmVal &= ~BIT0;
+    }
+  }
+
+  RootPortAspm = AspmVal;
+
+  *LinkAspmVal = AspmVal;
+  //
+  // Set Endpoint Aspm
+  //
+  QNCMmPci16AndThenOr (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, AspmVal);
+
+
+  //
+  // Set Root Port Aspm
+  //
+  QNCMmPci16AndThenOr (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, RootPortAspm);
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Configure ASPM based on the given setting for the interested device.
+
+  @param[in]  Bus                    Bus number of the interested device
+  @param[in]  Device                 Device number of the interested device
+  @param[in]  Function               Function number of the interested device
+  @param[in]  AspmSetting            Aspm setting
+  @param[in]  LinkAspmVal            Currently used ASPM setting
+
+  @retval EFI_SUCCESS    Configure ASPM successful
+
+**/
+EFI_STATUS
+PcieSetAspmManual (
+  IN  UINT8   Bus,
+  IN  UINT8   Device,
+  IN  UINT8   Function,
+  IN  UINT8   AspmSetting,
+  OUT UINT16  *LinkAspmVal
+ )
+{
+  UINT32    PcieCapOffset;
+  UINT16    PortAspm;
+
+  //
+  // Get the pointer to the Port PCI Express Capability Structure.
+  //
+  PcieCapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
+  if (PcieCapOffset == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  // Read the Link Capability register's ASPM setting
+  PortAspm = (QNCMmPci16 (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
+  // Mask it with the Setup selection
+  PortAspm &= AspmSetting;
+
+  *LinkAspmVal = PortAspm;
+  // Write it to the Link Control register
+  QNCMmPci16AndThenOr (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, PortAspm);
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Perform Initialization on one PCI Express root port.
+
+  @param[in]  RootPortIndex          Index of PCI Express root port
+  @param[in]  RootPortConfig         Pointer to the given pcie root port configuration
+  @param[in]  PciExpressBar          Base address of pcie space
+  @param[in]  QNCRootComplexBar       Base address of root complex
+  @param[in]  QNCPmioBase             Base address of PM IO space
+  @param[in]  QNCGpeBase              Base address of gpe IO space
+
+  @retval EFI_SUCCESS    Initialization successful
+
+**/
+EFI_STATUS
+QNCRootPortInit (
+  IN UINT32                                    RootPortIndex,
+  IN PCIEXP_ROOT_PORT_CONFIGURATION            *RootPortConfig,
+  IN UINT64                                    PciExpressBar,
+  IN UINT32                                    QNCRootComplexBar,
+  IN UINT32                                    QNCPmioBase,
+  IN UINT32                                    QNCGpeBase
+  )
+{
+  UINT64            RPBase;
+  UINT64            EndPointBase;
+  UINT16            AspmVal;
+  UINT16            SlotStatus;
+  UINTN             Index;
+  UINT32            CapOffset;
+  UINT32            DwordReg;
+
+  RPBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + ((PCI_DEVICE_NUMBER_PCIE_ROOTPORT) << 3) + ((PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex) << 0)) << 12);
+  CapOffset = PcieFindCapId (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), PCIE_CAPID);
+
+  if (CapOffset == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Initialize "Slot Implmemented Bit" for this root port
+  //
+  if (RootPortConfig[RootPortIndex].Bits.SlotImplemented) {
+    QNCMmio16Or (RPBase, R_QNC_PCIE_XCAP, B_QNC_PCIE_XCAP_SI);
+  }
+
+  //
+  // For Root Port Slots Numbering on the CRBs.
+  //  Root Port 0 = Slot 1
+  //  Root Port 1 = Slot 2
+  //  Root Port 2 = Slot 3
+  //  Root Port 3 = Slot 4
+  //
+  DwordReg = QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP);
+  DwordReg &= B_QNC_PCIE_SLCAP_MASK_RSV_VALUE;
+  DwordReg |= (V_QNC_PCIE_SLCAP_SLV << V_QNC_PCIE_SLCAP_SLV_OFFSET);
+  DwordReg |= ((RootPortConfig[RootPortIndex].Bits.PhysicalSlotNumber) << V_QNC_PCIE_SLCAP_PSN_OFFSET) ;
+  QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP) = DwordReg;
+
+  //
+  // Check for a Presence Detect Change.
+  //
+  SlotStatus = QNCMmio16 (RPBase, R_QNC_PCIE_SLSTS);
+  if ((SlotStatus & (B_QNC_PCIE_SLSTS_PDS + B_QNC_PCIE_SLSTS_PDC)) == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Temporarily Hardcode the Root Port Bridge Number to 2.
+  //
+  // This Endpoint check should immediately pass.  Howerver, a 900ms delay
+  // has been added to match the timing requirements of the PCI Express Base
+  // Specification, Revision 1.0A, Section 6.6 ("...software must allow 1.0s
+  // after a reset of a device, before it may determine that a device which
+  // fails to return a Successful Completion status for a valid Configuration
+  // Request is a broken device").  Note that a 100ms delay was already added
+  // after the Root Ports were first taken out of reset.
+  //
+  QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF, 0x00020200);
+  //
+  // Only do this when a downstream device is present
+  //
+  EndPointBase = PciExpressBar + (((2 << 8) + (0 << 3) + (0 << 0)) << 12);
+  if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
+    for (Index = 0; Index < V_PCIE_MAX_TRY_TIMES; Index++){
+      if (QNCMmio16 (EndPointBase, 0x0) != 0xFFFF) {
+        break;
+      }
+      PcieStall (15);
+    }
+    if (Index >= V_PCIE_MAX_TRY_TIMES) {
+      //
+      // Clear Bus Numbers.
+      //
+      QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);
+      return EFI_NOT_FOUND;
+    }
+  }
+
+  //
+  // PCI Express* Virtual Channels
+  // Clear TC1-7 Traffic classes.
+  // Map TC0-VC0
+  //
+  PcieInitTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0);
+  PcieMapTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, 0x0);
+
+  //
+  // Set Common Clock for inserted cards
+  //
+  if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
+    PcieSetCommonClock (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0);
+  }
+
+  //
+  // Flow for Enabling ASPM
+  //
+  if (RootPortConfig[RootPortIndex].Bits.AspmEnable) {
+    if (RootPortConfig[RootPortIndex].Bits.AspmAutoEnable) {
+      PcieSetAspmAuto (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, &AspmVal);
+    } else {
+      //
+      // Set ASPM values according to setup selections, masked by capabilities
+      //
+      PcieSetAspmManual (
+        PCI_BUS_NUMBER_QNC,
+        (UINT8) (PCI_DEVICE_NUMBER_PCIE_ROOTPORT),
+        (UINT8) (PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex),
+        (UINT8) ((RootPortConfig[RootPortIndex].Bits.AspmL0sEnable & 0x01) | (RootPortConfig[RootPortIndex].Bits.AspmL1Enable << 1)),
+        &AspmVal
+        );
+    }
+  }
+
+  //
+  // Enable the PCIe CLKREQ#
+  //
+  if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
+    PcieSetClkreq (2, 0);
+  }
+
+  //
+  // Clear Bus Numbers
+  //
+  QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);
+
+  //
+  // Additional configurations
+  //
+
+  //
+  // PCI-E Unsupported Request Reporting Enable
+  //
+  if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_URE_ENABLE) {
+    QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_URE);
+  }
+
+  //
+  // Device Fatal Error Reporting Enable
+  //
+  if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_FEE_ENABLE) {
+    QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_FEE);
+  }
+
+  //
+  // Device Non Fatal Error Reporting Enable
+  //
+  if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_NFE_ENABLE) {
+    QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_NFE);
+  }
+
+  //
+  // Device Correctable Error Reporting Enable
+  //
+  if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_CEE_ENABLE) {
+    QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_CEE);
+  }
+  //
+  // Root PCI-E PME Interrupt Enable
+  //
+  if (RootPortConfig[RootPortIndex].Bits.PmeInterruptEnable) {
+    QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_PIE);
+  }
+  //
+  // Root PCI-E System Error on Fatal Error Enable
+  //
+  if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SFE_ENABLE) {
+    QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SFE);
+  }
+
+  //
+  // Root PCI-E System Error on Non-Fatal Error Enable
+  //
+  if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SNE_ENABLE) {
+    QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SNE);
+  }
+
+  //
+  // Root PCI-E System Error on Correctable Error Enable
+  //
+  if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SCE_ENABLE) {
+    QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SCE);
+  }
+
+  //
+  // Root PCI-E Powermanagement SCI Enabled
+  //
+  if (RootPortConfig[RootPortIndex].Bits.PmSciEnable) {
+    //
+    // Make sure that PME Interrupt Enable bit of Root Control register
+    // of PCI Express Capability struceture is cleared
+    //
+    QNCMmio32And (RPBase, R_QNC_PCIE_RCTL, (~B_QNC_PCIE_RCTL_PIE));
+    QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_PMME), B_QNC_PCIE_MPC_PMCE);
+
+    //
+    // Make sure GPE0 Stutus RW1C Bit is clear.
+    //
+    DwordReg = IoRead32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S);
+    if ((DwordReg & B_QNC_GPE0BLK_GPE0S_PCIE) != 0) {
+      IoWrite32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S, B_QNC_GPE0BLK_GPE0S_PCIE);
+    }
+  }
+
+  //
+  // PCIe Hot Plug SCI Enable
+  //
+  if (RootPortConfig[RootPortIndex].Bits.HotplugSciEnable) {
+    //
+    // Write clear for :
+    // Attention Button Pressed (bit0)
+    // Presence Detect Changed (bit3)
+    //
+    QNCMmio32Or (RPBase, R_QNC_PCIE_SLSTS, (B_QNC_PCIE_SLSTS_PDC | B_QNC_PCIE_SLSTS_ABP));
+
+    //
+    // Sequence 2: Program the following bits in Slot Control register at offset 18h
+    // of PCI Express* Capability structure:
+    // Attention Button Pressed Enable (bit0) = 1b
+    // Presence Detect Changed Enable (bit3) = 1b
+    // Hot Plug Interrupt Enable (bit5) = 0b
+    //
+    QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_SLCTL, (~B_QNC_PCIE_SLCTL_HPE), (B_QNC_PCIE_SLCTL_PDE | B_QNC_PCIE_SLCTL_ABE));
+
+    //
+    // Sequence 3: Program Misc Port Config (MPC) register at PCI config space offset
+    // D8h as follows:
+    // Hot Plug SCI Enable (HPCE, bit30) = 1b
+    // Hot Plug SMI Enable (HPME, bit1) = 0b
+    //
+    QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_HPME), B_QNC_PCIE_MPC_HPCE);
+  }
+
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Perform Initialization of the Downstream Root Ports
+**/
+VOID
+QNCDownStreamPortsInit (
+  IN PCIEXP_ROOT_PORT_CONFIGURATION             *RootPortConfig,
+  IN QNC_DEVICE_ENABLES                      *QNCDeviceEnables,
+  IN UINT64                                     PciExpressBar,
+  IN UINT32                                     QNCRootComplexBar,
+  IN UINT32                                     QNCPmioBase,
+  IN UINT32                                     QNCGpeBase,
+  OUT UINTN                                     *RpEnableMask
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Index;
+
+  //
+  // Initialize every root port and downstream device
+  //
+  for (Index = 0;Index < MAX_PCI_EXPRESS_ROOT_PORTS;Index++) {
+    if ((QNCDeviceEnables->Uint32 & (1 << Index)) != 0) {
+      Status = QNCRootPortInit (
+               Index,
+               RootPortConfig,
+               PciExpressBar,
+               QNCRootComplexBar,
+               QNCPmioBase,
+               QNCGpeBase
+               );
+
+      if (!EFI_ERROR (Status)) {
+        (*RpEnableMask) |= LShiftU64(1, Index);
+        DEBUG ((EFI_D_INFO, " Root Port %x device found, enabled. RpEnableMask: 0x%x\n", Index + 1, *RpEnableMask));
+      }
+    }
+  }
+}
+
+/**
+  Do early init of pci express rootports on Soc.
+
+**/
+
+VOID
+EFIAPI
+PciExpressEarlyInit (
+  VOID
+  )
+{
+  //
+  // Setup Message Bus Idle Counter (SBIC) values.
+  //
+  QNCMmPci8(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_IOSFSBCTL) = QNCMmPci8AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_IOSFSBCTL, (~B_QNC_PCIE_IOSFSBCTL_SBIC_MASK), V_PCIE_ROOT_PORT_SBIC_VALUE);
+  QNCMmPci8(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_IOSFSBCTL) = QNCMmPci8AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_IOSFSBCTL, (~B_QNC_PCIE_IOSFSBCTL_SBIC_MASK), V_PCIE_ROOT_PORT_SBIC_VALUE);
+
+  //
+  // Program SVID/SID the same as VID/DID for Root ports.
+  //
+  QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, PCI_VENDOR_ID_OFFSET);
+  QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, PCI_VENDOR_ID_OFFSET);
+
+  //
+  // Set the IPF bit in MCR2
+  //
+  QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_MPC2) = QNCMmPci32Or(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_MPC2, B_QNC_PCIE_MPC2_IPF);
+  QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_MPC2) = QNCMmPci32Or(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_MPC2, B_QNC_PCIE_MPC2_IPF);
+
+  //
+  // Set up the Posted and Non Posted Request sizes for PCIe
+  //
+  QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_CCFG) = QNCMmPci32AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_CCFG, ~B_QNC_PCIE_CCFG_UPSD, (B_QNC_PCIE_CCFG_UNRS | B_QNC_PCIE_CCFG_UPRS));
+
+  return;
+}
+
+
+/**
+  Complete initialization all the pci express rootports on Soc.
+**/
+EFI_STATUS
+EFIAPI
+PciExpressInit (
+  )
+{
+  UINT64                            PciExpressBar;
+  UINT32                            QNCRootComplexBar;
+  UINT32                            QNCPmioBase;
+  UINT32                            QNCGpeBase;
+  UINTN                             RpEnableMask;
+  PCIEXP_ROOT_PORT_CONFIGURATION    *mRootPortConfig;
+  QNC_DEVICE_ENABLES                mQNCDeviceEnables;
+
+  //
+  // Get BAR registers
+  //
+  QNCRootComplexBar  = QNC_RCRB_BASE;
+  QNCPmioBase        = LpcPciCfg32 (R_QNC_LPC_PM1BLK) & B_QNC_LPC_PM1BLK_MASK;
+  QNCGpeBase         = LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & B_QNC_LPC_GPE0BLK_MASK;
+  RpEnableMask = 0;                 // assume all root ports are disabled
+
+  PciExpressBar = PcdGet64 (PcdPciExpressBaseAddress);
+
+  //
+  // Get platform information from PCD entries
+  //
+  mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);
+  mRootPortConfig = (PCIEXP_ROOT_PORT_CONFIGURATION*) PcdGetPtr (PcdPcieRootPortConfiguration);
+
+  DEBUG ((EFI_D_INFO, " mRootPortConfig: 0x%x,  value1: 0x%x, value2: 0x%x, value3: 0x%x, value4: 0x%x\n",
+          mRootPortConfig, mRootPortConfig[0].Uint32, mRootPortConfig[1].Uint32,
+          mRootPortConfig[2].Uint32, mRootPortConfig[3].Uint32));
+
+  QNCDownStreamPortsInit (
+                         mRootPortConfig,
+                         &mQNCDeviceEnables,
+                         PciExpressBar,
+                         QNCRootComplexBar,
+                         QNCPmioBase,
+                         QNCGpeBase,
+                         &RpEnableMask
+                         );
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c
new file mode 100644
index 0000000000..7df1c15f5b
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c
@@ -0,0 +1,2112 @@
+/** @file
+MTRR setting library
+
+Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+#include <Library/MtrrLib.h>
+#include <Library/BaseLib.h>
+#include <Library/CpuLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/QNCAccessLib.h>
+
+#define QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING         0x590
+
+#define CACHE_MTRR_ENABLED                            0x800
+#define CACHE_FIXED_MTRR_ENABLED                      0x400
+#define IA32_MTRR_CAP_VCNT_MASK                       0xFF
+
+//
+// Context to save and restore when MTRRs are programmed
+//
+typedef struct {
+  UINTN    Cr4;
+  BOOLEAN  InterruptState;
+} MTRR_CONTEXT;
+
+//
+// This table defines the offset, base and length of the fixed MTRRs
+//
+CONST FIXED_MTRR  mMtrrLibFixedMtrrTable[] = {
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000, 0,       SIZE_64KB },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000, 0x80000, SIZE_16KB },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_A0000, 0xA0000, SIZE_16KB },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C0000,  0xC0000, SIZE_4KB  },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C8000,  0xC8000, SIZE_4KB  },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D0000,  0xD0000, SIZE_4KB  },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D8000,  0xD8000, SIZE_4KB  },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E0000,  0xE0000, SIZE_4KB  },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E8000,  0xE8000, SIZE_4KB  },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F0000,  0xF0000, SIZE_4KB  },
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000,  0xF8000, SIZE_4KB  }
+};
+
+//
+// Lookup table used to print MTRRs
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
+  "UC",  // CacheUncacheable
+  "WC",  // CacheWriteCombining
+  "R*",  // Invalid
+  "R*",  // Invalid
+  "WT",  // CacheWriteThrough
+  "WP",  // CacheWriteProtected
+  "WB",  // CacheWriteBack
+  "R*"   // Invalid
+};
+
+UINT64
+MtrrRegisterRead (
+  IN  UINT32  MtrrRegister
+  )
+{
+  UINT64  Result;
+
+  Result = (UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister);
+  if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) {
+    Result = Result | LShiftU64 ((UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1), 32);
+  }
+  return Result;
+}
+
+UINT64
+MtrrRegisterWrite (
+  IN  UINT32  MtrrRegister,
+  IN  UINT64  Value
+  )
+{
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister, (UINT32)Value);
+  if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) {
+    QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1, (UINT32)RShiftU64 (Value, 32));
+  }
+  return Value;
+}
+
+UINT64
+MtrrRegisterBitFieldWrite (
+  IN  UINT32  MtrrRegister,
+  IN  UINTN   StartBit,
+  IN  UINTN   EndBit,
+  IN  UINT64  Value
+  )
+{
+  return MtrrRegisterWrite (
+           MtrrRegister,
+           BitFieldWrite64 (
+             MtrrRegisterRead (MtrrRegister),
+             StartBit,
+             EndBit,
+             Value
+             )
+           );
+}
+
+/**
+  Worker function returns the variable MTRR count for the CPU.
+
+  @return Variable MTRR count
+
+**/
+UINT32
+GetVariableMtrrCountWorker (
+  VOID
+  )
+{
+  UINT32  VariableMtrrCount;
+
+  VariableMtrrCount = (UINT32)(MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP) & IA32_MTRR_CAP_VCNT_MASK);
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
+  return VariableMtrrCount;
+}
+
+/**
+  Returns the variable MTRR count for the CPU.
+
+  @return Variable MTRR count
+
+**/
+UINT32
+EFIAPI
+GetVariableMtrrCount (
+  VOID
+  )
+{
+  if (!IsMtrrSupported ()) {
+    return 0;
+  }
+  return GetVariableMtrrCountWorker ();
+}
+
+/**
+  Worker function returns the firmware usable variable MTRR count for the CPU.
+
+  @return Firmware usable variable MTRR count
+
+**/
+UINT32
+GetFirmwareVariableMtrrCountWorker (
+  VOID
+  )
+{
+  UINT32  VariableMtrrCount;
+  UINT32  ReservedMtrrNumber;
+
+  VariableMtrrCount = GetVariableMtrrCountWorker ();
+  ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
+  if (VariableMtrrCount < ReservedMtrrNumber) {
+    return 0;
+  }
+
+  return VariableMtrrCount - ReservedMtrrNumber;
+}
+
+/**
+  Returns the firmware usable variable MTRR count for the CPU.
+
+  @return Firmware usable variable MTRR count
+
+**/
+UINT32
+EFIAPI
+GetFirmwareVariableMtrrCount (
+  VOID
+  )
+{
+  if (!IsMtrrSupported ()) {
+    return 0;
+  }
+  return GetFirmwareVariableMtrrCountWorker ();
+}
+
+/**
+  Worker function returns the default MTRR cache type for the system.
+
+  If MtrrSetting is not NULL, returns the default MTRR cache type from input
+  MTRR settings buffer.
+  If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
+
+  @param[in]  MtrrSetting    A buffer holding all MTRRs content.
+
+  @return  The default MTRR cache type.
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+MtrrGetDefaultMemoryTypeWorker (
+  IN MTRR_SETTINGS      *MtrrSetting
+  )
+{
+  if (MtrrSetting == NULL) {
+    return (MTRR_MEMORY_CACHE_TYPE) (MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE) & 0x7);
+  } else {
+    return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);
+  }
+}
+
+
+/**
+  Returns the default MTRR cache type for the system.
+
+  @return  The default MTRR cache type.
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+EFIAPI
+MtrrGetDefaultMemoryType (
+  VOID
+  )
+{
+  if (!IsMtrrSupported ()) {
+    return CacheUncacheable;
+  }
+  return MtrrGetDefaultMemoryTypeWorker (NULL);
+}
+
+/**
+  Preparation before programming MTRR.
+
+  This function will do some preparation for programming MTRRs:
+  disable cache, invalid cache and disable MTRR caching functionality
+
+  @param[out] MtrrContext  Pointer to context to save
+
+**/
+VOID
+PreMtrrChange (
+  OUT MTRR_CONTEXT  *MtrrContext
+  )
+{
+  //
+  // Disable interrupts and save current interrupt state
+  //
+  MtrrContext->InterruptState = SaveAndDisableInterrupts();
+
+  //
+  // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
+  //
+  AsmDisableCache ();
+
+  //
+  // Save original CR4 value and clear PGE flag (Bit 7)
+  //
+  MtrrContext->Cr4 = AsmReadCr4 ();
+  AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
+
+  //
+  // Flush all TLBs
+  //
+  CpuFlushTlb ();
+
+  //
+  // Disable MTRRs
+  //
+  MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 0);
+}
+
+/**
+  Cleaning up after programming MTRRs.
+
+  This function will do some clean up after programming MTRRs:
+  Flush all TLBs,  re-enable caching, restore CR4.
+
+  @param[in] MtrrContext  Pointer to context to restore
+
+**/
+VOID
+PostMtrrChangeEnableCache (
+  IN MTRR_CONTEXT  *MtrrContext
+  )
+{
+  //
+  // Flush all TLBs
+  //
+  CpuFlushTlb ();
+
+  //
+  // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
+  //
+  AsmEnableCache ();
+
+  //
+  // Restore original CR4 value
+  //
+  AsmWriteCr4 (MtrrContext->Cr4);
+
+  //
+  // Restore original interrupt state
+  //
+  SetInterruptState (MtrrContext->InterruptState);
+}
+
+/**
+  Cleaning up after programming MTRRs.
+
+  This function will do some clean up after programming MTRRs:
+  enable MTRR caching functionality, and enable cache
+
+  @param[in] MtrrContext  Pointer to context to restore
+
+**/
+VOID
+PostMtrrChange (
+  IN MTRR_CONTEXT  *MtrrContext
+  )
+{
+  //
+  // Enable Cache MTRR
+  //
+  MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 3);
+
+  PostMtrrChangeEnableCache (MtrrContext);
+}
+
+/**
+  Worker function gets the content in fixed MTRRs
+
+  @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.
+
+  @retval The pointer of FixedSettings
+
+**/
+MTRR_FIXED_SETTINGS*
+MtrrGetFixedMtrrWorker (
+  OUT MTRR_FIXED_SETTINGS         *FixedSettings
+  )
+{
+  UINT32  Index;
+
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+      FixedSettings->Mtrr[Index] =
+        MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);
+  }
+
+  return FixedSettings;
+}
+
+
+/**
+  This function gets the content in fixed MTRRs
+
+  @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.
+
+  @retval The pointer of FixedSettings
+
+**/
+MTRR_FIXED_SETTINGS*
+EFIAPI
+MtrrGetFixedMtrr (
+  OUT MTRR_FIXED_SETTINGS         *FixedSettings
+  )
+{
+  if (!IsMtrrSupported ()) {
+    return FixedSettings;
+  }
+
+  return MtrrGetFixedMtrrWorker (FixedSettings);
+}
+
+
+/**
+  Worker function will get the raw value in variable MTRRs
+
+  If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
+  MTRR settings buffer.
+  If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
+
+  @param[in]  MtrrSetting        A buffer holding all MTRRs content.
+  @param[in]  VariableMtrrCount  Number of variable MTRRs.
+  @param[out] VariableSettings   A buffer to hold variable MTRRs content.
+
+  @return The VariableSettings input pointer
+
+**/
+MTRR_VARIABLE_SETTINGS*
+MtrrGetVariableMtrrWorker (
+  IN  MTRR_SETTINGS           *MtrrSetting,
+  IN  UINT32                  VariableMtrrCount,
+  OUT MTRR_VARIABLE_SETTINGS  *VariableSettings
+  )
+{
+  UINT32  Index;
+
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
+
+  for (Index = 0; Index < VariableMtrrCount; Index++) {
+    if (MtrrSetting == NULL) {
+      VariableSettings->Mtrr[Index].Base =
+        MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1));
+      VariableSettings->Mtrr[Index].Mask =
+        MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1);
+    } else {
+      VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;
+      VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;
+    }
+  }
+
+  return  VariableSettings;
+}
+
+/**
+  This function will get the raw value in variable MTRRs
+
+  @param[out]  VariableSettings   A buffer to hold variable MTRRs content.
+
+  @return The VariableSettings input pointer
+
+**/
+MTRR_VARIABLE_SETTINGS*
+EFIAPI
+MtrrGetVariableMtrr (
+  OUT MTRR_VARIABLE_SETTINGS         *VariableSettings
+  )
+{
+  if (!IsMtrrSupported ()) {
+    return VariableSettings;
+  }
+
+  return MtrrGetVariableMtrrWorker (
+           NULL,
+           GetVariableMtrrCountWorker (),
+           VariableSettings
+           );
+}
+
+/**
+  Programs fixed MTRRs registers.
+
+  @param[in]      MemoryCacheType  The memory type to set.
+  @param[in, out] Base             The base address of memory range.
+  @param[in, out] Length           The length of memory range.
+  @param[out]     ReturnMsrNum     The index of the fixed MTRR MSR to program.
+  @param[out]     ReturnClearMask  The bits to clear in the fixed MTRR MSR.
+  @param[out]     ReturnOrMask     The bits to set in the fixed MTRR MSR.
+
+  @retval RETURN_SUCCESS      The cache type was updated successfully
+  @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid
+                              for the fixed MTRRs.
+
+**/
+RETURN_STATUS
+ProgramFixedMtrr (
+  IN     UINT64               MemoryCacheType,
+  IN OUT UINT64               *Base,
+  IN OUT UINT64               *Length,
+  OUT    UINT32               *ReturnMsrNum,
+  OUT    UINT64               *ReturnClearMask,
+  OUT    UINT64               *ReturnOrMask
+  )
+{
+  UINT32  MsrNum;
+  UINT32  ByteShift;
+  UINT64  OrMask;
+  UINT64  ClearMask;
+
+  OrMask    = 0;
+  ClearMask = 0;
+
+  for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
+    if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
+        (*Base <
+            (
+              mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
+              (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)
+            )
+          )
+        ) {
+      break;
+    }
+  }
+
+  if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
+    return RETURN_UNSUPPORTED;
+  }
+
+  //
+  // We found the fixed MTRR to be programmed
+  //
+  for (ByteShift = 0; ByteShift < 8; ByteShift++) {
+    if (*Base ==
+         (
+           mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
+           (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)
+         )
+       ) {
+      break;
+    }
+  }
+
+  if (ByteShift == 8) {
+    return RETURN_UNSUPPORTED;
+  }
+
+  for (
+        ;
+        ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));
+        ByteShift++
+      ) {
+    OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
+    ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
+    *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;
+    *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;
+  }
+
+  if (ByteShift < 8 && (*Length != 0)) {
+    return RETURN_UNSUPPORTED;
+  }
+
+  *ReturnMsrNum    = MsrNum;
+  *ReturnClearMask = ClearMask;
+  *ReturnOrMask    = OrMask;
+
+  return RETURN_SUCCESS;
+}
+
+
+/**
+  Worker function gets the attribute of variable MTRRs.
+
+  This function shadows the content of variable MTRRs into an
+  internal array: VariableMtrr.
+
+  @param[in]   VariableSettings           The variable MTRR values to shadow
+  @param[in]   FirmwareVariableMtrrCount  The number of variable MTRRs available to firmware
+  @param[in]   MtrrValidBitsMask          The mask for the valid bit of the MTRR
+  @param[in]   MtrrValidAddressMask       The valid address mask for MTRR
+  @param[out]  VariableMtrr               The array to shadow variable MTRRs content
+
+  @return                       The return value of this parameter indicates the
+                                number of MTRRs which has been used.
+
+**/
+UINT32
+MtrrGetMemoryAttributeInVariableMtrrWorker (
+  IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,
+  IN  UINTN                   FirmwareVariableMtrrCount,
+  IN  UINT64                  MtrrValidBitsMask,
+  IN  UINT64                  MtrrValidAddressMask,
+  OUT VARIABLE_MTRR           *VariableMtrr
+  )
+{
+  UINTN   Index;
+  UINT32  UsedMtrr;
+
+  ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
+  for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {
+    if ((VariableSettings->Mtrr[Index].Mask & CACHE_MTRR_ENABLED) != 0) {
+      VariableMtrr[Index].Msr         = (UINT32)Index;
+      VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
+      VariableMtrr[Index].Length      = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
+      VariableMtrr[Index].Type        = (VariableSettings->Mtrr[Index].Base & 0x0ff);
+      VariableMtrr[Index].Valid       = TRUE;
+      VariableMtrr[Index].Used        = TRUE;
+      UsedMtrr++;
+    }
+  }
+  return UsedMtrr;
+}
+
+
+/**
+  Gets the attribute of variable MTRRs.
+
+  This function shadows the content of variable MTRRs into an
+  internal array: VariableMtrr.
+
+  @param[in]   MtrrValidBitsMask     The mask for the valid bit of the MTRR
+  @param[in]   MtrrValidAddressMask  The valid address mask for MTRR
+  @param[out]  VariableMtrr          The array to shadow variable MTRRs content
+
+  @return                       The return value of this parameter indicates the
+                                number of MTRRs which has been used.
+
+**/
+UINT32
+EFIAPI
+MtrrGetMemoryAttributeInVariableMtrr (
+  IN  UINT64                    MtrrValidBitsMask,
+  IN  UINT64                    MtrrValidAddressMask,
+  OUT VARIABLE_MTRR             *VariableMtrr
+  )
+{
+  MTRR_VARIABLE_SETTINGS  VariableSettings;
+
+  if (!IsMtrrSupported ()) {
+    return 0;
+  }
+
+  MtrrGetVariableMtrrWorker (
+    NULL,
+    GetVariableMtrrCountWorker (),
+    &VariableSettings
+    );
+
+  return MtrrGetMemoryAttributeInVariableMtrrWorker (
+           &VariableSettings,
+           GetFirmwareVariableMtrrCountWorker (),
+           MtrrValidBitsMask,
+           MtrrValidAddressMask,
+           VariableMtrr
+           );
+}
+
+
+/**
+  Checks overlap between given memory range and MTRRs.
+
+  @param[in]  FirmwareVariableMtrrCount  The number of variable MTRRs available
+                                         to firmware.
+  @param[in]  Start                      The start address of memory range.
+  @param[in]  End                        The end address of memory range.
+  @param[in]  VariableMtrr               The array to shadow variable MTRRs content
+
+  @retval TRUE             Overlap exists.
+  @retval FALSE            No overlap.
+
+**/
+BOOLEAN
+CheckMemoryAttributeOverlap (
+  IN UINTN             FirmwareVariableMtrrCount,
+  IN PHYSICAL_ADDRESS  Start,
+  IN PHYSICAL_ADDRESS  End,
+  IN VARIABLE_MTRR     *VariableMtrr
+  )
+{
+  UINT32  Index;
+
+  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
+    if (
+         VariableMtrr[Index].Valid &&
+         !(
+           (Start > (VariableMtrr[Index].BaseAddress +
+                     VariableMtrr[Index].Length - 1)
+           ) ||
+           (End < VariableMtrr[Index].BaseAddress)
+         )
+       ) {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+
+/**
+  Marks a variable MTRR as non-valid.
+
+  @param[in]   Index         The index of the array VariableMtrr to be invalidated
+  @param[in]   VariableMtrr  The array to shadow variable MTRRs content
+  @param[out]  UsedMtrr      The number of MTRRs which has already been used
+
+**/
+VOID
+InvalidateShadowMtrr (
+  IN   UINTN              Index,
+  IN   VARIABLE_MTRR      *VariableMtrr,
+  OUT  UINT32             *UsedMtrr
+  )
+{
+  VariableMtrr[Index].Valid = FALSE;
+  *UsedMtrr = *UsedMtrr - 1;
+}
+
+
+/**
+  Combines memory attributes.
+
+  If overlap exists between given memory range and MTRRs, try to combine them.
+
+  @param[in]       FirmwareVariableMtrrCount  The number of variable MTRRs
+                                              available to firmware.
+  @param[in]       Attributes                 The memory type to set.
+  @param[in, out]  Base                       The base address of memory range.
+  @param[in, out]  Length                     The length of memory range.
+  @param[in]       VariableMtrr               The array to shadow variable MTRRs content
+  @param[in, out]  UsedMtrr                   The number of MTRRs which has already been used
+  @param[out]      OverwriteExistingMtrr      Returns whether an existing MTRR was used
+
+  @retval EFI_SUCCESS            Memory region successfully combined.
+  @retval EFI_ACCESS_DENIED      Memory region cannot be combined.
+
+**/
+RETURN_STATUS
+CombineMemoryAttribute (
+  IN     UINT32             FirmwareVariableMtrrCount,
+  IN     UINT64             Attributes,
+  IN OUT UINT64             *Base,
+  IN OUT UINT64             *Length,
+  IN     VARIABLE_MTRR      *VariableMtrr,
+  IN OUT UINT32             *UsedMtrr,
+  OUT    BOOLEAN            *OverwriteExistingMtrr
+  )
+{
+  UINT32  Index;
+  UINT64  CombineStart;
+  UINT64  CombineEnd;
+  UINT64  MtrrEnd;
+  UINT64  EndAddress;
+  BOOLEAN CoveredByExistingMtrr;
+
+  *OverwriteExistingMtrr = FALSE;
+  CoveredByExistingMtrr = FALSE;
+  EndAddress = *Base +*Length - 1;
+
+  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
+
+    MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
+    if (
+         !VariableMtrr[Index].Valid ||
+         (
+           *Base > (MtrrEnd) ||
+           (EndAddress < VariableMtrr[Index].BaseAddress)
+         )
+       ) {
+      continue;
+    }
+
+    //
+    // Combine same attribute MTRR range
+    //
+    if (Attributes == VariableMtrr[Index].Type) {
+      //
+      // if the MTRR range contain the request range, set a flag, then continue to
+      // invalidate any MTRR of the same request range with higher priority cache type.
+      //
+      if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
+        CoveredByExistingMtrr = TRUE;
+        continue;
+      }
+      //
+      // invalid this MTRR, and program the combine range
+      //
+      CombineStart  =
+        (*Base) < VariableMtrr[Index].BaseAddress ?
+          (*Base) :
+          VariableMtrr[Index].BaseAddress;
+      CombineEnd    = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
+
+      //
+      // Record the MTRR usage status in VariableMtrr array.
+      //
+      InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
+      *Base       = CombineStart;
+      *Length     = CombineEnd - CombineStart + 1;
+      EndAddress  = CombineEnd;
+      *OverwriteExistingMtrr = TRUE;
+      continue;
+    } else {
+      //
+      // The cache type is different, but the range is convered by one MTRR
+      //
+      if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
+        InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
+        continue;
+      }
+
+    }
+
+    if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
+         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
+        (Attributes == MTRR_CACHE_WRITE_BACK &&
+         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
+        (Attributes == MTRR_CACHE_UNCACHEABLE) ||
+        (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
+     ) {
+      *OverwriteExistingMtrr = TRUE;
+      continue;
+    }
+    //
+    // Other type memory overlap is invalid
+    //
+    return RETURN_ACCESS_DENIED;
+  }
+
+  if (CoveredByExistingMtrr) {
+    *Length = 0;
+  }
+
+  return RETURN_SUCCESS;
+}
+
+
+/**
+  Calculates the maximum value which is a power of 2, but less the MemoryLength.
+
+  @param[in]  MemoryLength        The number to pass in.
+
+  @return The maximum value which is align to power of 2 and less the MemoryLength
+
+**/
+UINT64
+Power2MaxMemory (
+  IN UINT64                     MemoryLength
+  )
+{
+  UINT64  Result;
+
+  if (RShiftU64 (MemoryLength, 32) != 0) {
+    Result = LShiftU64 (
+               (UINT64) GetPowerOfTwo32 (
+                          (UINT32) RShiftU64 (MemoryLength, 32)
+                          ),
+               32
+               );
+  } else {
+    Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
+  }
+
+  return Result;
+}
+
+
+/**
+  Determines the MTRR numbers used to program a memory range.
+
+  This function first checks the alignment of the base address.
+  If the alignment of the base address <= Length, cover the memory range
+ (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and
+  Length -= alignment. Repeat the step until alignment > Length.
+
+  Then this function determines which direction of programming the variable
+  MTRRs for the remaining length will use fewer MTRRs.
+
+  @param[in]  BaseAddress Length of Memory to program MTRR
+  @param[in]  Length      Length of Memory to program MTRR
+  @param[in]  MtrrNumber  Pointer to the number of necessary MTRRs
+
+  @retval TRUE        Positive direction is better.
+          FALSE       Negative direction is better.
+
+**/
+BOOLEAN
+GetMtrrNumberAndDirection (
+  IN UINT64      BaseAddress,
+  IN UINT64      Length,
+  IN UINTN       *MtrrNumber
+  )
+{
+  UINT64  TempQword;
+  UINT64  Alignment;
+  UINT32  Positive;
+  UINT32  Subtractive;
+
+  *MtrrNumber = 0;
+
+  if (BaseAddress != 0) {
+    do {
+      //
+      // Calculate the alignment of the base address.
+      //
+      Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
+
+      if (Alignment > Length) {
+        break;
+      }
+
+      (*MtrrNumber)++;
+      BaseAddress += Alignment;
+      Length -= Alignment;
+    } while (TRUE);
+
+    if (Length == 0) {
+      return TRUE;
+    }
+  }
+
+  TempQword   = Length;
+  Positive    = 0;
+  Subtractive = 0;
+
+  do {
+    TempQword -= Power2MaxMemory (TempQword);
+    Positive++;
+  } while (TempQword != 0);
+
+  TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;
+  Subtractive++;
+  do {
+    TempQword -= Power2MaxMemory (TempQword);
+    Subtractive++;
+  } while (TempQword != 0);
+
+  if (Positive <= Subtractive) {
+    *MtrrNumber += Positive;
+    return TRUE;
+  } else {
+    *MtrrNumber += Subtractive;
+    return FALSE;
+  }
+}
+
+/**
+  Invalid variable MTRRs according to the value in the shadow array.
+
+  This function programs MTRRs according to the values specified
+  in the shadow array.
+
+  @param[in, out]  VariableSettings   Variable MTRR settings
+  @param[in]       VariableMtrrCount  Number of variable MTRRs
+  @param[in, out]  VariableMtrr       Shadow of variable MTRR contents
+
+**/
+VOID
+InvalidateMtrr (
+  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,
+  IN     UINTN                   VariableMtrrCount,
+  IN OUT VARIABLE_MTRR           *VariableMtrr
+  )
+{
+  UINTN         Index;
+
+  for (Index = 0; Index < VariableMtrrCount; Index++) {
+    if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
+       VariableSettings->Mtrr[Index].Base = 0;
+       VariableSettings->Mtrr[Index].Mask = 0;
+       VariableMtrr[Index].Used = FALSE;
+    }
+  }
+}
+
+
+/**
+  Programs variable MTRRs
+
+  This function programs variable MTRRs
+
+  @param[in, out]  VariableSettings      Variable MTRR settings.
+  @param[in]       MtrrNumber            Index of MTRR to program.
+  @param[in]       BaseAddress           Base address of memory region.
+  @param[in]       Length                Length of memory region.
+  @param[in]       MemoryCacheType       Memory type to set.
+  @param[in]       MtrrValidAddressMask  The valid address mask for MTRR
+
+**/
+VOID
+ProgramVariableMtrr (
+  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,
+  IN     UINTN                   MtrrNumber,
+  IN     PHYSICAL_ADDRESS        BaseAddress,
+  IN     UINT64                  Length,
+  IN     UINT64                  MemoryCacheType,
+  IN     UINT64                  MtrrValidAddressMask
+  )
+{
+  UINT64        TempQword;
+
+  //
+  // MTRR Physical Base
+  //
+  TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
+  VariableSettings->Mtrr[MtrrNumber].Base = TempQword;
+
+  //
+  // MTRR Physical Mask
+  //
+  TempQword = ~(Length - 1);
+  VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | CACHE_MTRR_ENABLED;
+}
+
+
+/**
+  Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
+
+  If MtrrSetting is not NULL, gets the default memory attribute from input
+  MTRR settings buffer.
+  If MtrrSetting is NULL, gets the default memory attribute from MSR.
+
+  @param[in]  MtrrSetting        A buffer holding all MTRRs content.
+  @param[in]  MtrrType           MTRR memory type
+
+  @return The enum item in MTRR_MEMORY_CACHE_TYPE
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+GetMemoryCacheTypeFromMtrrType (
+  IN MTRR_SETTINGS         *MtrrSetting,
+  IN UINT64                MtrrType
+  )
+{
+  switch (MtrrType) {
+  case MTRR_CACHE_UNCACHEABLE:
+    return CacheUncacheable;
+  case MTRR_CACHE_WRITE_COMBINING:
+    return CacheWriteCombining;
+  case MTRR_CACHE_WRITE_THROUGH:
+    return CacheWriteThrough;
+  case MTRR_CACHE_WRITE_PROTECTED:
+    return CacheWriteProtected;
+  case MTRR_CACHE_WRITE_BACK:
+    return CacheWriteBack;
+  default:
+    //
+    // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
+    // no MTRR covers the range
+    //
+    return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
+  }
+}
+
+/**
+  Initializes the valid bits mask and valid address mask for MTRRs.
+
+  This function initializes the valid bits mask and valid address mask for MTRRs.
+
+  @param[out]  MtrrValidBitsMask     The mask for the valid bit of the MTRR
+  @param[out]  MtrrValidAddressMask  The valid address mask for the MTRR
+
+**/
+VOID
+MtrrLibInitializeMtrrMask (
+  OUT UINT64 *MtrrValidBitsMask,
+  OUT UINT64 *MtrrValidAddressMask
+  )
+{
+  UINT32  RegEax;
+  UINT8   PhysicalAddressBits;
+
+  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+
+  if (RegEax >= 0x80000008) {
+    AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+
+    PhysicalAddressBits = (UINT8) RegEax;
+  } else {
+    PhysicalAddressBits = 36;
+  }
+
+  *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;
+  *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
+}
+
+
+/**
+  Determines the real attribute of a memory range.
+
+  This function is to arbitrate the real attribute of the memory when
+  there are 2 MTRRs covers the same memory range.  For further details,
+  please refer the IA32 Software Developer's Manual, Volume 3,
+  Section 10.11.4.1.
+
+  @param[in]  MtrrType1    The first kind of Memory type
+  @param[in]  MtrrType2    The second kind of memory type
+
+**/
+UINT64
+MtrrPrecedence (
+  IN UINT64    MtrrType1,
+  IN UINT64    MtrrType2
+  )
+{
+  UINT64 MtrrType;
+
+  MtrrType = MTRR_CACHE_INVALID_TYPE;
+  switch (MtrrType1) {
+  case MTRR_CACHE_UNCACHEABLE:
+    MtrrType = MTRR_CACHE_UNCACHEABLE;
+    break;
+  case MTRR_CACHE_WRITE_COMBINING:
+    if (
+         MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
+         MtrrType2==MTRR_CACHE_UNCACHEABLE
+       ) {
+      MtrrType = MtrrType2;
+    }
+    break;
+  case MTRR_CACHE_WRITE_THROUGH:
+    if (
+         MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
+         MtrrType2==MTRR_CACHE_WRITE_BACK
+       ) {
+      MtrrType = MTRR_CACHE_WRITE_THROUGH;
+    } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
+      MtrrType = MTRR_CACHE_UNCACHEABLE;
+    }
+    break;
+  case MTRR_CACHE_WRITE_PROTECTED:
+    if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
+        MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
+      MtrrType = MtrrType2;
+    }
+    break;
+  case MTRR_CACHE_WRITE_BACK:
+    if (
+         MtrrType2== MTRR_CACHE_UNCACHEABLE ||
+         MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
+         MtrrType2== MTRR_CACHE_WRITE_BACK
+       ) {
+      MtrrType = MtrrType2;
+    }
+    break;
+  case MTRR_CACHE_INVALID_TYPE:
+    MtrrType = MtrrType2;
+    break;
+  default:
+    break;
+  }
+
+  if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
+    MtrrType = MtrrType1;
+  }
+  return MtrrType;
+}
+
+/**
+  Worker function will get the memory cache type of the specific address.
+
+  If MtrrSetting is not NULL, gets the memory cache type from input
+  MTRR settings buffer.
+  If MtrrSetting is NULL, gets the memory cache type from MTRRs.
+
+  @param[in]  MtrrSetting        A buffer holding all MTRRs content.
+  @param[in]  Address            The specific address
+
+  @return Memory cache type of the specific address
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+MtrrGetMemoryAttributeByAddressWorker (
+  IN MTRR_SETTINGS      *MtrrSetting,
+  IN PHYSICAL_ADDRESS   Address
+  )
+{
+  UINT64                  TempQword;
+  UINTN                   Index;
+  UINTN                   SubIndex;
+  UINT64                  MtrrType;
+  UINT64                  TempMtrrType;
+  MTRR_MEMORY_CACHE_TYPE  CacheType;
+  VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
+  UINT64                  MtrrValidBitsMask;
+  UINT64                  MtrrValidAddressMask;
+  UINTN                   VariableMtrrCount;
+  MTRR_VARIABLE_SETTINGS  VariableSettings;
+
+  //
+  // Check if MTRR is enabled, if not, return UC as attribute
+  //
+  if (MtrrSetting == NULL) {
+    TempQword = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);
+  } else {
+    TempQword = MtrrSetting->MtrrDefType;
+  }
+  MtrrType = MTRR_CACHE_INVALID_TYPE;
+
+  if ((TempQword & CACHE_MTRR_ENABLED) == 0) {
+    return CacheUncacheable;
+  }
+
+  //
+  // If address is less than 1M, then try to go through the fixed MTRR
+  //
+  if (Address < BASE_1MB) {
+    if ((TempQword & CACHE_FIXED_MTRR_ENABLED) != 0) {
+      //
+      // Go through the fixed MTRR
+      //
+      for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+         if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
+             Address  < (
+                          mMtrrLibFixedMtrrTable[Index].BaseAddress +
+                          (mMtrrLibFixedMtrrTable[Index].Length * 8)
+                        )
+            ) {
+           SubIndex =
+             ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
+               mMtrrLibFixedMtrrTable[Index].Length;
+           if (MtrrSetting == NULL) {
+             TempQword = MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);
+           } else {
+             TempQword = MtrrSetting->Fixed.Mtrr[Index];
+           }
+           MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
+           return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
+         }
+      }
+    }
+  }
+  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
+
+  MtrrGetVariableMtrrWorker (
+    MtrrSetting,
+    GetVariableMtrrCountWorker (),
+    &VariableSettings
+    );
+
+  MtrrGetMemoryAttributeInVariableMtrrWorker (
+           &VariableSettings,
+           GetFirmwareVariableMtrrCountWorker (),
+           MtrrValidBitsMask,
+           MtrrValidAddressMask,
+           VariableMtrr
+           );
+
+  //
+  // Go through the variable MTRR
+  //
+  VariableMtrrCount = GetVariableMtrrCountWorker ();
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
+
+  for (Index = 0; Index < VariableMtrrCount; Index++) {
+    if (VariableMtrr[Index].Valid) {
+      if (Address >= VariableMtrr[Index].BaseAddress &&
+          Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
+        TempMtrrType = VariableMtrr[Index].Type;
+        MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
+      }
+    }
+  }
+  CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
+
+  return CacheType;
+}
+
+
+/**
+  This function will get the memory cache type of the specific address.
+
+  This function is mainly for debug purpose.
+
+  @param[in]  Address   The specific address
+
+  @return Memory cache type of the specific address
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+EFIAPI
+MtrrGetMemoryAttribute (
+  IN PHYSICAL_ADDRESS   Address
+  )
+{
+  if (!IsMtrrSupported ()) {
+    return CacheUncacheable;
+  }
+
+  return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
+}
+
+/**
+  Worker function prints all MTRRs for debugging.
+
+  If MtrrSetting is not NULL, print MTRR settings from from input MTRR
+  settings buffer.
+  If MtrrSetting is NULL, print MTRR settings from MTRRs.
+
+  @param  MtrrSetting    A buffer holding all MTRRs content.
+**/
+VOID
+MtrrDebugPrintAllMtrrsWorker (
+  IN MTRR_SETTINGS    *MtrrSetting
+  )
+{
+  DEBUG_CODE (
+    MTRR_SETTINGS  LocalMtrrs;
+    MTRR_SETTINGS  *Mtrrs;
+    UINTN          Index;
+    UINTN          Index1;
+    UINTN          VariableMtrrCount;
+    UINT64         Base;
+    UINT64         Limit;
+    UINT64         MtrrBase;
+    UINT64         MtrrLimit;
+    UINT64         RangeBase;
+    UINT64         RangeLimit;
+    UINT64         NoRangeBase;
+    UINT64         NoRangeLimit;
+    UINT32         RegEax;
+    UINTN          MemoryType;
+    UINTN          PreviousMemoryType;
+    BOOLEAN        Found;
+
+    if (!IsMtrrSupported ()) {
+      return;
+    }
+
+    DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
+    DEBUG((DEBUG_CACHE, "=============\n"));
+
+    if (MtrrSetting != NULL) {
+      Mtrrs = MtrrSetting;
+    } else {
+      MtrrGetAllMtrrs (&LocalMtrrs);
+      Mtrrs = &LocalMtrrs;
+    }
+
+    DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
+    for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+      DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
+    }
+
+    VariableMtrrCount = GetVariableMtrrCount ();
+    for (Index = 0; Index < VariableMtrrCount; Index++) {
+      DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
+        Index,
+        Mtrrs->Variables.Mtrr[Index].Base,
+        Mtrrs->Variables.Mtrr[Index].Mask
+        ));
+    }
+    DEBUG((DEBUG_CACHE, "\n"));
+    DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
+    DEBUG((DEBUG_CACHE, "====================================\n"));
+
+    Base = 0;
+    PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
+    for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+      Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
+      for (Index1 = 0; Index1 < 8; Index1++) {
+      MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);
+        if (MemoryType > CacheWriteBack) {
+          MemoryType = MTRR_CACHE_INVALID_TYPE;
+        }
+        if (MemoryType != PreviousMemoryType) {
+          if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
+            DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
+          }
+          PreviousMemoryType = MemoryType;
+          DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
+        }
+        Base += mMtrrLibFixedMtrrTable[Index].Length;
+      }
+    }
+    DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
+
+    VariableMtrrCount = GetVariableMtrrCount ();
+
+    Limit        = BIT36 - 1;
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+    if (RegEax >= 0x80000008) {
+      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+      Limit = LShiftU64 (1, RegEax & 0xff) - 1;
+    }
+    Base = BASE_1MB;
+    PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
+    do {
+      MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);
+      if (MemoryType > CacheWriteBack) {
+        MemoryType = MTRR_CACHE_INVALID_TYPE;
+      }
+
+      if (MemoryType != PreviousMemoryType) {
+        if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
+          DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
+        }
+        PreviousMemoryType = MemoryType;
+        DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
+      }
+
+      RangeBase    = BASE_1MB;
+      NoRangeBase  = BASE_1MB;
+      RangeLimit   = Limit;
+      NoRangeLimit = Limit;
+
+      for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
+        if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
+          //
+          // If mask is not valid, then do not display range
+          //
+          continue;
+        }
+        MtrrBase  = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
+        MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
+
+        if (Base >= MtrrBase && Base < MtrrLimit) {
+          Found = TRUE;
+        }
+
+        if (Base >= MtrrBase && MtrrBase > RangeBase) {
+          RangeBase = MtrrBase;
+        }
+        if (Base > MtrrLimit && MtrrLimit > RangeBase) {
+          RangeBase = MtrrLimit + 1;
+        }
+        if (Base < MtrrBase && MtrrBase < RangeLimit) {
+          RangeLimit = MtrrBase - 1;
+        }
+        if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
+          RangeLimit = MtrrLimit;
+        }
+
+        if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
+          NoRangeBase = MtrrLimit + 1;
+        }
+        if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
+          NoRangeLimit = MtrrBase - 1;
+        }
+      }
+
+      if (Found) {
+        Base = RangeLimit + 1;
+      } else {
+        Base = NoRangeLimit + 1;
+      }
+    } while (Base < Limit);
+    DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
+  );
+}
+
+
+/**
+  This function prints all MTRRs for debugging.
+**/
+VOID
+EFIAPI
+MtrrDebugPrintAllMtrrs (
+  VOID
+  )
+{
+  MtrrDebugPrintAllMtrrsWorker (NULL);
+}
+
+
+/**
+  Worker function attempts to set the attributes for a memory range.
+
+  If MtrrSettings is not NULL, set the attributes into the input MTRR
+  settings buffer.
+  If MtrrSettings is NULL, set the attributes into MTRRs registers.
+
+  @param[in, out]  MtrrSetting       A buffer holding all MTRRs content.
+  @param[in]       BaseAddress       The physical address that is the start
+                                     address of a memory region.
+  @param[in]       Length            The size in bytes of the memory region.
+  @param[in]       Attribute         The bit mask of attributes to set for the
+                                     memory region.
+
+  @retval RETURN_SUCCESS            The attributes were set for the memory
+                                    region.
+  @retval RETURN_INVALID_PARAMETER  Length is zero.
+  @retval RETURN_UNSUPPORTED        The processor does not support one or
+                                    more bytes of the memory resource range
+                                    specified by BaseAddress and Length.
+  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support
+                                    for the memory resource range specified
+                                    by BaseAddress and Length.
+  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource
+                                    range specified by BaseAddress and Length
+                                    cannot be modified.
+  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to
+                                    modify the attributes of the memory
+                                    resource range.
+
+**/
+RETURN_STATUS
+MtrrSetMemoryAttributeWorker (
+  IN OUT MTRR_SETTINGS           *MtrrSetting,
+  IN PHYSICAL_ADDRESS            BaseAddress,
+  IN UINT64                      Length,
+  IN MTRR_MEMORY_CACHE_TYPE      Attribute
+  )
+{
+  UINT64                    TempQword;
+  RETURN_STATUS             Status;
+  UINT64                    MemoryType;
+  UINT64                    Alignment;
+  BOOLEAN                   OverLap;
+  BOOLEAN                   Positive;
+  UINT32                    MsrNum;
+  UINTN                     MtrrNumber;
+  VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
+  UINT32                    UsedMtrr;
+  UINT64                    MtrrValidBitsMask;
+  UINT64                    MtrrValidAddressMask;
+  BOOLEAN                   OverwriteExistingMtrr;
+  UINT32                    FirmwareVariableMtrrCount;
+  MTRR_CONTEXT              MtrrContext;
+  BOOLEAN                   MtrrContextValid;
+  BOOLEAN                   FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];
+  BOOLEAN                   FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];
+  MTRR_FIXED_SETTINGS       WorkingFixedSettings;
+  UINT32                    VariableMtrrCount;
+  MTRR_VARIABLE_SETTINGS    OriginalVariableSettings;
+  BOOLEAN                   ProgramVariableSettings;
+  MTRR_VARIABLE_SETTINGS    WorkingVariableSettings;
+  UINT32                    Index;
+  UINT64                    ClearMask;
+  UINT64                    OrMask;
+  UINT64                    NewValue;
+  MTRR_VARIABLE_SETTINGS    *VariableSettings;
+
+  MtrrContextValid  = FALSE;
+  VariableMtrrCount = 0;
+  ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+    FixedSettingsValid[Index]    = FALSE;
+    FixedSettingsModified[Index] = FALSE;
+  }
+  ProgramVariableSettings = FALSE;
+
+  if (!IsMtrrSupported ()) {
+    Status = RETURN_UNSUPPORTED;
+    goto Done;
+  }
+
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
+
+  TempQword = 0;
+  MemoryType = (UINT64)Attribute;
+  OverwriteExistingMtrr = FALSE;
+
+  //
+  // Check for an invalid parameter
+  //
+  if (Length == 0) {
+    Status = RETURN_INVALID_PARAMETER;
+    goto Done;
+  }
+
+  if (
+       (BaseAddress & ~MtrrValidAddressMask) != 0 ||
+       (Length & ~MtrrValidAddressMask) != 0
+     ) {
+    Status = RETURN_UNSUPPORTED;
+    goto Done;
+  }
+
+  //
+  // Check if Fixed MTRR
+  //
+  Status = RETURN_SUCCESS;
+  if (BaseAddress < BASE_1MB) {
+    while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
+      Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);
+      if (RETURN_ERROR (Status)) {
+        goto Done;
+      }
+      if (MtrrSetting != NULL) {
+        MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;
+        MtrrSetting->MtrrDefType |= CACHE_FIXED_MTRR_ENABLED;
+      } else {
+        if (!FixedSettingsValid[MsrNum]) {
+          WorkingFixedSettings.Mtrr[MsrNum] = MtrrRegisterRead (mMtrrLibFixedMtrrTable[MsrNum].Msr);
+          FixedSettingsValid[MsrNum] = TRUE;
+        }
+        NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;
+        if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {
+          WorkingFixedSettings.Mtrr[MsrNum] = NewValue;
+          FixedSettingsModified[MsrNum] = TRUE;
+        }
+      }
+    }
+
+    if (Length == 0) {
+      //
+      // A Length of 0 can only make sense for fixed MTTR ranges.
+      // Since we just handled the fixed MTRRs, we can skip the
+      // variable MTRR section.
+      //
+      goto Done;
+    }
+  }
+
+  //
+  // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
+  // we can set the base to 0 to save variable MTRRs.
+  //
+  if (BaseAddress == BASE_1MB) {
+    BaseAddress = 0;
+    Length += SIZE_1MB;
+  }
+
+  //
+  // Read all variable MTRRs
+  //
+  VariableMtrrCount = GetVariableMtrrCountWorker ();
+  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();
+  if (MtrrSetting != NULL) {
+    VariableSettings = &MtrrSetting->Variables;
+  } else {
+    MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);
+    CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));
+    ProgramVariableSettings = TRUE;
+    VariableSettings = &WorkingVariableSettings;
+  }
+
+  //
+  // Check for overlap
+  //
+  UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (
+               VariableSettings,
+               FirmwareVariableMtrrCount,
+               MtrrValidBitsMask,
+               MtrrValidAddressMask,
+               VariableMtrr
+               );
+  OverLap = CheckMemoryAttributeOverlap (
+              FirmwareVariableMtrrCount,
+              BaseAddress,
+              BaseAddress + Length - 1,
+              VariableMtrr
+              );
+  if (OverLap) {
+    Status = CombineMemoryAttribute (
+               FirmwareVariableMtrrCount,
+               MemoryType,
+               &BaseAddress,
+               &Length,
+               VariableMtrr,
+               &UsedMtrr,
+               &OverwriteExistingMtrr
+               );
+    if (RETURN_ERROR (Status)) {
+      goto Done;
+    }
+
+    if (Length == 0) {
+      //
+      // Combined successfully, invalidate the now-unused MTRRs
+      //
+      InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
+      Status = RETURN_SUCCESS;
+      goto Done;
+    }
+  }
+
+  //
+  // The memory type is the same with the type specified by
+  // MTRR_LIB_IA32_MTRR_DEF_TYPE.
+  //
+  if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {
+    //
+    // Invalidate the now-unused MTRRs
+    //
+    InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
+    goto Done;
+  }
+
+  Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);
+
+  if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
+    Status = RETURN_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  //
+  // Invalidate the now-unused MTRRs
+  //
+  InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
+
+  //
+  // Find first unused MTRR
+  //
+  for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {
+    if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) {
+      break;
+    }
+  }
+
+  if (BaseAddress != 0) {
+    do {
+      //
+      // Calculate the alignment of the base address.
+      //
+      Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
+
+      if (Alignment > Length) {
+        break;
+      }
+
+      //
+      // Find unused MTRR
+      //
+      for (; MsrNum < VariableMtrrCount; MsrNum++) {
+        if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) {
+          break;
+        }
+      }
+
+      ProgramVariableMtrr (
+        VariableSettings,
+        MsrNum,
+        BaseAddress,
+        Alignment,
+        MemoryType,
+        MtrrValidAddressMask
+        );
+      BaseAddress += Alignment;
+      Length -= Alignment;
+    } while (TRUE);
+
+    if (Length == 0) {
+      goto Done;
+    }
+  }
+
+  TempQword = Length;
+
+  if (!Positive) {
+    Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
+
+    //
+    // Find unused MTRR
+    //
+    for (; MsrNum < VariableMtrrCount; MsrNum++) {
+      if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) {
+        break;
+      }
+    }
+
+    ProgramVariableMtrr (
+      VariableSettings,
+      MsrNum,
+      BaseAddress,
+      Length,
+      MemoryType,
+      MtrrValidAddressMask
+      );
+    BaseAddress += Length;
+    TempQword   = Length - TempQword;
+    MemoryType  = MTRR_CACHE_UNCACHEABLE;
+  }
+
+  do {
+    //
+    // Find unused MTRR
+    //
+    for (; MsrNum < VariableMtrrCount; MsrNum++) {
+      if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) {
+        break;
+      }
+    }
+
+    Length = Power2MaxMemory (TempQword);
+    if (!Positive) {
+      BaseAddress -= Length;
+    }
+
+    ProgramVariableMtrr (
+      VariableSettings,
+      MsrNum,
+      BaseAddress,
+      Length,
+      MemoryType,
+      MtrrValidAddressMask
+      );
+
+    if (Positive) {
+      BaseAddress += Length;
+    }
+    TempQword -= Length;
+
+  } while (TempQword > 0);
+
+Done:
+
+  //
+  // Write fixed MTRRs that have been modified
+  //
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+    if (FixedSettingsModified[Index]) {
+      if (!MtrrContextValid) {
+        PreMtrrChange (&MtrrContext);
+        MtrrContextValid = TRUE;
+      }
+      MtrrRegisterWrite (
+        mMtrrLibFixedMtrrTable[Index].Msr,
+        WorkingFixedSettings.Mtrr[Index]
+        );
+    }
+  }
+
+  //
+  // Write variable MTRRs
+  //
+  if (ProgramVariableSettings) {
+    for (Index = 0; Index < VariableMtrrCount; Index++) {
+      if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||
+          WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask    ) {
+        if (!MtrrContextValid) {
+          PreMtrrChange (&MtrrContext);
+          MtrrContextValid = TRUE;
+        }
+        MtrrRegisterWrite (
+          QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),
+          WorkingVariableSettings.Mtrr[Index].Base
+          );
+        MtrrRegisterWrite (
+          QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,
+          WorkingVariableSettings.Mtrr[Index].Mask
+          );
+      }
+    }
+  }
+  if (MtrrContextValid) {
+    PostMtrrChange (&MtrrContext);
+  }
+
+  DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));
+  if (!RETURN_ERROR (Status)) {
+    if (MtrrSetting != NULL) {
+      MtrrSetting->MtrrDefType |= CACHE_MTRR_ENABLED;
+    }
+    MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
+  }
+
+  return Status;
+}
+
+/**
+  This function attempts to set the attributes for a memory range.
+
+  @param[in]  BaseAddress        The physical address that is the start
+                                 address of a memory region.
+  @param[in]  Length             The size in bytes of the memory region.
+  @param[in]  Attributes         The bit mask of attributes to set for the
+                                 memory region.
+
+  @retval RETURN_SUCCESS            The attributes were set for the memory
+                                    region.
+  @retval RETURN_INVALID_PARAMETER  Length is zero.
+  @retval RETURN_UNSUPPORTED        The processor does not support one or
+                                    more bytes of the memory resource range
+                                    specified by BaseAddress and Length.
+  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support
+                                    for the memory resource range specified
+                                    by BaseAddress and Length.
+  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource
+                                    range specified by BaseAddress and Length
+                                    cannot be modified.
+  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to
+                                    modify the attributes of the memory
+                                    resource range.
+
+**/
+RETURN_STATUS
+EFIAPI
+MtrrSetMemoryAttribute (
+  IN PHYSICAL_ADDRESS        BaseAddress,
+  IN UINT64                  Length,
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute
+  )
+{
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
+  return MtrrSetMemoryAttributeWorker (
+           NULL,
+           BaseAddress,
+           Length,
+           Attribute
+           );
+}
+
+/**
+  This function attempts to set the attributes into MTRR setting buffer for a memory range.
+
+  @param[in, out]  MtrrSetting  MTRR setting buffer to be set.
+  @param[in]       BaseAddress  The physical address that is the start address
+                                of a memory region.
+  @param[in]       Length       The size in bytes of the memory region.
+  @param[in]       Attribute    The bit mask of attributes to set for the
+                                memory region.
+
+  @retval RETURN_SUCCESS            The attributes were set for the memory region.
+  @retval RETURN_INVALID_PARAMETER  Length is zero.
+  @retval RETURN_UNSUPPORTED        The processor does not support one or more bytes of the
+                                    memory resource range specified by BaseAddress and Length.
+  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support for the memory resource
+                                    range specified by BaseAddress and Length.
+  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource range specified by
+                                    BaseAddress and Length cannot be modified.
+  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to modify the attributes of
+                                    the memory resource range.
+
+**/
+RETURN_STATUS
+EFIAPI
+MtrrSetMemoryAttributeInMtrrSettings (
+  IN OUT MTRR_SETTINGS       *MtrrSetting,
+  IN PHYSICAL_ADDRESS        BaseAddress,
+  IN UINT64                  Length,
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute
+  )
+{
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
+  return MtrrSetMemoryAttributeWorker (
+           MtrrSetting,
+           BaseAddress,
+           Length,
+           Attribute
+           );
+}
+
+/**
+  Worker function setting variable MTRRs
+
+  @param[in]  VariableSettings   A buffer to hold variable MTRRs content.
+
+**/
+VOID
+MtrrSetVariableMtrrWorker (
+  IN MTRR_VARIABLE_SETTINGS         *VariableSettings
+  )
+{
+  UINT32  Index;
+  UINT32  VariableMtrrCount;
+
+  VariableMtrrCount = GetVariableMtrrCountWorker ();
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
+
+  for (Index = 0; Index < VariableMtrrCount; Index++) {
+    MtrrRegisterWrite (
+      QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),
+      VariableSettings->Mtrr[Index].Base
+      );
+    MtrrRegisterWrite (
+      QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,
+      VariableSettings->Mtrr[Index].Mask
+      );
+  }
+}
+
+
+/**
+  This function sets variable MTRRs
+
+  @param[in]  VariableSettings   A buffer to hold variable MTRRs content.
+
+  @return The pointer of VariableSettings
+
+**/
+MTRR_VARIABLE_SETTINGS*
+EFIAPI
+MtrrSetVariableMtrr (
+  IN MTRR_VARIABLE_SETTINGS         *VariableSettings
+  )
+{
+  MTRR_CONTEXT  MtrrContext;
+
+  if (!IsMtrrSupported ()) {
+    return VariableSettings;
+  }
+
+  PreMtrrChange (&MtrrContext);
+  MtrrSetVariableMtrrWorker (VariableSettings);
+  PostMtrrChange (&MtrrContext);
+  MtrrDebugPrintAllMtrrs ();
+
+  return  VariableSettings;
+}
+
+/**
+  Worker function setting fixed MTRRs
+
+  @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.
+
+**/
+VOID
+MtrrSetFixedMtrrWorker (
+  IN MTRR_FIXED_SETTINGS          *FixedSettings
+  )
+{
+  UINT32  Index;
+
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+     MtrrRegisterWrite (
+       mMtrrLibFixedMtrrTable[Index].Msr,
+       FixedSettings->Mtrr[Index]
+       );
+  }
+}
+
+
+/**
+  This function sets fixed MTRRs
+
+  @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.
+
+  @retval The pointer of FixedSettings
+
+**/
+MTRR_FIXED_SETTINGS*
+EFIAPI
+MtrrSetFixedMtrr (
+  IN MTRR_FIXED_SETTINGS          *FixedSettings
+  )
+{
+  MTRR_CONTEXT  MtrrContext;
+
+  if (!IsMtrrSupported ()) {
+    return FixedSettings;
+  }
+
+  PreMtrrChange (&MtrrContext);
+  MtrrSetFixedMtrrWorker (FixedSettings);
+  PostMtrrChange (&MtrrContext);
+  MtrrDebugPrintAllMtrrs ();
+
+  return FixedSettings;
+}
+
+
+/**
+  This function gets the content in all MTRRs (variable and fixed)
+
+  @param[out]  MtrrSetting  A buffer to hold all MTRRs content.
+
+  @retval the pointer of MtrrSetting
+
+**/
+MTRR_SETTINGS *
+EFIAPI
+MtrrGetAllMtrrs (
+  OUT MTRR_SETTINGS                *MtrrSetting
+  )
+{
+  if (!IsMtrrSupported ()) {
+    return MtrrSetting;
+  }
+
+  //
+  // Get fixed MTRRs
+  //
+  MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
+
+  //
+  // Get variable MTRRs
+  //
+  MtrrGetVariableMtrrWorker (
+    NULL,
+    GetVariableMtrrCountWorker (),
+    &MtrrSetting->Variables
+    );
+
+  //
+  // Get MTRR_DEF_TYPE value
+  //
+  MtrrSetting->MtrrDefType = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);
+
+  return MtrrSetting;
+}
+
+
+/**
+  This function sets all MTRRs (variable and fixed)
+
+  @param[in]  MtrrSetting  A buffer holding all MTRRs content.
+
+  @retval The pointer of MtrrSetting
+
+**/
+MTRR_SETTINGS *
+EFIAPI
+MtrrSetAllMtrrs (
+  IN MTRR_SETTINGS                *MtrrSetting
+  )
+{
+  MTRR_CONTEXT  MtrrContext;
+
+  if (!IsMtrrSupported ()) {
+    return MtrrSetting;
+  }
+
+  PreMtrrChange (&MtrrContext);
+
+  //
+  // Set fixed MTRRs
+  //
+  MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
+
+  //
+  // Set variable MTRRs
+  //
+  MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
+
+  //
+  // Set MTRR_DEF_TYPE value
+  //
+  MtrrRegisterWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
+
+  PostMtrrChangeEnableCache (&MtrrContext);
+
+  MtrrDebugPrintAllMtrrs ();
+
+  return MtrrSetting;
+}
+
+
+/**
+  Checks if MTRR is supported.
+
+  @retval TRUE  MTRR is supported.
+  @retval FALSE MTRR is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+IsMtrrSupported (
+  VOID
+  )
+{
+  UINT32  RegEax;
+
+  //
+  // Check CPUID(1).EAX[0..11] for Quark SoC
+  //
+  AsmCpuid (1, &RegEax, NULL, NULL, NULL);
+  if ((RegEax & 0xfff) == QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf
new file mode 100644
index 0000000000..72e83510d5
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf
@@ -0,0 +1,42 @@
+## @file
+#  MTRR library provides APIs for MTRR operation.
+#
+#  Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = MtrrLib
+  MODULE_UNI_FILE                = MtrrLib.uni
+  FILE_GUID                      = 6826b408-f4f3-47ee-917f-af7047f9d937
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = MtrrLib
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  MtrrLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  BaseLib
+  CpuLib
+  DebugLib
+  QNCAccessLib
+
+[Pcd]
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs   ## SOMETIMES_CONSUMES
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni
new file mode 100644
index 0000000000..b564c8af74
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// MtrrLib Module Localized Abstract and Description Content
+//
+// Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"MTRR library provides APIs for MTRR operation"
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"MTRR library provides APIs for MTRR operation."
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c
new file mode 100644
index 0000000000..da364c7b7c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c
@@ -0,0 +1,28 @@
+/** @file
+Base Lib function for QNC internal network access.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <Uefi.h>
+
+/**
+  Gets the base address of PCI Express for Quark North Cluster.
+
+  @return The base address of PCI Express for Quark North Cluster.
+
+**/
+UINTN
+EFIAPI
+QncGetPciExpressBaseAddress (
+  VOID
+  )
+{
+  return (UINTN) PcdGet64(PcdPciExpressBaseAddress);
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c
new file mode 100644
index 0000000000..b9b1e258a0
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c
@@ -0,0 +1,327 @@
+/** @file
+Common Lib function for QNC internal network access.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <Uefi.h>
+
+#include <IntelQNCRegs.h>
+#include <Library/QNCAccessLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Pci22.h>
+
+UINT32
+EFIAPI
+QNCPortRead(
+  UINT8 Port,
+  UINT32 RegAddress
+  )
+{
+  McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
+  McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_READ_DW (Port, RegAddress);
+  return McD0PciCfg32 (QNC_ACCESS_PORT_MDR);
+}
+
+VOID
+EFIAPI
+QNCPortWrite (
+  UINT8 Port,
+  UINT32 RegAddress,
+  UINT32 WriteValue
+  )
+{
+  McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue;
+  McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
+  McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_WRITE_DW (Port, RegAddress);
+}
+
+UINT32
+EFIAPI
+QNCAltPortRead (
+  UINT8 Port,
+  UINT32 RegAddress
+  )
+{
+  McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
+  McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = ALT_MESSAGE_READ_DW (Port, RegAddress);
+  return McD0PciCfg32 (QNC_ACCESS_PORT_MDR);
+}
+
+VOID
+EFIAPI
+QNCAltPortWrite (
+  UINT8 Port,
+  UINT32 RegAddress,
+  UINT32 WriteValue
+  )
+{
+  McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue;
+  McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
+  McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = ALT_MESSAGE_WRITE_DW (Port, RegAddress);
+}
+
+UINT32
+EFIAPI
+QNCPortIORead(
+  UINT8 Port,
+  UINT32 RegAddress
+  )
+{
+  McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
+  McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_IO_READ_DW (Port, RegAddress);
+  return McD0PciCfg32 (QNC_ACCESS_PORT_MDR);
+}
+
+VOID
+EFIAPI
+QNCPortIOWrite (
+  UINT8 Port,
+  UINT32 RegAddress,
+  UINT32 WriteValue
+  )
+{
+  McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue;
+  McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
+  McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_IO_WRITE_DW (Port, RegAddress);
+}
+
+RETURN_STATUS
+EFIAPI
+QNCMmIoWrite (
+  UINT32             MmIoAddress,
+  QNC_MEM_IO_WIDTH    Width,
+  UINT32             DataNumber,
+  VOID               *pData
+  )
+/*++
+
+Routine Description:
+
+  This is for the special consideration for QNC MMIO write, as required by FWG, a reading must be performed after MMIO writing
+to ensure the expected write is processed and data is flushed into chipset
+
+Arguments:
+
+  Row -- row number to be cleared ( start from 1 )
+
+Returns:
+
+  EFI_SUCCESS
+
+--*/
+{
+  RETURN_STATUS  Status;
+  UINTN          Index;
+
+  Status = RETURN_SUCCESS;
+
+  for (Index =0; Index < DataNumber; Index++) {
+    switch (Width) {
+      case QNCMmioWidthUint8:
+        QNCMmio8 (MmIoAddress, 0) = ((UINT8 *)pData)[Index];
+        if (QNCMmio8 (MmIoAddress, 0) != ((UINT8*)pData)[Index]) {
+          Status = RETURN_DEVICE_ERROR;
+          break;
+        }
+        break;
+
+      case QNCMmioWidthUint16:
+        QNCMmio16 (MmIoAddress, 0) = ((UINT16 *)pData)[Index];
+        if (QNCMmio16 (MmIoAddress, 0) != ((UINT16 *)pData)[Index]) {
+          Status = RETURN_DEVICE_ERROR;
+          break;
+        }
+        break;
+
+      case QNCMmioWidthUint32:
+        QNCMmio32 (MmIoAddress, 0) = ((UINT32 *)pData)[Index];
+        if (QNCMmio32 (MmIoAddress, 0) != ((UINT32 *)pData)[Index]) {
+          Status = RETURN_DEVICE_ERROR;
+          break;
+        }
+        break;
+
+      case QNCMmioWidthUint64:
+        QNCMmio64 (MmIoAddress, 0) = ((UINT64 *)pData)[Index];
+        if (QNCMmio64 (MmIoAddress, 0) != ((UINT64 *)pData)[Index]) {
+          Status = RETURN_DEVICE_ERROR;
+          break;
+        }
+        break;
+
+      default:
+        break;
+    }
+  }
+
+  return Status;
+}
+
+UINT32
+EFIAPI
+QncHsmmcRead (
+  VOID
+  )
+{
+  return QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC);
+}
+
+VOID
+EFIAPI
+QncHsmmcWrite (
+  UINT32 WriteValue
+  )
+{
+  UINT16  DeviceId;
+  UINT32  Data32;
+
+  //
+  // Check what Soc we are running on (read Host bridge DeviceId)
+  //
+  DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);
+
+  if (DeviceId == QUARK2_MC_DEVICE_ID) {
+    //
+    // Disable HSMMC configuration
+    //
+    Data32 = QncHsmmcRead ();
+    Data32 &= ~SMM_CTL_EN;
+    QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, Data32);
+
+    //
+    // Validate HSMMC configuration is disabled
+    //
+    Data32 = QncHsmmcRead ();
+    ASSERT((Data32 & SMM_CTL_EN) == 0);
+
+    //
+    // Enable HSMMC configuration
+    //
+    WriteValue |= SMM_CTL_EN;
+  }
+
+  //
+  // Write the register value
+  //
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, WriteValue);
+
+  if (DeviceId == QUARK2_MC_DEVICE_ID) {
+    //
+    // Validate HSMMC configuration is enabled
+    //
+    Data32 = QncHsmmcRead ();
+    ASSERT((Data32 & SMM_CTL_EN) != 0);
+  }
+}
+
+VOID
+EFIAPI
+QncImrWrite (
+  UINT32 ImrBaseOffset,
+  UINT32 ImrLow,
+  UINT32 ImrHigh,
+  UINT32 ImrReadMask,
+  UINT32 ImrWriteMask
+  )
+{
+  UINT16  DeviceId;
+  UINT32  Data32;
+
+  //
+  // Check what Soc we are running on (read Host bridge DeviceId)
+  //
+  DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);
+
+  //
+  // Disable IMR protection
+  //
+  if (DeviceId == QUARK2_MC_DEVICE_ID) {
+    //
+    // Disable IMR protection
+    //
+    Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL);
+    Data32 &= ~IMR_EN;
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, Data32);
+
+    //
+    // Validate IMR protection is disabled
+    //
+    Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL);
+    ASSERT((Data32 & IMR_EN) == 0);
+
+    //
+    // Update the IMR (IMRXL must be last as it may enable IMR violation checking)
+    //
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, ImrReadMask);
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, ImrWriteMask);
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXH, ImrHigh);
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, ImrLow);
+
+    //
+    // Validate IMR protection is enabled/disabled
+    //
+    Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL);
+    ASSERT((Data32 & IMR_EN) == (ImrLow & IMR_EN));
+  } else {
+    //
+    // Disable IMR protection (allow all access)
+    //
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, (UINT32)IMRX_ALL_ACCESS);
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, (UINT32)IMRX_ALL_ACCESS);
+
+    //
+    // Update the IMR (IMRXRM/IMRXWM must be last as they restrict IMR access)
+    //
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, (ImrLow & ~IMR_EN));
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXH, ImrHigh);
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, ImrReadMask);
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, ImrWriteMask);
+  }
+}
+
+VOID
+EFIAPI
+QncIClkAndThenOr (
+  UINT32 RegAddress,
+  UINT32 AndValue,
+  UINT32 OrValue
+  )
+{
+  UINT32 RegValue;
+  //
+  // Whenever an iCLK SB register (Endpoint 32h) is being programmed the access
+  // should always consist of a READ from the address followed by 2 identical
+  // WRITEs to that address.
+  //
+  RegValue = QNCAltPortRead (QUARK_ICLK_SB_PORT_ID, RegAddress);
+  RegValue &= AndValue;
+  RegValue |= OrValue;
+  QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);
+  QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);
+}
+
+VOID
+EFIAPI
+QncIClkOr (
+  UINT32 RegAddress,
+  UINT32 OrValue
+  )
+{
+  UINT32 RegValue;
+  //
+  // Whenever an iCLK SB register (Endpoint 32h) is being programmed the access
+  // should always consist of a READ from the address followed by 2 identical
+  // WRITEs to that address.
+  //
+  RegValue = QNCAltPortRead (QUARK_ICLK_SB_PORT_ID, RegAddress);
+  RegValue |= OrValue;
+  QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);
+  QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf
new file mode 100644
index 0000000000..5489c1aa46
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf
@@ -0,0 +1,37 @@
+## @file
+# Base Intel QNC Library Instance
+#
+# Intel QNC internal network access Library Instance
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = QNCAccessLib
+  FILE_GUID                      = CC13B9FB-DAF5-4b42-907F-122216787C05
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = QNCAccessLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  QNCAccessLib.c
+  BaseAccess.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  DebugLib
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c
new file mode 100644
index 0000000000..65af27c305
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c
@@ -0,0 +1,142 @@
+/** @file
+Runtime Lib function for QNC internal network access.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/QNCAccessLib.h>
+
+///
+/// Set Virtual Address Map Event
+///
+EFI_EVENT                               mDxeRuntimeQncAccessLibVirtualNotifyEvent = NULL;
+
+///
+/// Module global that contains the base physical address of the PCI Express MMIO range.
+///
+UINTN                                   mDxeRuntimeQncAccessLibPciExpressBaseAddress = 0;
+
+/**
+  Convert the physical PCI Express MMIO address to a virtual address.
+
+  @param[in]    Event   The event that is being processed.
+  @param[in]    Context The Event Context.
+**/
+VOID
+EFIAPI
+DxeRuntimeQncAccessLibVirtualNotify (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  EFI_STATUS                       Status;
+
+  //
+  // Convert the physical PCI Express MMIO address to a virtual address.
+  //
+  Status = EfiConvertPointer (0, (VOID **) &mDxeRuntimeQncAccessLibPciExpressBaseAddress);
+
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  The constructor function to setup globals and goto virtual mode notify.
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor completed successfully.
+  @retval Other value   The constructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimeQncAccessLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Cache the physical address of the PCI Express MMIO range into a module global variable
+  //
+  mDxeRuntimeQncAccessLibPciExpressBaseAddress = (UINTN) PcdGet64(PcdPciExpressBaseAddress);
+
+  //
+  // Register SetVirtualAddressMap () notify function
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  DxeRuntimeQncAccessLibVirtualNotify,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &mDxeRuntimeQncAccessLibVirtualNotifyEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  The destructor function frees any allocated buffers and closes the Set Virtual
+  Address Map event.
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The destructor completed successfully.
+  @retval Other value   The destructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimeQncAccessLibDestructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Close the Set Virtual Address Map event
+  //
+  Status = gBS->CloseEvent (mDxeRuntimeQncAccessLibVirtualNotifyEvent);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  Gets the base address of PCI Express for Quark North Cluster.
+
+  @return The base address of PCI Express for Quark North Cluster.
+
+**/
+UINTN
+EFIAPI
+QncGetPciExpressBaseAddress (
+  VOID
+  )
+{
+  //
+  // If system goes to virtual mode then virtual notify callback will update
+  // mDxeRuntimeQncAccessLibPciExpressBaseAddress with virtual address of
+  // PCIe memory base.
+  //
+  return mDxeRuntimeQncAccessLibPciExpressBaseAddress;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf
new file mode 100644
index 0000000000..0e6aa4cd97
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf
@@ -0,0 +1,43 @@
+## @file
+# DXE Runtime Intel QNC Library Instance
+#
+# Intel QNC internal network access Library Instance.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = RuntimeQNCAccessLib
+  FILE_GUID                      = E6B51D93-E4C8-4425-9FA9-9DED814220F9
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = QNCAccessLib|DXE_RUNTIME_DRIVER
+  CONSTRUCTOR                    = DxeRuntimeQncAccessLibConstructor
+  DESTRUCTOR                     = DxeRuntimeQncAccessLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32
+#
+
+[Sources]
+  QNCAccessLib.c
+  RuntimeAccess.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  PcdLib
+  UefiBootServicesTableLib
+  UefiRuntimeLib
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c
new file mode 100644
index 0000000000..d6bba0bc1c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c
@@ -0,0 +1,313 @@
+/** @file
+QNC Smm Library Services that implements SMM Region access, S/W SMI generation and detection.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Base.h>
+#include <IntelQNCRegs.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/QNCAccessLib.h>
+
+#define BOOT_SERVICE_SOFTWARE_SMI_DATA          0
+#define RUNTIME_SOFTWARE_SMI_DATA               1
+
+/**
+  Triggers a run time or boot time SMI.
+
+  This function triggers a software SMM interrupt and set the APMC status with an 8-bit Data.
+
+  @param  Data                 The value to set the APMC status.
+
+**/
+VOID
+InternalTriggerSmi (
+  IN UINT8                     Data
+  )
+{
+  UINT16        GPE0BLK_Base;
+  UINT32        NewValue;
+
+  //
+  // Get GPE0BLK_Base
+  //
+  GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);
+
+
+  //
+  // Enable APM SMI
+  //
+  IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM);
+
+  //
+  // Enable SMI globally
+  //
+  NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+  NewValue |= SMI_EN;
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+  //
+  // Set APM_STS
+  //
+  IoWrite8 (PcdGet16 (PcdSmmDataPort), Data);
+
+  //
+  // Generate the APM SMI
+  //
+  IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData));
+
+  //
+  // Clear the APM SMI Status Bit
+  //
+  IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
+
+  //
+  // Set the EOS Bit
+  //
+  IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
+}
+
+
+/**
+  Triggers an SMI at boot time.
+
+  This function triggers a software SMM interrupt at boot time.
+
+**/
+VOID
+EFIAPI
+TriggerBootServiceSoftwareSmi (
+  VOID
+  )
+{
+  InternalTriggerSmi (BOOT_SERVICE_SOFTWARE_SMI_DATA);
+}
+
+
+/**
+  Triggers an SMI at run time.
+
+  This function triggers a software SMM interrupt at run time.
+
+**/
+VOID
+EFIAPI
+TriggerRuntimeSoftwareSmi (
+  VOID
+  )
+{
+  InternalTriggerSmi (RUNTIME_SOFTWARE_SMI_DATA);
+}
+
+
+/**
+  Gets the software SMI data.
+
+  This function tests if a software SMM interrupt happens. If a software SMI happens,
+  it retrieves the SMM data and returns it as a non-negative value; otherwise a negative
+  value is returned.
+
+  @return Data                 The data retrieved from SMM data port in case of a software SMI;
+                               otherwise a negative value.
+
+**/
+INTN
+InternalGetSwSmiData (
+  VOID
+  )
+{
+  UINT8                        SmiStatus;
+  UINT8                        Data;
+
+  SmiStatus = IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
+  if (((SmiStatus & B_QNC_GPE0BLK_SMIS_APM) != 0) &&
+       (IoRead8 (PcdGet16 (PcdSmmActivationPort)) == PcdGet8 (PcdSmmActivationData))) {
+    Data = IoRead8 (PcdGet16 (PcdSmmDataPort));
+    return (INTN)(UINTN)Data;
+  }
+
+  return -1;
+}
+
+
+/**
+  Test if a boot time software SMI happened.
+
+  This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and
+  it was triggered at boot time, it returns TRUE. Otherwise, it returns FALSE.
+
+  @retval TRUE   A software SMI triggered at boot time happened.
+  @retval FLASE  No software SMI happened or the software SMI was triggered at run time.
+
+**/
+BOOLEAN
+EFIAPI
+IsBootServiceSoftwareSmi (
+  VOID
+  )
+{
+  return (BOOLEAN) (InternalGetSwSmiData () == BOOT_SERVICE_SOFTWARE_SMI_DATA);
+}
+
+
+/**
+  Test if a run time software SMI happened.
+
+  This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and
+  it was triggered at run time, it returns TRUE. Otherwise, it returns FALSE.
+
+  @retval TRUE   A software SMI triggered at run time happened.
+  @retval FLASE  No software SMI happened or the software SMI was triggered at boot time.
+
+**/
+BOOLEAN
+EFIAPI
+IsRuntimeSoftwareSmi (
+  VOID
+  )
+{
+  return (BOOLEAN) (InternalGetSwSmiData () == RUNTIME_SOFTWARE_SMI_DATA);
+}
+
+
+
+/**
+
+  Clear APM SMI Status Bit; Set the EOS bit.
+
+**/
+VOID
+EFIAPI
+ClearSmi (
+  VOID
+  )
+{
+
+  UINT16                       GPE0BLK_Base;
+
+  //
+  // Get GpeBase
+  //
+  GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);
+
+  //
+  // Clear the APM SMI Status Bit
+  //
+  IoOr16 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_APM);
+
+  //
+  // Set the EOS Bit
+  //
+  IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS);
+}
+
+/**
+  This routine is the chipset code that accepts a request to "open" a region of SMRAM.
+  The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
+  The use of "open" means that the memory is visible from all boot-service
+  and SMM agents.
+
+  @retval FALSE  Cannot open a locked SMRAM region
+  @retval TRUE   Success to open SMRAM region.
+**/
+BOOLEAN
+EFIAPI
+QNCOpenSmramRegion (
+  VOID
+  )
+{
+  UINT32                     Smram;
+
+  // Read the SMRAM register
+  Smram = QncHsmmcRead ();
+
+  //
+  //  Is the platform locked?
+  //
+  if (Smram & SMM_LOCKED) {
+    // Cannot Open a locked region
+    DEBUG ((EFI_D_WARN, "Cannot open a locked SMRAM region\n"));
+    return FALSE;
+  }
+
+  //
+  // Open all SMRAM regions for Host access only
+  //
+  Smram |= (SMM_WRITE_OPEN | SMM_READ_OPEN);  // Open for Host.
+  Smram &= ~(NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN);  // Not for others.
+
+  //
+  // Write the SMRAM register
+  //
+  QncHsmmcWrite (Smram);
+
+  return TRUE;
+}
+
+/**
+  This routine is the chipset code that accepts a request to "close" a region of SMRAM.
+  The region could be legacy AB or TSEG near top of physical memory.
+  The use of "close" means that the memory is only visible from SMM agents,
+  not from BS or RT code.
+
+  @retval FALSE  Cannot open a locked SMRAM region
+  @retval TRUE   Success to open SMRAM region.
+**/
+BOOLEAN
+EFIAPI
+QNCCloseSmramRegion (
+  VOID
+  )
+{
+  UINT32                    Smram;
+
+  // Read the SMRAM register.
+  Smram = QncHsmmcRead ();
+
+  //
+  //  Is the platform locked?
+  //
+  if(Smram & SMM_LOCKED) {
+    // Cannot Open a locked region
+    DEBUG ((EFI_D_WARN, "Cannot close a locked SMRAM region\n"));
+    return FALSE;
+  }
+
+  Smram &= (~(SMM_WRITE_OPEN | SMM_READ_OPEN | NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN));
+
+  QncHsmmcWrite (Smram);
+
+  return TRUE;
+}
+
+/**
+  This routine is the chipset code that accepts a request to "lock" SMRAM.
+  The region could be legacy AB or TSEG near top of physical memory.
+  The use of "lock" means that the memory can no longer be opened
+  to BS state.
+**/
+VOID
+EFIAPI
+QNCLockSmramRegion (
+  VOID
+  )
+{
+  UINT32                    Smram;
+
+  // Read the SMRAM register.
+  Smram = QncHsmmcRead ();
+  if(Smram & SMM_LOCKED) {
+    DEBUG ((EFI_D_WARN, "SMRAM region already locked!\n"));
+  }
+  Smram |= SMM_LOCKED;
+
+  QncHsmmcWrite (Smram);
+
+  return;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf
new file mode 100644
index 0000000000..5383580f3b
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf
@@ -0,0 +1,44 @@
+## @file
+# Component description file for Intel QNC SMM Library.
+#
+# QNC SMM Library that layers on top of the I/O Library to directly
+# access SMM power management registers.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = QNCSmmLib
+  FILE_GUID                      = 8A9A62F5-758B-4965-A28B-0AAC292FBD89
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = SmmLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  QNCSmmLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  PcdLib
+  IoLib
+  DebugLib
+  QNCAccessLib
+
+[Pcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationData
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c
new file mode 100644
index 0000000000..d730f62ce0
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c
@@ -0,0 +1,379 @@
+/** @file
+System reset Library Services.  This library class provides a set of
+methods to reset whole system with manipulate QNC.
+
+Copyright (c) 2013-2019 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <IntelQNCBase.h>
+#include <QNCAccess.h>
+
+#include <Uefi/UefiBaseType.h>
+
+#include <Library/ResetSystemLib.h>
+#include <Library/BaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CpuLib.h>
+#include <Library/QNCAccessLib.h>
+
+//
+// Amount of time (seconds) before RTC alarm fires
+// This must be < BCD_BASE
+//
+#define PLATFORM_WAKE_SECONDS_BUFFER 0x06
+
+//
+// RTC 'seconds' above which we will not read to avoid potential rollover
+//
+#define PLATFORM_RTC_ROLLOVER_LIMIT 0x47
+
+//
+// BCD is base 10
+//
+#define BCD_BASE 0x0A
+
+#define PCAT_RTC_ADDRESS_REGISTER 0x70
+#define PCAT_RTC_DATA_REGISTER    0x71
+
+//
+// Dallas DS12C887 Real Time Clock
+//
+#define RTC_ADDRESS_SECONDS           0   // R/W  Range 0..59
+#define RTC_ADDRESS_SECONDS_ALARM     1   // R/W  Range 0..59
+#define RTC_ADDRESS_MINUTES           2   // R/W  Range 0..59
+#define RTC_ADDRESS_MINUTES_ALARM     3   // R/W  Range 0..59
+#define RTC_ADDRESS_HOURS             4   // R/W  Range 1..12 or 0..23 Bit 7 is AM/PM
+#define RTC_ADDRESS_HOURS_ALARM       5   // R/W  Range 1..12 or 0..23 Bit 7 is AM/PM
+#define RTC_ADDRESS_DAY_OF_THE_WEEK   6   // R/W  Range 1..7
+#define RTC_ADDRESS_DAY_OF_THE_MONTH  7   // R/W  Range 1..31
+#define RTC_ADDRESS_MONTH             8   // R/W  Range 1..12
+#define RTC_ADDRESS_YEAR              9   // R/W  Range 0..99
+#define RTC_ADDRESS_REGISTER_A        10  // R/W[0..6]  R0[7]
+#define RTC_ADDRESS_REGISTER_B        11  // R/W
+#define RTC_ADDRESS_REGISTER_C        12  // RO
+#define RTC_ADDRESS_REGISTER_D        13  // RO
+#define RTC_ADDRESS_CENTURY           50  // R/W  Range 19..20 Bit 8 is R/W
+
+/**
+  Wait for an RTC update to happen
+
+**/
+VOID
+EFIAPI
+WaitForRTCUpdate (
+VOID
+)
+{
+  UINT8   Data8;
+
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
+  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
+  if ((Data8 & BIT7) == BIT7) {
+    while ((Data8 & BIT7) == BIT7) {
+      IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
+      Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
+    }
+
+  } else {
+    while ((Data8 & BIT7) == 0) {
+      IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
+      Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
+    }
+
+    while ((Data8 & BIT7) == BIT7) {
+      IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
+      Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
+    }
+  }
+}
+
+/**
+  Calling this function causes a system-wide reset. This sets
+  all circuitry within the system to its initial state. This type of reset
+  is asynchronous to system operation and operates without regard to
+  cycle boundaries.
+
+  System reset should not return, if it returns, it means the system does
+  not support cold reset.
+**/
+VOID
+EFIAPI
+ResetCold (
+VOID
+)
+{
+  //
+  // Reference to QuarkNcSocId BWG
+  // Setting bit 1 will generate a warm reset, driving only RSTRDY# low
+  //
+  IoWrite8 (RST_CNT, B_RST_CNT_COLD_RST);
+}
+
+/**
+  Calling this function causes a system-wide initialization. The processors
+  are set to their initial state, and pending cycles are not corrupted.
+
+  System reset should not return, if it returns, it means the system does
+  not support warm reset.
+**/
+VOID
+EFIAPI
+ResetWarm (
+VOID
+)
+{
+  //
+  // Reference to QuarkNcSocId BWG
+  // Setting bit 1 will generate a warm reset, driving only RSTRDY# low
+  //
+  IoWrite8 (RST_CNT, B_RST_CNT_WARM_RST);
+}
+
+/**
+  Calling this function causes the system to enter a power state equivalent
+  to the ACPI G2/S5 or G3 states.
+
+  System shutdown should not return, if it returns, it means the system does
+  not support shut down reset.
+**/
+VOID
+EFIAPI
+ResetShutdown (
+VOID
+)
+{
+  //
+  // Reference to QuarkNcSocId BWG
+  //  Disable RTC Alarm :  (RTC Enable at PM1BLK + 02h[10]))
+  //
+  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0);
+
+  //
+  // Firstly, GPE0_EN should be disabled to
+  // avoid any GPI waking up the system from S5
+  //
+  IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0);
+
+  //
+  // Reference to QuarkNcSocId BWG
+  //  Disable Resume Well GPIO :  (GPIO bits in GPIOBASE + 34h[8:0])
+  //
+  IoWrite32 (PcdGet16 (PcdGbaIoBaseAddress) + R_QNC_GPIO_RGGPE_RESUME_WELL, 0);
+
+  //
+  // No power button status bit to clear for our platform, go to next step.
+  //
+
+  //
+  // Finally, transform system into S5 sleep state
+  //
+  IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, 0xffffc3ff, B_QNC_PM1BLK_PM1C_SLPEN | V_S5);
+}
+
+/**
+  Calling this function causes the system to enter a power state for capsule
+  update.
+
+  Reset update should not return, if it returns, it means the system does
+  not support capsule update.
+
+**/
+VOID
+EFIAPI
+EnterS3WithImmediateWake (
+VOID
+)
+{
+  UINT8     Data8;
+  UINT16    Data16;
+  UINT32    Data32;
+  UINTN     Eflags;
+  UINTN     RegCr0;
+  EFI_TIME  EfiTime;
+  UINT32    SmiEnSave;
+
+  Eflags  = AsmReadEflags ();
+  if ( (Eflags & 0x200) ) {
+     DisableInterrupts ();
+  }
+
+  //
+  //  Write all cache data to memory because processor will lost power
+  //
+  AsmWbinvd();
+  RegCr0 = AsmReadCr0();
+  AsmWriteCr0 (RegCr0 | 0x060000000);
+
+  SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));
+
+  //
+  // Pogram RTC alarm for immediate WAKE
+  //
+
+  //
+  // Disable SMI sources
+  //
+  IoWrite16 (PcdGet16 (PcdGpe0blkIoBaseAddress) + R_QNC_GPE0BLK_SMIE, 0);
+
+  //
+  // Disable RTC alarm interrupt
+  //
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
+  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
+  IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 & ~BIT5));
+
+  //
+  // Clear RTC alarm if already set
+  //
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
+  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);              // Read clears alarm status
+
+  //
+  // Disable all WAKE events
+  //
+  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, B_QNC_PM1BLK_PM1E_PWAKED);
+
+  //
+  // Clear all WAKE status bits
+  //
+  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S, B_QNC_PM1BLK_PM1S_ALL);
+
+  //
+  // Avoid RTC rollover
+  //
+  do {
+    WaitForRTCUpdate();
+    IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
+    EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
+  } while (EfiTime.Second > PLATFORM_RTC_ROLLOVER_LIMIT);
+
+  //
+  // Read RTC time
+  //
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS);
+  EfiTime.Hour = IoRead8 (PCAT_RTC_DATA_REGISTER);
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES);
+  EfiTime.Minute = IoRead8 (PCAT_RTC_DATA_REGISTER);
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
+  EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
+
+  //
+  // Set RTC alarm
+  //
+
+  //
+  // Add PLATFORM_WAKE_SECONDS_BUFFER to current EfiTime.Second
+  // The maths is to allow for the fact we are adding to a BCD number and require the answer to be BCD (EfiTime.Second)
+  //
+  if ((BCD_BASE - (EfiTime.Second & 0x0F)) <= PLATFORM_WAKE_SECONDS_BUFFER) {
+    Data8 = (((EfiTime.Second & 0xF0) + 0x10) + (PLATFORM_WAKE_SECONDS_BUFFER - (BCD_BASE - (EfiTime.Second & 0x0F))));
+  } else {
+    Data8 = EfiTime.Second + PLATFORM_WAKE_SECONDS_BUFFER;
+  }
+
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS_ALARM);
+  IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Hour);
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES_ALARM);
+  IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Minute);
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS_ALARM);
+  IoWrite8 (PCAT_RTC_DATA_REGISTER, Data8);
+
+  //
+  // Enable RTC alarm interrupt
+  //
+  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
+  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
+  IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 | BIT5));
+
+  //
+  // Enable RTC alarm as WAKE event
+  //
+  Data16 = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);
+  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, (Data16 | B_QNC_PM1BLK_PM1E_RTC));
+
+  //
+  // Enter S3
+  //
+  Data32 = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+  Data32  = (UINT32) ((Data32 & 0xffffc3fe) | V_S3 | B_QNC_PM1BLK_PM1C_SCIEN);
+  IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
+  Data32 = Data32 | B_QNC_PM1BLK_PM1C_SLPEN;
+  IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
+
+  //
+  // Enable Interrupt if it's enabled before
+  //
+  if ( (Eflags & 0x200) ) {
+     EnableInterrupts ();
+  }
+}
+
+/**
+  This function causes a systemwide reset. The exact type of the reset is
+  defined by the EFI_GUID that follows the Null-terminated Unicode string passed
+  into ResetData. If the platform does not recognize the EFI_GUID in ResetData
+  the platform must pick a supported reset type to perform.The platform may
+  optionally log the parameters from any non-normal reset that occurs.
+
+  @param[in]  DataSize   The size, in bytes, of ResetData.
+  @param[in]  ResetData  The data buffer starts with a Null-terminated string,
+                         followed by the EFI_GUID.
+**/
+VOID
+EFIAPI
+ResetPlatformSpecific (
+  IN UINTN   DataSize,
+  IN VOID    *ResetData
+  )
+{
+  ResetCold ();
+}
+
+/**
+  The ResetSystem function resets the entire platform.
+
+  @param[in] ResetType      The type of reset to perform.
+  @param[in] ResetStatus    The status code for the reset.
+  @param[in] DataSize       The size, in bytes, of ResetData.
+  @param[in] ResetData      For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
+                            the data buffer starts with a Null-terminated string, optionally
+                            followed by additional binary data. The string is a description
+                            that the caller may use to further indicate the reason for the
+                            system reset.
+**/
+VOID
+EFIAPI
+ResetSystem (
+  IN EFI_RESET_TYPE               ResetType,
+  IN EFI_STATUS                   ResetStatus,
+  IN UINTN                        DataSize,
+  IN VOID                         *ResetData OPTIONAL
+  )
+{
+  switch (ResetType) {
+  case EfiResetWarm:
+    ResetWarm ();
+    break;
+
+  case EfiResetCold:
+    ResetCold ();
+    break;
+
+  case EfiResetShutdown:
+    ResetShutdown ();
+    return;
+
+  case EfiResetPlatformSpecific:
+    ResetPlatformSpecific (DataSize, ResetData);
+    return;
+
+  default:
+    return;
+  }
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf
new file mode 100644
index 0000000000..b849259b7f
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf
@@ -0,0 +1,46 @@
+## @file
+# Component description file for Intel QuarkNcSocId Reset System Library.
+#
+# Reset System Library implementation that bases on QNC.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = ResetSystemLib
+  FILE_GUID                      = AD33A56E-3AAD-40ac-91B1-FA861E8D9D85
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = ResetSystemLib
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  ResetSystemLib.c
+
+
+[Packages]
+  QuarkSocPkg/QuarkSocPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  PcdLib
+  IoLib
+  BaseLib
+  CpuLib
+  QNCAccessLib
+
+[Pcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h
new file mode 100644
index 0000000000..8968aa8931
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h
@@ -0,0 +1,25 @@
+/** @file
+Common header file shared by all source files.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __COMMON_HEADER_H_
+#define __COMMON_HEADER_H_
+
+
+#include <Uefi.h>
+#include <Base.h>
+
+#include <Library/SmbusLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/QNCAccessLib.h>
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c
new file mode 100644
index 0000000000..319e103cf4
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c
@@ -0,0 +1,797 @@
+/** @file
+Intel QNC SMBUS library implementation built upon I/O library.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+/**
+  Gets Io port base address of Smbus Host Controller.
+
+  This internal function depends on a feature flag named PcdIchSmbusFixedIoPortBaseAddress
+  to retrieve Smbus Io port base. If that feature flag is true, it will get Smbus Io port base
+  address from a preset Pcd entry named PcdIchSmbusIoPortBaseAddress; otherwise, it will always
+  read Pci configuration space to get that value in each Smbus bus transaction.
+
+  @return The Io port base address of Smbus host controller.
+
+**/
+UINTN
+InternalGetSmbusIoPortBaseAddress (
+  VOID
+  )
+{
+  UINTN     IoPortBaseAddress;
+
+  if (FeaturePcdGet (PcdSmbaIoBaseAddressFixed)) {
+    IoPortBaseAddress = (UINTN) PcdGet16 (PcdSmbaIoBaseAddress);
+  } else {
+    IoPortBaseAddress = (UINTN) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) & B_QNC_LPC_SMBUS_BASE_MASK;
+  }
+
+  //
+  // Make sure that the IO port base address has been properly set.
+  //
+  ASSERT (IoPortBaseAddress != 0);
+
+  return IoPortBaseAddress;
+}
+
+
+/**
+  Acquires the ownership of SMBUS.
+
+  This internal function reads the host state register.
+  If the SMBUS is not available, RETURN_TIMEOUT is returned;
+  Otherwise, it performs some basic initializations and returns
+  RETURN_SUCCESS.
+
+  @param  IoPortBaseAddress The Io port base address of Smbus Host controller.
+
+  @retval RETURN_SUCCESS    The SMBUS command was executed successfully.
+  @retval RETURN_TIMEOUT    A timeout occurred while executing the SMBUS command.
+
+**/
+RETURN_STATUS
+InternalSmBusAcquire (
+  UINTN                     IoPortBaseAddress
+  )
+{
+
+  //
+  // Clear host status register and exit.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL, 0);
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, 0);
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD1, 0);
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);
+
+  return RETURN_SUCCESS;
+}
+
+/**
+  Starts the SMBUS transaction and waits until the end.
+
+  This internal function start the SMBUS transaction and waits until the transaction
+  of SMBUS is over by polling the INTR bit of Host status register.
+  If the SMBUS is not available, RETURN_TIMEOUT is returned;
+  Otherwise, it performs some basic initializations and returns
+  RETURN_SUCCESS.
+
+  @param  IoPortBaseAddress   The Io port base address of Smbus Host controller.
+  @param  HostControl         The Host control command to start SMBUS transaction.
+
+  @retval RETURN_SUCCESS      The SMBUS command was executed successfully.
+  @retval RETURN_CRC_ERROR    The checksum is not correct (PEC is incorrect).
+  @retval RETURN_DEVICE_ERROR The request was not completed because a failure reflected
+                              in the Host Status Register bit.  Device errors are
+                              a result of a transaction collision, illegal command field,
+                              unclaimed cycle (host initiated), or bus errors (collisions).
+
+**/
+RETURN_STATUS
+InternalSmBusStart (
+  IN  UINTN                   IoPortBaseAddress,
+  IN  UINT8                   HostControl
+  )
+{
+  UINT8   HostStatus;
+
+  //
+  // Set Host Control Register (Initiate Operation, Interrupt disabled).
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL, HostControl + B_QNC_SMBUS_START);
+
+  do {
+    //
+    // Poll INTR bit of Host Status Register.
+    //
+    HostStatus = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS);
+  } while ((HostStatus & (B_QNC_SMBUS_BYTE_DONE_STS | B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR)) == 0);
+
+  if ((HostStatus & (B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR)) == 0) {
+    return RETURN_SUCCESS;
+  }
+  //
+  // Clear error bits of Host Status Register.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, (B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR));
+
+  return RETURN_DEVICE_ERROR;
+}
+
+/**
+  Executes an SMBUS quick, byte or word command.
+
+  This internal function executes an SMBUS quick, byte or word commond.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+
+  @param  HostControl     The value of Host Control Register to set.
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Value           The byte/word write to the SMBUS.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The byte/word read from the SMBUS.
+
+**/
+UINT16
+InternalSmBusNonBlock (
+  IN  UINT8                     HostControl,
+  IN  UINTN                     SmBusAddress,
+  IN  UINT16                    Value,
+  OUT RETURN_STATUS             *Status
+  )
+{
+  RETURN_STATUS                 ReturnStatus;
+  UINTN                         IoPortBaseAddress;
+
+  IoPortBaseAddress = InternalGetSmbusIoPortBaseAddress ();
+
+  //
+  // Try to acquire the ownership of QNC SMBUS.
+  //
+  ReturnStatus = InternalSmBusAcquire (IoPortBaseAddress);
+  if (RETURN_ERROR (ReturnStatus)) {
+    goto Done;
+  }
+
+  //
+  // Set Host Commond Register.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCMD, (UINT8) SMBUS_LIB_COMMAND (SmBusAddress));
+  //
+  // Write value to Host Data 0 and Host Data 1 Registers.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, (UINT8) Value);
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD1, (UINT8) (Value >> 8));
+
+
+  //
+  // Set SMBUS slave address for the device to send/receive from.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_TSA, (UINT8) SmBusAddress);
+  //
+  // Start the SMBUS transaction and wait for the end.
+  //
+  ReturnStatus = InternalSmBusStart (IoPortBaseAddress, HostControl);
+  //
+  // Read value from Host Data 0 and Host Data 1 Registers.
+  //
+  Value = (UINT16)(IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD1) << 8);
+  Value = (UINT16)(Value | IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD0));
+
+  //
+  // Clear Host Status Register and Auxiliary Status Register.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);
+
+Done:
+  if (Status != NULL) {
+    *Status = ReturnStatus;
+  }
+
+  return Value;
+}
+
+/**
+  Executes an SMBUS quick read command.
+
+  Executes an SMBUS quick read command on the SMBUS device specified by SmBusAddress.
+  Only the SMBUS slave address field of SmBusAddress is required.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If PEC is set in SmBusAddress, then ASSERT().
+  If Command in SmBusAddress is not zero, then ASSERT().
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+**/
+VOID
+EFIAPI
+SmBusQuickRead (
+  IN  UINTN                     SmBusAddress,
+  OUT RETURN_STATUS             *Status       OPTIONAL
+  )
+{
+  ASSERT (!SMBUS_LIB_PEC (SmBusAddress));
+  ASSERT (SMBUS_LIB_COMMAND (SmBusAddress)   == 0);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress)    == 0);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  InternalSmBusNonBlock (
+    V_QNC_SMBUS_HCTL_CMD_QUICK,
+    SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
+    0,
+    Status
+    );
+
+}
+
+/**
+  Executes an SMBUS quick write command.
+
+  Executes an SMBUS quick write command on the SMBUS device specified by SmBusAddress.
+  Only the SMBUS slave address field of SmBusAddress is required.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If PEC is set in SmBusAddress, then ASSERT().
+  If Command in SmBusAddress is not zero, then ASSERT().
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+**/
+VOID
+EFIAPI
+SmBusQuickWrite (
+  IN  UINTN                     SmBusAddress,
+  OUT RETURN_STATUS             *Status       OPTIONAL
+  )
+{
+  ASSERT (!SMBUS_LIB_PEC (SmBusAddress));
+  ASSERT (SMBUS_LIB_COMMAND (SmBusAddress)   == 0);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress)    == 0);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  InternalSmBusNonBlock (
+    V_QNC_SMBUS_HCTL_CMD_QUICK,
+    SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE,
+    0,
+    Status
+    );
+
+}
+
+/**
+  Executes an SMBUS receive byte command.
+
+  Executes an SMBUS receive byte command on the SMBUS device specified by SmBusAddress.
+  Only the SMBUS slave address field of SmBusAddress is required.
+  The byte received from the SMBUS is returned.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If Command in SmBusAddress is not zero, then ASSERT().
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The byte received from the SMBUS.
+
+**/
+UINT8
+EFIAPI
+SmBusReceiveByte (
+  IN  UINTN          SmBusAddress,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (SMBUS_LIB_COMMAND (SmBusAddress)   == 0);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress)    == 0);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  return (UINT8) InternalSmBusNonBlock (
+                   V_QNC_SMBUS_HCTL_CMD_BYTE,
+                   SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
+                   0,
+                   Status
+                   );
+
+}
+
+/**
+  Executes an SMBUS send byte command.
+
+  Executes an SMBUS send byte command on the SMBUS device specified by SmBusAddress.
+  The byte specified by Value is sent.
+  Only the SMBUS slave address field of SmBusAddress is required.  Value is returned.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If Command in SmBusAddress is not zero, then ASSERT().
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Value           The 8-bit value to send.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The parameter of Value.
+
+**/
+UINT8
+EFIAPI
+SmBusSendByte (
+  IN  UINTN          SmBusAddress,
+  IN  UINT8          Value,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (SMBUS_LIB_COMMAND (SmBusAddress)   == 0);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress)    == 0);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  return (UINT8) InternalSmBusNonBlock (
+                   V_QNC_SMBUS_HCTL_CMD_BYTE,
+                   SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE,
+                   Value,
+                   Status
+                   );
+
+}
+
+/**
+  Executes an SMBUS read data byte command.
+
+  Executes an SMBUS read data byte command on the SMBUS device specified by SmBusAddress.
+  Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
+  The 8-bit value read from the SMBUS is returned.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The byte read from the SMBUS.
+
+**/
+UINT8
+EFIAPI
+SmBusReadDataByte (
+  IN  UINTN          SmBusAddress,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress)    == 0);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  return (UINT8) InternalSmBusNonBlock (
+                   V_QNC_SMBUS_HCTL_CMD_BYTE_DATA,
+                   SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
+                   0,
+                   Status
+                   );
+}
+
+/**
+  Executes an SMBUS write data byte command.
+
+  Executes an SMBUS write data byte command on the SMBUS device specified by SmBusAddress.
+  The 8-bit value specified by Value is written.
+  Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
+  Value is returned.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Value           The 8-bit value to write.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The parameter of Value.
+
+**/
+UINT8
+EFIAPI
+SmBusWriteDataByte (
+  IN  UINTN          SmBusAddress,
+  IN  UINT8          Value,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress)    == 0);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  return (UINT8) InternalSmBusNonBlock (
+                   V_QNC_SMBUS_HCTL_CMD_BYTE_DATA,
+                   SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE,
+                   Value,
+                   Status
+                   );
+}
+
+/**
+  Executes an SMBUS read data word command.
+
+  Executes an SMBUS read data word command on the SMBUS device specified by SmBusAddress.
+  Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
+  The 16-bit value read from the SMBUS is returned.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The byte read from the SMBUS.
+
+**/
+UINT16
+EFIAPI
+SmBusReadDataWord (
+  IN  UINTN          SmBusAddress,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress)    == 2);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  return InternalSmBusNonBlock (
+           V_QNC_SMBUS_HCTL_CMD_WORD_DATA,
+           SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
+           0,
+           Status
+           );
+
+}
+
+/**
+  Executes an SMBUS write data word command.
+
+  Executes an SMBUS write data word command on the SMBUS device specified by SmBusAddress.
+  The 16-bit value specified by Value is written.
+  Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
+  Value is returned.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Value           The 16-bit value to write.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The parameter of Value.
+
+**/
+UINT16
+EFIAPI
+SmBusWriteDataWord (
+  IN  UINTN          SmBusAddress,
+  IN  UINT16         Value,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress)    == 2);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  return InternalSmBusNonBlock (
+         V_QNC_SMBUS_HCTL_CMD_WORD_DATA,
+         SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE,
+         Value,
+         Status
+         );
+}
+
+/**
+  Executes an SMBUS process call command.
+
+  Executes an SMBUS process call command on the SMBUS device specified by SmBusAddress.
+  The 16-bit value specified by Value is written.
+  Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
+  The 16-bit value returned by the process call command is returned.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Value           The 16-bit value to write.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The 16-bit value returned by the process call command.
+
+**/
+UINT16
+EFIAPI
+SmBusProcessCall (
+  IN  UINTN          SmBusAddress,
+  IN  UINT16         Value,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress)    == 0);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  return InternalSmBusNonBlock (
+           V_QNC_SMBUS_HCTL_CMD_PROCESS_CALL,
+           SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE,
+           Value,
+           Status
+           );
+
+}
+
+/**
+  Executes an SMBUS block command.
+
+  Executes an SMBUS block read, block write and block write-block read command
+  on the SMBUS device specified by SmBusAddress.
+  Bytes are read from the SMBUS and stored in Buffer.
+  The number of bytes read is returned, and will never return a value larger than 32-bytes.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+  SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes.
+
+  @param  HostControl     The value of Host Control Register to set.
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  WriteBuffer     Pointer to the buffer of bytes to write to the SMBUS.
+  @param  ReadBuffer      Pointer to the buffer of bytes to read from the SMBUS.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The number of bytes read from the SMBUS.
+
+**/
+UINTN
+InternalSmBusBlock (
+  IN  UINT8                     HostControl,
+  IN  UINTN                     SmBusAddress,
+  IN  UINT8                     *WriteBuffer,
+  OUT UINT8                     *ReadBuffer,
+  OUT RETURN_STATUS             *Status
+  )
+{
+  RETURN_STATUS                 ReturnStatus;
+  UINTN                         Index;
+  UINTN                         BytesCount;
+  UINTN                         IoPortBaseAddress;
+
+  IoPortBaseAddress = InternalGetSmbusIoPortBaseAddress ();
+
+  BytesCount = SMBUS_LIB_LENGTH (SmBusAddress);
+
+  //
+  // Try to acquire the ownership of ICH SMBUS.
+  //
+  ReturnStatus = InternalSmBusAcquire (IoPortBaseAddress);
+  if (RETURN_ERROR (ReturnStatus)) {
+    goto Done;
+  }
+
+  //
+  // Set Host Command Register.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCMD, (UINT8) SMBUS_LIB_COMMAND (SmBusAddress));
+
+  //
+  // Clear byte pointer of 32-byte buffer.
+  //
+  IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL);
+
+  if (WriteBuffer != NULL) {
+    //
+    // Write the number of block to Host Block Data Byte Register.
+    //
+    IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, (UINT8) BytesCount);
+    //
+    // Write data block to Host Block Data Register.
+    //
+    for (Index = 0; Index < BytesCount; Index++) {
+      IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HBD + (UINT8)Index, WriteBuffer[Index]);
+    }
+  }
+  //
+  // Set SMBUS slave address for the device to send/receive from.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_TSA, (UINT8) SmBusAddress);
+  //
+  // Start the SMBUS transaction and wait for the end.
+  //
+  ReturnStatus = InternalSmBusStart (IoPortBaseAddress, HostControl);
+  if (RETURN_ERROR (ReturnStatus)) {
+    goto Done;
+  }
+
+  if (ReadBuffer != NULL) {
+    //
+    // Read the number of block from host block data byte register.
+    //
+    BytesCount = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD0);
+    //
+    // Write data block from Host Block Data Register.
+    //
+    for (Index = 0; Index < BytesCount; Index++) {
+      ReadBuffer[Index] = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HBD + (UINT8)Index);
+    }
+  }
+
+Done:
+  //
+  // Clear Host Status Register and Auxiliary Status Register.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);
+
+  if (Status != NULL) {
+    *Status = ReturnStatus;
+  }
+
+  return BytesCount;
+}
+
+/**
+  Executes an SMBUS read block command.
+
+  Executes an SMBUS read block command on the SMBUS device specified by SmBusAddress.
+  Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
+  Bytes are read from the SMBUS and stored in Buffer.
+  The number of bytes read is returned, and will never return a value larger than 32-bytes.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+  SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes.
+  If Length in SmBusAddress is not zero, then ASSERT().
+  If Buffer is NULL, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Buffer          Pointer to the buffer to store the bytes read from the SMBUS.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The number of bytes read.
+
+**/
+UINTN
+EFIAPI
+SmBusReadBlock (
+  IN  UINTN          SmBusAddress,
+  OUT VOID           *Buffer,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (Buffer != NULL);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  return InternalSmBusBlock (
+           V_QNC_SMBUS_HCTL_CMD_BLOCK,
+           SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
+           NULL,
+           Buffer,
+           Status
+           );
+}
+
+/**
+  Executes an SMBUS write block command.
+
+  Executes an SMBUS write block command on the SMBUS device specified by SmBusAddress.
+  The SMBUS slave address, SMBUS command, and SMBUS length fields of SmBusAddress are required.
+  Bytes are written to the SMBUS from Buffer.
+  The number of bytes written is returned, and will never return a value larger than 32-bytes.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  If Length in SmBusAddress is zero or greater than 32, then ASSERT().
+  If Buffer is NULL, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress    Address that encodes the SMBUS Slave Address,
+                          SMBUS Command, SMBUS Data Length, and PEC.
+  @param  Buffer          Pointer to the buffer to store the bytes read from the SMBUS.
+  @param  Status          Return status for the executed command.
+                          This is an optional parameter and may be NULL.
+
+  @return The number of bytes written.
+
+**/
+UINTN
+EFIAPI
+SmBusWriteBlock (
+  IN  UINTN          SmBusAddress,
+  OUT VOID           *Buffer,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (Buffer != NULL);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+
+  return InternalSmBusBlock (
+           V_QNC_SMBUS_HCTL_CMD_BLOCK,
+           SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE,
+           Buffer,
+           NULL,
+           Status
+           );
+}
+
+/**
+  Executes an SMBUS block process call command.
+
+  Executes an SMBUS block process call command on the SMBUS device specified by SmBusAddress.
+  The SMBUS slave address, SMBUS command, and SMBUS length fields of SmBusAddress are required.
+  Bytes are written to the SMBUS from WriteBuffer.  Bytes are then read from the SMBUS into ReadBuffer.
+  If Status is not NULL, then the status of the executed command is returned in Status.
+  It is the caller's responsibility to make sure ReadBuffer is large enough for the total number of bytes read.
+  SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes.
+  If Length in SmBusAddress is zero or greater than 32, then ASSERT().
+  If WriteBuffer is NULL, then ASSERT().
+  If ReadBuffer is NULL, then ASSERT().
+  If any reserved bits of SmBusAddress are set, then ASSERT().
+
+  @param  SmBusAddress  Address that encodes the SMBUS Slave Address,
+                        SMBUS Command, SMBUS Data Length, and PEC.
+  @param  WriteBuffer   Pointer to the buffer of bytes to write to the SMBUS.
+  @param  ReadBuffer    Pointer to the buffer of bytes to read from the SMBUS.
+  @param  Status        Return status for the executed command.
+                        This is an optional parameter and may be NULL.
+                        RETURN_TIMEOUT A timeout occurred while executing the SMBUS command.
+                        RETURN_DEVICE_ERROR  The request was not completed because a failure
+                        reflected in the Host Status Register bit.  Device errors are a result
+                        of a transaction collision, illegal command field, unclaimed cycle
+                        (host initiated), or bus errors (collisions).
+                        RETURN_CRC_ERROR  The checksum is not correct (PEC is incorrect)
+                        RETURN_UNSUPPORTED  The SMBus operation is not supported.
+
+  @return The number of bytes written.
+
+**/
+UINTN
+EFIAPI
+SmBusBlockProcessCall (
+  IN  UINTN          SmBusAddress,
+  IN  VOID           *WriteBuffer,
+  OUT VOID           *ReadBuffer,
+  OUT RETURN_STATUS  *Status        OPTIONAL
+  )
+{
+  ASSERT (WriteBuffer != NULL);
+  ASSERT (ReadBuffer  != NULL);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1);
+  ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32);
+  ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
+  if (Status != NULL) {
+    *Status = RETURN_UNSUPPORTED;
+  }
+  return 0;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf
new file mode 100644
index 0000000000..6cf4c569ed
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf
@@ -0,0 +1,47 @@
+## @file
+# Component description file for Intel QNC Smbus Library.
+#
+# SMBUS Library that layers on top of the I/O Library to directly
+# access a standard SMBUS host controller.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SmbusLib
+  FILE_GUID                      = 6F2F36B3-936B-4eb2-83C7-2987B4F9D4EB
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = SmbusLib
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  SmbusLib.c
+  CommonHeader.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  PcdLib
+  DebugLib
+  PciLib
+  IoLib
+  QNCAccessLib
+
+[FeaturePcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed
+
+[Pcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
new file mode 100644
index 0000000000..f9a7af0449
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
@@ -0,0 +1,446 @@
+/** @file
+The Quark CPU specific programming for PiSmmCpuDxeSmm module.
+
+Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include <Library/SmmCpuFeaturesLib.h>
+#include <Register/SmramSaveStateMap.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/QNCAccessLib.h>
+
+#define  EFI_MSR_SMRR_PHYS_MASK_VALID          BIT11
+#define  EFI_MSR_SMRR_MASK                     0xFFFFF000
+
+/**
+  Called during the very first SMI into System Management Mode to initialize
+  CPU features, including SMBASE, for the currently executing CPU.  Since this
+  is the first SMI, the SMRAM Save State Map is at the default address of
+  SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET.  The currently executing
+  CPU is specified by CpuIndex and CpuIndex can be used to access information
+  about the currently executing CPU in the ProcessorInfo array and the
+  HotPlugCpuData data structure.
+
+  @param[in] CpuIndex        The index of the CPU to initialize.  The value
+                             must be between 0 and the NumberOfCpus field in
+                             the System Management System Table (SMST).
+  @param[in] IsMonarch       TRUE if the CpuIndex is the index of the CPU that
+                             was elected as monarch during System Management
+                             Mode initialization.
+                             FALSE if the CpuIndex is not the index of the CPU
+                             that was elected as monarch during System
+                             Management Mode initialization.
+  @param[in] ProcessorInfo   Pointer to an array of EFI_PROCESSOR_INFORMATION
+                             structures.  ProcessorInfo[CpuIndex] contains the
+                             information for the currently executing CPU.
+  @param[in] CpuHotPlugData  Pointer to the CPU_HOT_PLUG_DATA structure that
+                             contains the ApidId and SmBase arrays.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesInitializeProcessor (
+  IN UINTN                      CpuIndex,
+  IN BOOLEAN                    IsMonarch,
+  IN EFI_PROCESSOR_INFORMATION  *ProcessorInfo,
+  IN CPU_HOT_PLUG_DATA          *CpuHotPlugData
+  )
+{
+  SMRAM_SAVE_STATE_MAP  *CpuState;
+
+  //
+  // Configure SMBASE.
+  //
+  CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
+  CpuState->x86.SMBASE = CpuHotPlugData->SmBase[CpuIndex];
+
+  //
+  // SMRR size cannot be less than 4-KBytes
+  // SMRR size must be of length 2^n
+  // SMRR base alignment cannot be less than SMRR length
+  //
+  if ((CpuHotPlugData->SmrrSize < SIZE_4KB) ||
+      (CpuHotPlugData->SmrrSize != GetPowerOfTwo32 (CpuHotPlugData->SmrrSize)) ||
+      ((CpuHotPlugData->SmrrBase & ~(CpuHotPlugData->SmrrSize - 1)) != CpuHotPlugData->SmrrBase)) {
+    DEBUG ((EFI_D_ERROR, "SMM Base/Size does not meet alignment/size requirement!\n"));
+    CpuDeadLoop ();
+  }
+
+  //
+  // Use QNC to initialize SMRR on Quark
+  //
+  QNCPortWrite(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSBASE, CpuHotPlugData->SmrrBase);
+  QNCPortWrite(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK, (~(CpuHotPlugData->SmrrSize - 1) & EFI_MSR_SMRR_MASK) | EFI_MSR_SMRR_PHYS_MASK_VALID);
+}
+
+/**
+  This function updates the SMRAM save state on the currently executing CPU
+  to resume execution at a specific address after an RSM instruction.  This
+  function must evaluate the SMRAM save state to determine the execution mode
+  the RSM instruction resumes and update the resume execution address with
+  either NewInstructionPointer32 or NewInstructionPoint.  The auto HALT restart
+  flag in the SMRAM save state must always be cleared.  This function returns
+  the value of the instruction pointer from the SMRAM save state that was
+  replaced.  If this function returns 0, then the SMRAM save state was not
+  modified.
+
+  This function is called during the very first SMI on each CPU after
+  SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
+  to signal that the SMBASE of each CPU has been updated before the default
+  SMBASE address is used for the first SMI to the next CPU.
+
+  @param[in] CpuIndex                 The index of the CPU to hook.  The value
+                                      must be between 0 and the NumberOfCpus
+                                      field in the System Management System Table
+                                      (SMST).
+  @param[in] CpuState                 Pointer to SMRAM Save State Map for the
+                                      currently executing CPU.
+  @param[in] NewInstructionPointer32  Instruction pointer to use if resuming to
+                                      32-bit execution mode from 64-bit SMM.
+  @param[in] NewInstructionPointer    Instruction pointer to use if resuming to
+                                      same execution mode as SMM.
+
+  @retval 0    This function did modify the SMRAM save state.
+  @retval > 0  The original instruction pointer value from the SMRAM save state
+               before it was replaced.
+**/
+UINT64
+EFIAPI
+SmmCpuFeaturesHookReturnFromSmm (
+  IN UINTN                 CpuIndex,
+  IN SMRAM_SAVE_STATE_MAP  *CpuState,
+  IN UINT64                NewInstructionPointer32,
+  IN UINT64                NewInstructionPointer
+  )
+{
+  return 0;
+}
+
+/**
+  Hook point in normal execution mode that allows the one CPU that was elected
+  as monarch during System Management Mode initialization to perform additional
+  initialization actions immediately after all of the CPUs have processed their
+  first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
+  into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesSmmRelocationComplete (
+  VOID
+  )
+{
+}
+
+/**
+  Return the size, in bytes, of a custom SMI Handler in bytes.  If 0 is
+  returned, then a custom SMI handler is not provided by this library,
+  and the default SMI handler must be used.
+
+  @retval 0    Use the default SMI handler.
+  @retval > 0  Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
+               The caller is required to allocate enough SMRAM for each CPU to
+               support the size of the custom SMI handler.
+**/
+UINTN
+EFIAPI
+SmmCpuFeaturesGetSmiHandlerSize (
+  VOID
+  )
+{
+  return 0;
+}
+
+/**
+  Install a custom SMI handler for the CPU specified by CpuIndex.  This function
+  is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
+  than zero and is called by the CPU that was elected as monarch during System
+  Management Mode initialization.
+
+  @param[in] CpuIndex   The index of the CPU to install the custom SMI handler.
+                        The value must be between 0 and the NumberOfCpus field
+                        in the System Management System Table (SMST).
+  @param[in] SmBase     The SMBASE address for the CPU specified by CpuIndex.
+  @param[in] SmiStack   The stack to use when an SMI is processed by the
+                        the CPU specified by CpuIndex.
+  @param[in] StackSize  The size, in bytes, if the stack used when an SMI is
+                        processed by the CPU specified by CpuIndex.
+  @param[in] GdtBase    The base address of the GDT to use when an SMI is
+                        processed by the CPU specified by CpuIndex.
+  @param[in] GdtSize    The size, in bytes, of the GDT used when an SMI is
+                        processed by the CPU specified by CpuIndex.
+  @param[in] IdtBase    The base address of the IDT to use when an SMI is
+                        processed by the CPU specified by CpuIndex.
+  @param[in] IdtSize    The size, in bytes, of the IDT used when an SMI is
+                        processed by the CPU specified by CpuIndex.
+  @param[in] Cr3        The base address of the page tables to use when an SMI
+                        is processed by the CPU specified by CpuIndex.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesInstallSmiHandler (
+  IN UINTN   CpuIndex,
+  IN UINT32  SmBase,
+  IN VOID    *SmiStack,
+  IN UINTN   StackSize,
+  IN UINTN   GdtBase,
+  IN UINTN   GdtSize,
+  IN UINTN   IdtBase,
+  IN UINTN   IdtSize,
+  IN UINT32  Cr3
+  )
+{
+}
+
+/**
+  Determines if MTRR registers must be configured to set SMRAM cache-ability
+  when executing in System Management Mode.
+
+  @retval TRUE   MTRR registers must be configured to set SMRAM cache-ability.
+  @retval FALSE  MTRR registers do not need to be configured to set SMRAM
+                   cache-ability.
+**/
+BOOLEAN
+EFIAPI
+SmmCpuFeaturesNeedConfigureMtrrs (
+  VOID
+  )
+{
+  return TRUE;
+}
+
+/**
+  Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
+  returns TRUE.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesDisableSmrr (
+  VOID
+  )
+{
+  //
+  // Use QNC to disable SMRR on Quark
+  //
+  QNCPortWrite(
+    QUARK_NC_HOST_BRIDGE_SB_PORT_ID,
+    QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK,
+    QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK) & ~EFI_MSR_SMRR_PHYS_MASK_VALID
+    );
+}
+
+/**
+  Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
+  returns TRUE.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesReenableSmrr (
+  VOID
+  )
+{
+  //
+  // Use QNC to enable SMRR on Quark
+  //
+  QNCPortWrite(
+    QUARK_NC_HOST_BRIDGE_SB_PORT_ID,
+    QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK,
+    QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK) | EFI_MSR_SMRR_PHYS_MASK_VALID
+    );
+}
+
+/**
+  Processor specific hook point each time a CPU enters System Management Mode.
+
+  @param[in] CpuIndex  The index of the CPU that has entered SMM.  The value
+                       must be between 0 and the NumberOfCpus field in the
+                       System Management System Table (SMST).
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesRendezvousEntry (
+  IN UINTN  CpuIndex
+  )
+{
+}
+
+/**
+  Processor specific hook point each time a CPU exits System Management Mode.
+
+  @param[in] CpuIndex  The index of the CPU that is exiting SMM.  The value must
+                       be between 0 and the NumberOfCpus field in the System
+                       Management System Table (SMST).
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesRendezvousExit (
+  IN UINTN  CpuIndex
+  )
+{
+}
+
+/**
+  Check to see if an SMM register is supported by a specified CPU.
+
+  @param[in] CpuIndex  The index of the CPU to check for SMM register support.
+                       The value must be between 0 and the NumberOfCpus field
+                       in the System Management System Table (SMST).
+  @param[in] RegName   Identifies the SMM register to check for support.
+
+  @retval TRUE   The SMM register specified by RegName is supported by the CPU
+                 specified by CpuIndex.
+  @retval FALSE  The SMM register specified by RegName is not supported by the
+                 CPU specified by CpuIndex.
+**/
+BOOLEAN
+EFIAPI
+SmmCpuFeaturesIsSmmRegisterSupported (
+  IN UINTN         CpuIndex,
+  IN SMM_REG_NAME  RegName
+  )
+{
+  return FALSE;
+}
+
+/**
+  Returns the current value of the SMM register for the specified CPU.
+  If the SMM register is not supported, then 0 is returned.
+
+  @param[in] CpuIndex  The index of the CPU to read the SMM register.  The
+                       value must be between 0 and the NumberOfCpus field in
+                       the System Management System Table (SMST).
+  @param[in] RegName   Identifies the SMM register to read.
+
+  @return  The value of the SMM register specified by RegName from the CPU
+           specified by CpuIndex.
+**/
+UINT64
+EFIAPI
+SmmCpuFeaturesGetSmmRegister (
+  IN UINTN         CpuIndex,
+  IN SMM_REG_NAME  RegName
+  )
+{
+  return 0;
+}
+
+/**
+  Sets the value of an SMM register on a specified CPU.
+  If the SMM register is not supported, then no action is performed.
+
+  @param[in] CpuIndex  The index of the CPU to write the SMM register.  The
+                       value must be between 0 and the NumberOfCpus field in
+                       the System Management System Table (SMST).
+  @param[in] RegName   Identifies the SMM register to write.
+                       registers are read-only.
+  @param[in] Value     The value to write to the SMM register.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesSetSmmRegister (
+  IN UINTN         CpuIndex,
+  IN SMM_REG_NAME  RegName,
+  IN UINT64        Value
+  )
+{
+}
+
+/**
+  Read an SMM Save State register on the target processor.  If this function
+  returns EFI_UNSUPPORTED, then the caller is responsible for reading the
+  SMM Save Sate register.
+
+  @param[in]  CpuIndex  The index of the CPU to read the SMM Save State.  The
+                        value must be between 0 and the NumberOfCpus field in
+                        the System Management System Table (SMST).
+  @param[in]  Register  The SMM Save State register to read.
+  @param[in]  Width     The number of bytes to read from the CPU save state.
+  @param[out] Buffer    Upon return, this holds the CPU register value read
+                        from the save state.
+
+  @retval EFI_SUCCESS           The register was read from Save State.
+  @retval EFI_INVALID_PARAMTER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED       This function does not support reading Register.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuFeaturesReadSaveStateRegister (
+  IN  UINTN                        CpuIndex,
+  IN  EFI_SMM_SAVE_STATE_REGISTER  Register,
+  IN  UINTN                        Width,
+  OUT VOID                         *Buffer
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Writes an SMM Save State register on the target processor.  If this function
+  returns EFI_UNSUPPORTED, then the caller is responsible for writing the
+  SMM Save Sate register.
+
+  @param[in] CpuIndex  The index of the CPU to write the SMM Save State.  The
+                       value must be between 0 and the NumberOfCpus field in
+                       the System Management System Table (SMST).
+  @param[in] Register  The SMM Save State register to write.
+  @param[in] Width     The number of bytes to write to the CPU save state.
+  @param[in] Buffer    Upon entry, this holds the new CPU register value.
+
+  @retval EFI_SUCCESS           The register was written to Save State.
+  @retval EFI_INVALID_PARAMTER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED       This function does not support writing Register.
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuFeaturesWriteSaveStateRegister (
+  IN UINTN                        CpuIndex,
+  IN EFI_SMM_SAVE_STATE_REGISTER  Register,
+  IN UINTN                        Width,
+  IN CONST VOID                   *Buffer
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
+  notification is completely processed.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesCompleteSmmReadyToLock (
+  VOID
+  )
+{
+}
+
+/**
+  This API provides a method for a CPU to allocate a specific region for storing page tables.
+
+  This API can be called more once to allocate memory for page tables.
+
+  Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+  allocated buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL
+  is returned.  If there is not enough memory remaining to satisfy the request, then NULL is
+  returned.
+
+  This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM.
+
+  @param  Pages                 The number of 4 KB pages to allocate.
+
+  @return A pointer to the allocated buffer for page tables.
+  @retval NULL      Fail to allocate a specific region for storing page tables,
+                    Or there is no preference on where the page tables are allocated in SMRAM.
+
+**/
+VOID *
+EFIAPI
+SmmCpuFeaturesAllocatePageTableMemory (
+  IN UINTN           Pages
+  )
+{
+  return NULL;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
new file mode 100644
index 0000000000..a45c857910
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
@@ -0,0 +1,30 @@
+## @file
+#  The CPU specific programming for PiSmmCpuDxeSmm module.
+#
+#  Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SmmCpuFeaturesLib
+  MODULE_UNI_FILE                = SmmCpuFeaturesLib.uni
+  FILE_GUID                      = 34001BF4-1E93-4e08-B90E-52F2418A5026
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = SmmCpuFeaturesLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[Sources]
+  SmmCpuFeaturesLib.c
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  QNCAccessLib
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni
new file mode 100644
index 0000000000..6ee54e9254
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni
@@ -0,0 +1,12 @@
+// /** @file
+// The CPU specific programming for PiSmmCpuDxeSmm module.
+//
+// Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module."
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c
new file mode 100644
index 0000000000..1d91360ec3
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c
@@ -0,0 +1,59 @@
+/** @file
+Framework PEIM to initialize memory on a QuarkNcSocId Memory Controller.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "MemoryInit.h"
+
+static PEI_QNC_MEMORY_INIT_PPI mPeiQNCMemoryInitPpi =
+{ MrcStart };
+
+static EFI_PEI_PPI_DESCRIPTOR PpiListPeiQNCMemoryInit =
+{
+    (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+    &gQNCMemoryInitPpiGuid,
+    &mPeiQNCMemoryInitPpi
+};
+
+void Mrc( MRCParams_t *MrcData);
+
+/**
+
+ Do memory initialization for QuarkNcSocId DDR3 SDRAM Controller
+
+ @param  FfsHeader    Not used.
+ @param  PeiServices  General purpose services available to every PEIM.
+
+ @return EFI_SUCCESS  Memory initialization completed successfully.
+ All other error conditions encountered result in an ASSERT.
+
+ **/
+EFI_STATUS
+PeimMemoryInit(
+    IN EFI_PEI_FILE_HANDLE FileHandle,
+    IN CONST EFI_PEI_SERVICES **PeiServices
+    )
+{
+  EFI_STATUS Status;
+
+  Status = (**PeiServices).InstallPpi(PeiServices, &PpiListPeiQNCMemoryInit);
+
+  return Status;
+}
+
+VOID
+EFIAPI
+MrcStart(
+    IN OUT MRCParams_t *MrcData
+    )
+{
+
+  Mrc(MrcData);
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h
new file mode 100644
index 0000000000..0cea554e0e
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h
@@ -0,0 +1,35 @@
+/** @file
+Framework PEIM to initialize memory on an DDR2 SDRAM Memory Controller.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _PEI_QNC_MEMORY_INIT_H_
+#define _PEI_QNC_MEMORY_INIT_H_
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+#include <IntelQNCPeim.h>
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Ppi/QNCMemoryInit.h>
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+
+
+VOID
+EFIAPI
+MrcStart (
+  IN OUT MRCParams_t  *MrcData
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf
new file mode 100644
index 0000000000..7a1ba522bf
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf
@@ -0,0 +1,70 @@
+## @file
+# This is the Memory Initialization Driver for Quark
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = MemoryInitPei
+  FILE_GUID                      = D2C69B26-82E1-4a1b-AD35-ED0261B9F347
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = PeimMemoryInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[BuildOptions]
+  GCC:DEBUG_*_*_CC_FLAGS               = -DGCC -Wno-unused-function
+  GCC:RELEASE_*_*_CC_FLAGS             = -DNDEBUG -DGCC -Wno-unused-function
+  INTEL:RELEASE_*_*_CC_FLAGS           = /D NDEBUG
+  MSFT:RELEASE_*_*_CC_FLAGS            = /D NDEBUG
+
+[Sources]
+  memory_options.h
+  platform.c
+  lprint.c
+  meminit.h
+  meminit.c
+  meminit_utils.h
+  meminit_utils.c
+  gen5_iosf_sb_definitions.h
+  general_definitions.h
+  io.h
+  core_types.h
+  prememinit.h
+  prememinit.c
+  mrc.h
+  mrc.c
+  hte.c
+  hte.h
+  MemoryInit.h
+  MemoryInit.c
+
+[Packages]
+  QuarkSocPkg/QuarkSocPkg.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  PeimEntryPoint
+  DebugLib
+  BaseMemoryLib
+
+[Ppis]
+  gQNCMemoryInitPpiGuid                        # PPI ALWAYS_PRODUCED
+
+[Depex]
+  TRUE
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h
new file mode 100644
index 0000000000..eef3c3f8ae
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h
@@ -0,0 +1,43 @@
+/** @file
+Core types used in Mrc.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __MRC_CORE_TYPES_H
+#define __MRC_CORE_TYPES_H
+
+typedef char char_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef unsigned char bool;
+typedef unsigned int size_t;
+
+#ifdef ASM_INC
+// Unfortunately h2inc has issue with long long
+typedef struct uint64_s
+{
+  uint32_t lo;
+  uint32_t hi;
+}uint64_t;
+#else
+typedef unsigned long long uint64_t;
+#endif
+
+#ifdef SIM
+// Native word length is 64bit in simulation environment
+typedef uint64_t uintn_t;
+#else
+// Quark is 32bit
+typedef uint32_t uintn_t;
+#endif
+
+#define PTR32(a)  ((volatile uint32_t*)(uintn_t)(a))
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h
new file mode 100644
index 0000000000..dea2a9ad05
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h
@@ -0,0 +1,738 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ * MCU register definition
+ *
+ ************************************************************************/
+#ifndef __IOSF_DEFINITIONS_H
+#define __IOSF_DEFINITIONS_H
+
+// Define each of the IOSF-SB register offsets used by MRC.
+
+
+// MCU registers (DUNIT):
+// ====
+#define DRP                 0x0000
+#define DTR0                0x0001
+#define DTR1                0x0002
+#define DTR2                0x0003
+#define DTR3                0x0004
+#define DTR4                0x0005
+#define DPMC0               0x0006
+#define DPMC1               0x0007
+#define DRFC                0x0008
+#define DSCH                0x0009
+#define DCAL                0x000A
+#define DRMC                0x000B
+#define PMSTS               0x000C
+#define DCO                 0x000F
+#define DSTAT               0x0020
+#define DECCCTRL            0x0060
+#define DFUSESTAT           0x0070
+#define SCRMSEED            0x0080
+#define SCRMLO              0x0081
+#define SCRMHI              0x0082
+
+#define MCU_CH_OFFSET       0x0040
+#define MCU_RK_OFFSET       0x0020
+
+////
+//
+// BEGIN DUnit register definition
+//
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t rank0Enabled       :1;             /**< BIT [0]   Rank 0 Enable */
+        uint32_t rank1Enabled       :1;             /**< BIT [1]   Rank 1 Enable */
+        uint32_t reserved0          :2;
+        uint32_t dimm0DevWidth      :2;             /**< BIT [5:4] DIMM 0 Device Width (Rank0&1)  */
+        uint32_t dimm0DevDensity    :2;             /**< BIT [7:6] DIMM 0 Device Density          */
+        uint32_t reserved1          :1;
+        uint32_t dimm1DevWidth      :2;             /**< BIT [10:9]  DIMM 1 Device Width (Rank2&3)  */
+        uint32_t dimm1DevDensity    :2;             /**< BIT [12:11] DIMM 1 Device Density          */
+        uint32_t split64            :1;             /**< BIT [13] split 64B transactions */
+        uint32_t addressMap         :2;             /**< BIT [15:14] Address Map select */
+        uint32_t reserved3          :14;
+        uint32_t mode32             :1;             /**< BIT [30] Select 32bit data interface*/
+        uint32_t reserved4          :1;
+    } field;
+} RegDRP;                                           /**< DRAM Rank Population and Interface Register */
+#pragma pack()
+
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t dramFrequency      :2;             /**< DRAM Frequency (000=800,001=1033,010=1333) */
+        uint32_t reserved1          :2;
+        uint32_t tRP                :4;             /**< bit [7:4]   Precharge to Activate Delay  */
+        uint32_t tRCD               :4;             /**< bit [11:8]  Activate to CAS Delay  */
+        uint32_t tCL                :3;             /**< bit [14:12] CAS Latency  */
+        uint32_t reserved4          :1;
+        uint32_t tXS                :1;             /**< SRX Delay  */
+        uint32_t reserved5          :1;
+        uint32_t tXSDLL             :1;             /**< SRX To DLL Delay  */
+        uint32_t reserved6          :1;
+        uint32_t tZQCS              :1;             /**< bit [20] ZQTS recovery Latncy  */
+        uint32_t reserved7          :1;
+        uint32_t tZQCL              :1;             /**< bit [22] ZQCL recovery Latncy  */
+        uint32_t reserved8          :1;
+        uint32_t pmeDelay           :2;             /**< bit [25:24] Power mode entry delay  */
+        uint32_t reserved9          :2;
+        uint32_t CKEDLY             :4;               /**< bit [31:28]  */
+    } field;
+} RegDTR0;                                          /**< DRAM Timing Register 0 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t tWCL               :3;             /**< bit [2:0] CAS Write Latency */
+        uint32_t reserved1          :1;
+        uint32_t tCMD               :2;             /**< bit [5:4] Command transport duration */
+        uint32_t reserved2          :2;
+        uint32_t tWTP               :4;             /**< Write to Precharge */
+        uint32_t tCCD               :2;             /**< CAS to CAS delay */
+        uint32_t reserved4          :2;
+        uint32_t tFAW               :4;             /**< Four bank Activation Window*/
+        uint32_t tRAS               :4;             /**< Row Activation Period: */
+        uint32_t tRRD               :2;             /**<Row activation to Row activation Delay */
+        uint32_t reserved5          :2;
+        uint32_t tRTP               :3;             /**<Read to Precharge Delay */
+        uint32_t reserved6          :1;
+    } field;
+} RegDTR1;                                          /**< DRAM Timing Register 1 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t tRRDR              :3;             /**< RD to RD from different ranks, same DIMM */
+        uint32_t reserved1          :5;
+        uint32_t tWWDR              :3;             /**< WR to WR from different ranks, same DIMM. */
+        uint32_t reserved3          :5;
+        uint32_t tRWDR              :4;             /**< bit [19:16] RD to WR from different ranks, same DIMM. */
+        uint32_t reserved5          :12;
+    } field;
+} RegDTR2;                                          /**< DRAM Timing Register 2 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t tWRDR              :3;             /**< WR to RD from different ranks, same DIMM. */
+        uint32_t reserved1          :1;
+        uint32_t tWRDD              :3;             /**< WR to RD from different DIMM. */
+        uint32_t reserved2          :1;
+        uint32_t tRWSR              :4;             /**< RD to WR Same Rank. */
+        uint32_t reserved3          :1;
+        uint32_t tWRSR              :4;             /**< WR to RD Same Rank. */
+        uint32_t reserved4          :5;
+        uint32_t tXP                :2;             /**< Time from CKE set on to any command. */
+        uint32_t PWD_DLY            :4;             /**< Extended Power-Down Delay. */
+        uint32_t EnDeRate           :1;
+        uint32_t DeRateOvr          :1;
+        uint32_t DeRateStat         :1;
+        uint32_t reserved5          :1;
+    } field;
+} RegDTR3;                                          /**< DRAM Timing Register 3 */
+#pragma pack()
+
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t WRODTSTRT          :2;             /**< WR command to ODT assert delay */
+        uint32_t reserved1          :2;
+        uint32_t WRODTSTOP          :3;             /**< Write command to ODT de-assert delay. */
+        uint32_t reserved2          :1;
+        uint32_t RDODTSTRT          :3;             /**< Read command to ODT assert delay */
+        uint32_t reserved3          :1;
+        uint32_t RDODTSTOP          :3;             /**< Read command to ODT de-assert delay */
+        uint32_t ODTDIS             :1;             /**< ODT disable */
+        uint32_t TRGSTRDIS          :1;             /**< Write target rank is not stretched */
+        uint32_t RDODTDIS           :1;             /**< Disable Read ODT */
+        uint32_t WRBODTDIS          :1;             /**< Disable Write ODT */
+        uint32_t reserved5          :13;
+    } field;
+} RegDTR4;                                          /**< DRAM Timing Register 3 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t SREntryDelay       :8;             /**< Self-Refresh Entry Delay: */
+        uint32_t powerModeOpCode    :5;             /**< SPID Power Mode Opcode */
+        uint32_t reserved1          :3;
+        uint32_t PCLSTO             :3;             /**< Page Close Timeout Period */
+        uint32_t reserved2          :1;
+        uint32_t PCLSWKOK           :1;             /**< Wake Allowed For Page Close Timeout */
+        uint32_t PREAPWDEN          :1;             /**< Send Precharge All to rank before entering Power-Down mode. */
+        uint32_t reserved3          :1;
+        uint32_t DYNSREN            :1;             /**< Dynamic Self-Refresh */
+        uint32_t CLKGTDIS           :1;             /**< Clock Gating Disabled*/
+        uint32_t DISPWRDN           :1;             /**< Disable Power Down*/
+        uint32_t reserved4          :2;
+        uint32_t REUTCLKGTDIS       :1;
+        uint32_t ENPHYCLKGATE       :1;
+        uint32_t reserved5          :2;
+    } field;
+} RegDPMC0;                                           /**< DRAM Power Management Control Register 0 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t REFWMLO            :4;             /**< Refresh Opportunistic Watermark */
+        uint32_t REFWMHI            :4;             /**< Refresh High Watermark*/
+        uint32_t REFWMPNC           :4;             /**< Refresh Panic Watermark */
+        uint32_t tREFI              :3;             /**< bit [14:12] Refresh Period */
+        uint32_t reserved1          :1;
+        uint32_t REFCNTMAX          :2;             /**< Refresh Max tREFI Interval */
+        uint32_t reserved2          :2;
+        uint32_t REFSKEWDIS         :1;             /**< tREFI counters */
+        uint32_t REFDBTCLR          :1;
+        uint32_t reserved3          :2;
+        uint32_t CuRefRate          :3;
+        uint32_t DisRefBW           :1;
+        uint32_t reserved4          :4;
+    } field;
+} RegDRCF;                                           /**< DRAM Refresh Control Register*/
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t reserved1          :8;
+        uint32_t ZQCINT             :3;             /**< ZQ Calibration Short Interval: */
+        uint32_t reserved2          :1;
+        uint32_t SRXZQCL            :2;             /** < ZQ Calibration Length */
+        uint32_t ZQCalType          :1;
+        uint32_t ZQCalStart         :1;
+        uint32_t TQPollStart        :1;
+        uint32_t TQPollRS           :2;
+        uint32_t reserved3          :5;
+        uint32_t MRRData            :8;             /**< bit[31:24] */
+    } field;
+} RegDCAL;                                          /**< DRAM Calibration Control*/
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t OOOAGETRH          :5;             /**< Out-of-Order Aging Threshold */
+        uint32_t reserved1          :3;
+        uint32_t OOODIS             :1;             /**< Out-of-Order Disable */
+        uint32_t OOOST3DIS          :1;             /**< Out-of-Order Disabled when RequestBD_Status is 3. */
+        uint32_t reserved2          :2;
+        uint32_t NEWBYPDIS          :1;
+        uint32_t reserved3          :3;
+        uint32_t IPREQMAX           :3;             /** < Max In-Progress Requests stored in MC */
+        uint32_t reserved4          :13;
+    } field;
+} RegDSCH;                                           /**< DRAM Scheduler Control Register */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t DRPLOCK            :1;             /**< DRP lock bit */
+        uint32_t reserved1          :7;
+        uint32_t REUTLOCK           :1;             /**< REUT lock bit */
+        uint32_t reserved2          :19;
+        uint32_t PMICTL             :1;             /**< PRI Control Select: 0-memory_manager, 1-hte */
+        uint32_t PMIDIS             :1;             /**< PMIDIS Should be set is using IOSF-SB RW */
+        uint32_t DIOIC              :1;             /**< DDRIO initialization is complete */
+        uint32_t IC                 :1;             /**< D-unit Initialization Complete */
+    } field;
+} RegDCO;                                           /**< DRAM Controller Operation Register*/
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t SBEEN       :1;             /**< Enable Single Bit Error Detection and Correction */
+        uint32_t DBEEN       :1;             /**< Enable Double Bit Error Detection */
+        uint32_t CBOEN       :3;             /**< Enable ECC Check Bits Override */
+        uint32_t SYNSEL      :2;             /**< ECC Syndrome Bits Select for Observation */
+    uint32_t CLRSBECNT   :1;             /**< Clear ECC Single Bit Error Count */
+        uint32_t CBOV        :8;             /**< ECC Check Bits Override Value */
+        uint32_t reserved1   :1;             /**<  */
+        uint32_t ENCBGEN     :1;             /**< Enable Generation of ECC Check Bits */
+        uint32_t ENCBGESWIZ  :1;             /**< Enable Same Chip ECC Byte Lane Swizzle */
+
+    } field;
+} RegDECCCTRL;                                      /**< DRAM ECC Control Register */
+#pragma pack()
+
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t FUS_DUN_ECC_DIS              :1;
+    uint32_t FUS_DUN_MAX_SUPPORTED_MEMORY :3;
+    uint32_t FUS_DUN_MAX_DEVDEN           :2;
+    uint32_t RESERVED1                    :1;
+    uint32_t FUS_DUN_RANK2_DIS            :1;
+    uint32_t FUS_DUN_OOO_DIS              :1;
+    uint32_t FUS_DUN_MEMX8_DIS            :1;
+    uint32_t FUS_DUN_MEMX16_DIS           :1;
+    uint32_t RESERVED2                    :1;
+    uint32_t FUS_DUN_1N_DIS               :1;
+    uint32_t FUS_DUN_DQ_SCRAMBLER_DIS     :1;
+    uint32_t RESERVED3                    :1;
+    uint32_t FUS_DUN_32BIT_DRAM_IFC       :1;
+    } field;
+} RegDFUSESTAT;
+#pragma pack()
+
+//
+// END DUnit register definition
+//
+////
+
+
+
+////
+//
+// DRAM Initialization Structures used in JEDEC Message Bus Commands
+//
+
+#pragma pack(1)
+typedef union {
+        uint32_t      raw;
+    struct {
+        unsigned    command         :3;             /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
+        unsigned    bankAddress     :3;             /**< Bank Address (BA[2:0]) */
+        unsigned    BL              :2;             /**< Burst Length, CDV:1*/
+        unsigned    CL              :1;             /**< CL Reserved CDV:0 */
+        unsigned    RBT             :1;             /**< Read Burst Type */
+        unsigned    casLatency      :3;             /**< cas Latency */
+        unsigned    TM              :1;             /**< Test mode */
+        unsigned    dllReset        :1;             /**< DLL Reset */
+        unsigned    writeRecovery   :3;             /**< Write Recovery for Auto Pre-Charge: 001=2,010=3,011=4,100=5,101=6 */
+        unsigned    PPD             :1;             /**< DLL Control for Precharge Power-Down CDV:1 */
+        unsigned    reserved1       :3;
+        unsigned    rankSelect      :4;             /**< Rank Select */
+        unsigned    reserved2       :6;
+    } field;
+} DramInitDDR3MRS0;                                 /**< DDR3 Mode Register Set (MRS) Command */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+        uint32_t      raw;
+    struct {
+        unsigned    command         :3;             /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
+        unsigned    bankAddress     :3;             /**< Bank Address (BA[2:0]) */
+        unsigned    dllEnabled      :1;             /**< CDV=0 */
+        unsigned    DIC0            :1;             /**< Output Driver Impedance Control */
+        unsigned    rttNom0         :1;             /**< RTT_nom[0] */
+        unsigned    MRC_AL          :2;             /**< Additive Latency = 0 */
+        unsigned    DIC1            :1;             /**< Reserved */
+        unsigned    rttNom1         :1;             /**< RTT_nom[1] */
+        unsigned    wlEnabled       :1;             /**< Write Leveling Enable */
+        unsigned    reserved1       :1;
+        unsigned    rttNom2         :1;             /** < RTT_nom[2] */
+        unsigned    reserved2       :1;
+        unsigned    TDQS            :1;             /**< TDQS Enable */
+        unsigned    Qoff            :1;             /**< Output Buffers Disabled */
+        unsigned    reserved3       :3;
+        unsigned    rankSelect      :4;             /**< Rank Select */
+        unsigned    reserved4       :6;
+    } field;
+} DramInitDDR3EMR1;                                 /**< DDR3 Extended Mode Register 1 Set (EMRS1) Command */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+        uint32_t      raw;
+    struct {
+        uint32_t    command         :3;             /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
+        uint32_t    bankAddress     :3;             /**< Bank Address (BA[2:0]) */
+        uint32_t    PASR            :3;             /**< Partial Array Self-Refresh */
+        uint32_t    CWL             :3;             /**< CAS Write Latency */
+        uint32_t    ASR             :1;             /**< Auto Self-Refresh */
+        uint32_t    SRT             :1;             /**< SR Temperature Range = 0*/
+        uint32_t    reserved1       :1;
+        uint32_t    rtt_WR          :2;             /**< Rtt_WR */
+        uint32_t    reserved2       :5;
+        uint32_t    rankSelect      :4;             /**< Rank Select */
+        uint32_t    reserved3       :6;
+    } field;
+} DramInitDDR3EMR2;                                 /**< DDR3 Extended Mode Register 2 Set (EMRS2) Command */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+        uint32_t      raw;
+    struct {
+        uint32_t    command         :3;             /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
+        uint32_t    bankAddress     :3;             /**< Bank Address (BA[2:0]) */
+        uint32_t    MPR_Location    :2;             /**< MPR Location */
+        uint32_t    MPR             :1;             /**< MPR: Multi Purpose Register */
+        uint32_t    reserved1       :13;
+        uint32_t    rankSelect      :4;             /**< Rank Select */
+        uint32_t    reserved2       :6;
+    } field;
+} DramInitDDR3EMR3;                                 /**< DDR3 Extended Mode Register 2 Set (EMRS2) Command */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+    uint32_t    raw;
+    struct {
+        uint32_t    command         :3;             /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110 - ZQ Calibration,111-NOP */
+        uint32_t    bankAddress     :3;             /**< Bank Address (BA[2:0]) */
+        uint32_t    multAddress     :16;            /**< Multiplexed Address (MA[14:0]) */
+        uint32_t    rankSelect      :2;             /**< Rank Select */
+        uint32_t    reserved3       :8;
+    } field;
+} DramInitMisc;                                     /**< Miscellaneous DDRx Initialization Command */
+#pragma pack()
+
+//
+// Construct DRAM init command using DramInitXxxx pattern
+//
+#define DCMD_MRS1(rnk,dat) (0 | ((rnk)<<22) | (1<<3) | ((dat)<<6))
+#define DCMD_REF(rnk)      (1 | ((rnk)<<22))
+#define DCMD_PRE(rnk)      (2 | ((rnk)<<22))
+#define DCMD_PREA(rnk)     (2 | ((rnk)<<22) | (BIT10<<6))
+#define DCMD_ACT(rnk,row)  (3 | ((rnk)<<22) | ((row)<<6))
+#define DCMD_WR(rnk,col)   (4 | ((rnk)<<22) | ((col)<<6))
+#define DCMD_RD(rnk,col)   (5 | ((rnk)<<22) | ((col)<<6))
+#define DCMD_ZQCS(rnk)     (6 | ((rnk)<<22))
+#define DCMD_ZQCL(rnk)     (6 | ((rnk)<<22) | (BIT10<<6))
+#define DCMD_NOP(rnk)      (7 | ((rnk)<<22))
+
+
+
+
+#define DDR3_EMRS1_DIC_40       (0)
+#define DDR3_EMRS1_DIC_34       (1)
+
+#define DDR3_EMRS2_RTTWR_60     (BIT9)
+#define DDR3_EMRS2_RTTWR_120    (BIT10)
+
+#define DDR3_EMRS1_RTTNOM_0     (0)
+#define DDR3_EMRS1_RTTNOM_60    (BIT2)
+#define DDR3_EMRS1_RTTNOM_120   (BIT6)
+#define DDR3_EMRS1_RTTNOM_40    (BIT6|BIT2)
+#define DDR3_EMRS1_RTTNOM_20    (BIT9)
+#define DDR3_EMRS1_RTTNOM_30    (BIT9|BIT2)
+
+
+//
+// END DRAM Init...
+//
+////
+
+
+// HOST_BRIDGE registers:
+#define HMBOUND             0x0020  //ok
+
+// MEMORY_MANAGER registers:
+#define BCTRL               0x0004
+#define BWFLUSH             0x0008
+#define BDEBUG1             0x00C4
+
+////
+//
+// BEGIN DDRIO registers
+//
+
+// DDR IOs & COMPs:
+#define DDRIODQ_BL_OFFSET   0x0800
+#define DDRIODQ_CH_OFFSET   ((NUM_BYTE_LANES/2) * DDRIODQ_BL_OFFSET)
+#define DDRIOCCC_CH_OFFSET  0x0800
+#define DDRCOMP_CH_OFFSET   0x0100
+
+// CH0-BL01-DQ
+#define DQOBSCKEBBCTL       0x0000
+#define DQDLLTXCTL          0x0004
+#define DQDLLRXCTL          0x0008
+#define DQMDLLCTL           0x000C
+#define B0RXIOBUFCTL        0x0010
+#define B0VREFCTL           0x0014
+#define B0RXOFFSET1         0x0018
+#define B0RXOFFSET0         0x001C
+#define B1RXIOBUFCTL        0x0020
+#define B1VREFCTL           0x0024
+#define B1RXOFFSET1         0x0028
+#define B1RXOFFSET0         0x002C
+#define DQDFTCTL            0x0030
+#define DQTRAINSTS          0x0034
+#define B1DLLPICODER0       0x0038
+#define B0DLLPICODER0       0x003C
+#define B1DLLPICODER1       0x0040
+#define B0DLLPICODER1       0x0044
+#define B1DLLPICODER2       0x0048
+#define B0DLLPICODER2       0x004C
+#define B1DLLPICODER3       0x0050
+#define B0DLLPICODER3       0x0054
+#define B1RXDQSPICODE       0x0058
+#define B0RXDQSPICODE       0x005C
+#define B1RXDQPICODER32     0x0060
+#define B1RXDQPICODER10     0x0064
+#define B0RXDQPICODER32     0x0068
+#define B0RXDQPICODER10     0x006C
+#define B01PTRCTL0          0x0070
+#define B01PTRCTL1          0x0074
+#define B01DBCTL0           0x0078
+#define B01DBCTL1           0x007C
+#define B0LATCTL0           0x0080
+#define B1LATCTL0           0x0084
+#define B01LATCTL1          0x0088
+#define B0ONDURCTL          0x008C
+#define B1ONDURCTL          0x0090
+#define B0OVRCTL            0x0094
+#define B1OVRCTL            0x0098
+#define DQCTL               0x009C
+#define B0RK2RKCHGPTRCTRL   0x00A0
+#define B1RK2RKCHGPTRCTRL   0x00A4
+#define DQRK2RKCTL          0x00A8
+#define DQRK2RKPTRCTL       0x00AC
+#define B0RK2RKLAT          0x00B0
+#define B1RK2RKLAT          0x00B4
+#define DQCLKALIGNREG0      0x00B8
+#define DQCLKALIGNREG1      0x00BC
+#define DQCLKALIGNREG2      0x00C0
+#define DQCLKALIGNSTS0      0x00C4
+#define DQCLKALIGNSTS1      0x00C8
+#define DQCLKGATE           0x00CC
+#define B0COMPSLV1          0x00D0
+#define B1COMPSLV1          0x00D4
+#define B0COMPSLV2          0x00D8
+#define B1COMPSLV2          0x00DC
+#define B0COMPSLV3          0x00E0
+#define B1COMPSLV3          0x00E4
+#define DQVISALANECR0TOP    0x00E8
+#define DQVISALANECR1TOP    0x00EC
+#define DQVISACONTROLCRTOP  0x00F0
+#define DQVISALANECR0BL     0x00F4
+#define DQVISALANECR1BL     0x00F8
+#define DQVISACONTROLCRBL   0x00FC
+#define DQTIMINGCTRL        0x010C
+// CH0-ECC
+#define ECCDLLTXCTL         0x2004
+#define ECCDLLRXCTL         0x2008
+#define ECCMDLLCTL          0x200C
+#define ECCB1DLLPICODER0    0x2038
+#define ECCB1DLLPICODER1    0x2040
+#define ECCB1DLLPICODER2    0x2048
+#define ECCB1DLLPICODER3    0x2050
+#define ECCB01DBCTL0        0x2078
+#define ECCB01DBCTL1        0x207C
+#define ECCCLKALIGNREG0     0x20B8
+#define ECCCLKALIGNREG1     0x20BC
+#define ECCCLKALIGNREG2     0x20C0
+// CH0-CMD
+#define CMDOBSCKEBBCTL      0x4800
+#define CMDDLLTXCTL         0x4808
+#define CMDDLLRXCTL         0x480C
+#define CMDMDLLCTL          0x4810
+#define CMDRCOMPODT         0x4814
+#define CMDDLLPICODER0      0x4820
+#define CMDDLLPICODER1      0x4824
+#define CMDCFGREG0          0x4840
+#define CMDPTRREG           0x4844
+#define CMDCLKALIGNREG0     0x4850
+#define CMDCLKALIGNREG1     0x4854
+#define CMDCLKALIGNREG2     0x4858
+#define CMDPMCONFIG0        0x485C
+#define CMDPMDLYREG0        0x4860
+#define CMDPMDLYREG1        0x4864
+#define CMDPMDLYREG2        0x4868
+#define CMDPMDLYREG3        0x486C
+#define CMDPMDLYREG4        0x4870
+#define CMDCLKALIGNSTS0     0x4874
+#define CMDCLKALIGNSTS1     0x4878
+#define CMDPMSTS0           0x487C
+#define CMDPMSTS1           0x4880
+#define CMDCOMPSLV          0x4884
+#define CMDBONUS0           0x488C
+#define CMDBONUS1           0x4890
+#define CMDVISALANECR0      0x4894
+#define CMDVISALANECR1      0x4898
+#define CMDVISACONTROLCR    0x489C
+#define CMDCLKGATE          0x48A0
+#define CMDTIMINGCTRL       0x48A4
+// CH0-CLK-CTL
+#define CCOBSCKEBBCTL       0x5800
+#define CCRCOMPIO           0x5804
+#define CCDLLTXCTL          0x5808
+#define CCDLLRXCTL          0x580C
+#define CCMDLLCTL           0x5810
+#define CCRCOMPODT          0x5814
+#define CCDLLPICODER0       0x5820
+#define CCDLLPICODER1       0x5824
+#define CCDDR3RESETCTL      0x5830
+#define CCCFGREG0           0x5838
+#define CCCFGREG1           0x5840
+#define CCPTRREG            0x5844
+#define CCCLKALIGNREG0      0x5850
+#define CCCLKALIGNREG1      0x5854
+#define CCCLKALIGNREG2      0x5858
+#define CCPMCONFIG0         0x585C
+#define CCPMDLYREG0         0x5860
+#define CCPMDLYREG1         0x5864
+#define CCPMDLYREG2         0x5868
+#define CCPMDLYREG3         0x586C
+#define CCPMDLYREG4         0x5870
+#define CCCLKALIGNSTS0      0x5874
+#define CCCLKALIGNSTS1      0x5878
+#define CCPMSTS0            0x587C
+#define CCPMSTS1            0x5880
+#define CCCOMPSLV1          0x5884
+#define CCCOMPSLV2          0x5888
+#define CCCOMPSLV3          0x588C
+#define CCBONUS0            0x5894
+#define CCBONUS1            0x5898
+#define CCVISALANECR0       0x589C
+#define CCVISALANECR1       0x58A0
+#define CCVISACONTROLCR     0x58A4
+#define CCCLKGATE           0x58A8
+#define CCTIMINGCTL         0x58AC
+// COMP
+#define CMPCTRL             0x6800
+#define SOFTRSTCNTL         0x6804
+#define MSCNTR              0x6808
+#define NMSCNTRL            0x680C
+#define LATCH1CTL           0x6814
+#define COMPVISALANECR0     0x681C
+#define COMPVISALANECR1     0x6820
+#define COMPVISACONTROLCR   0x6824
+#define COMPBONUS0          0x6830
+#define TCOCNTCTRL          0x683C
+#define DQANAODTPUCTL       0x6840
+#define DQANAODTPDCTL       0x6844
+#define DQANADRVPUCTL       0x6848
+#define DQANADRVPDCTL       0x684C
+#define DQANADLYPUCTL       0x6850
+#define DQANADLYPDCTL       0x6854
+#define DQANATCOPUCTL       0x6858
+#define DQANATCOPDCTL       0x685C
+#define CMDANADRVPUCTL      0x6868
+#define CMDANADRVPDCTL      0x686C
+#define CMDANADLYPUCTL      0x6870
+#define CMDANADLYPDCTL      0x6874
+#define CLKANAODTPUCTL      0x6880
+#define CLKANAODTPDCTL      0x6884
+#define CLKANADRVPUCTL      0x6888
+#define CLKANADRVPDCTL      0x688C
+#define CLKANADLYPUCTL      0x6890
+#define CLKANADLYPDCTL      0x6894
+#define CLKANATCOPUCTL      0x6898
+#define CLKANATCOPDCTL      0x689C
+#define DQSANAODTPUCTL      0x68A0
+#define DQSANAODTPDCTL      0x68A4
+#define DQSANADRVPUCTL      0x68A8
+#define DQSANADRVPDCTL      0x68AC
+#define DQSANADLYPUCTL      0x68B0
+#define DQSANADLYPDCTL      0x68B4
+#define DQSANATCOPUCTL      0x68B8
+#define DQSANATCOPDCTL      0x68BC
+#define CTLANADRVPUCTL      0x68C8
+#define CTLANADRVPDCTL      0x68CC
+#define CTLANADLYPUCTL      0x68D0
+#define CTLANADLYPDCTL      0x68D4
+#define CHNLBUFSTATIC       0x68F0
+#define COMPOBSCNTRL        0x68F4
+#define COMPBUFFDBG0        0x68F8
+#define COMPBUFFDBG1        0x68FC
+#define CFGMISCCH0          0x6900
+#define COMPEN0CH0          0x6904
+#define COMPEN1CH0          0x6908
+#define COMPEN2CH0          0x690C
+#define STATLEGEN0CH0       0x6910
+#define STATLEGEN1CH0       0x6914
+#define DQVREFCH0           0x6918
+#define CMDVREFCH0          0x691C
+#define CLKVREFCH0          0x6920
+#define DQSVREFCH0          0x6924
+#define CTLVREFCH0          0x6928
+#define TCOVREFCH0          0x692C
+#define DLYSELCH0           0x6930
+#define TCODRAMBUFODTCH0    0x6934
+#define CCBUFODTCH0         0x6938
+#define RXOFFSETCH0         0x693C
+#define DQODTPUCTLCH0       0x6940
+#define DQODTPDCTLCH0       0x6944
+#define DQDRVPUCTLCH0       0x6948
+#define DQDRVPDCTLCH0       0x694C
+#define DQDLYPUCTLCH0       0x6950
+#define DQDLYPDCTLCH0       0x6954
+#define DQTCOPUCTLCH0       0x6958
+#define DQTCOPDCTLCH0       0x695C
+#define CMDDRVPUCTLCH0      0x6968
+#define CMDDRVPDCTLCH0      0x696C
+#define CMDDLYPUCTLCH0      0x6970
+#define CMDDLYPDCTLCH0      0x6974
+#define CLKODTPUCTLCH0      0x6980
+#define CLKODTPDCTLCH0      0x6984
+#define CLKDRVPUCTLCH0      0x6988
+#define CLKDRVPDCTLCH0      0x698C
+#define CLKDLYPUCTLCH0      0x6990
+#define CLKDLYPDCTLCH0      0x6994
+#define CLKTCOPUCTLCH0      0x6998
+#define CLKTCOPDCTLCH0      0x699C
+#define DQSODTPUCTLCH0      0x69A0
+#define DQSODTPDCTLCH0      0x69A4
+#define DQSDRVPUCTLCH0      0x69A8
+#define DQSDRVPDCTLCH0      0x69AC
+#define DQSDLYPUCTLCH0      0x69B0
+#define DQSDLYPDCTLCH0      0x69B4
+#define DQSTCOPUCTLCH0      0x69B8
+#define DQSTCOPDCTLCH0      0x69BC
+#define CTLDRVPUCTLCH0      0x69C8
+#define CTLDRVPDCTLCH0      0x69CC
+#define CTLDLYPUCTLCH0      0x69D0
+#define CTLDLYPDCTLCH0      0x69D4
+#define FNLUPDTCTLCH0       0x69F0
+// PLL
+#define MPLLCTRL0           0x7800
+#define MPLLCTRL1           0x7808
+#define MPLLCSR0            0x7810
+#define MPLLCSR1            0x7814
+#define MPLLCSR2            0x7820
+#define MPLLDFT             0x7828
+#define MPLLMON0CTL         0x7830
+#define MPLLMON1CTL         0x7838
+#define MPLLMON2CTL         0x783C
+#define SFRTRIM             0x7850
+#define MPLLDFTOUT0         0x7858
+#define MPLLDFTOUT1         0x785C
+#define MASTERRSTN          0x7880
+#define PLLLOCKDEL          0x7884
+#define SFRDEL              0x7888
+#define CRUVISALANECR0      0x78F0
+#define CRUVISALANECR1      0x78F4
+#define CRUVISACONTROLCR    0x78F8
+#define IOSFVISALANECR0     0x78FC
+#define IOSFVISALANECR1     0x7900
+#define IOSFVISACONTROLCR   0x7904
+
+//
+// END DDRIO registers
+//
+////
+
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h
new file mode 100644
index 0000000000..1b79ecab2e
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h
@@ -0,0 +1,84 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ ************************************************************************/
+#ifndef __GENERAL_DEFINITIONS_H
+#define __GENERAL_DEFINITIONS_H
+
+#undef BIT0
+#undef BIT1
+#undef BIT2
+#undef BIT3
+#undef BIT4
+#undef BIT5
+#undef BIT6
+#undef BIT7
+#undef BIT8
+#undef BIT9
+#undef BIT10
+#undef BIT11
+#undef BIT12
+#undef BIT13
+#undef BIT14
+#undef BIT15
+#undef BIT16
+#undef BIT17
+#undef BIT18
+#undef BIT19
+#undef BIT20
+#undef BIT21
+#undef BIT22
+#undef BIT23
+#undef BIT24
+#undef BIT25
+#undef BIT26
+#undef BIT27
+#undef BIT28
+#undef BIT29
+#undef BIT30
+#undef BIT31
+
+
+
+// defines
+#define BIT0  0x00000001U
+#define BIT1  0x00000002U
+#define BIT2  0x00000004U
+#define BIT3  0x00000008U
+#define BIT4  0x00000010U
+#define BIT5  0x00000020U
+#define BIT6  0x00000040U
+#define BIT7  0x00000080U
+#define BIT8  0x00000100U
+#define BIT9  0x00000200U
+#define BIT10 0x00000400U
+#define BIT11 0x00000800U
+#define BIT12 0x00001000U
+#define BIT13 0x00002000U
+#define BIT14 0x00004000U
+#define BIT15 0x00008000U
+#define BIT16 0x00010000U
+#define BIT17 0x00020000U
+#define BIT18 0x00040000U
+#define BIT19 0x00080000U
+#define BIT20 0x00100000U
+#define BIT21 0x00200000U
+#define BIT22 0x00400000U
+#define BIT23 0x00800000U
+#define BIT24 0x01000000U
+#define BIT25 0x02000000U
+#define BIT26 0x04000000U
+#define BIT27 0x08000000U
+#define BIT28 0x10000000U
+#define BIT29 0x20000000U
+#define BIT30 0x40000000U
+#define BIT31 0x80000000U
+
+
+#define true  0x01
+#define false 0x00
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c
new file mode 100644
index 0000000000..718fac12b8
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c
@@ -0,0 +1,536 @@
+/** @file
+HTE handling routines for MRC use.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "mrc.h"
+#include "memory_options.h"
+#include "io.h"
+
+#include "hte.h"
+
+
+#ifdef SIM
+VOID delay_n(UINT32 nanoseconds);
+#define MySimStall(a)   delay_n(a/1000)
+#endif
+
+STATIC VOID EnableAllHteErrors(
+    UINT8 Mask)
+/*++
+
+ Routine Description:
+
+ This function enables to HTE to detect all possible errors for
+ the given training parameters (per-bit or full byte lane).
+
+ Returns:
+
+ None
+
+ --*/
+{
+  isbW32m(HTE, 0x000200A2, 0xFFFFFFFF);
+  isbW32m(HTE, 0x000200A3, 0x000000FF);
+  isbW32m(HTE, 0x000200A4, 0x00000000);
+}
+
+STATIC UINT32 CheckHteErrors(
+    VOID)
+/*++
+
+ Routine Description:
+
+ This function goes and reads the HTE register in order to find any error
+
+ Returns:
+
+ The errors detected in the HTE status register
+
+ --*/
+{
+  return isbR32m(HTE, 0x000200A7);
+}
+
+STATIC VOID WaitForHteComplete(
+    VOID)
+/*++
+
+ Routine Description:
+
+ This function waits until HTE finishes
+
+ Returns:
+
+ None
+
+ --*/
+{
+  UINT32 Tmp;
+
+  ENTERFN();
+
+  //
+  // Is the test done?
+  //
+  do
+  {
+#ifdef SIM
+    MySimStall (35000); // 35 ns delay
+#endif
+  } while (0 != (isbR32m(HTE, 0x00020012) & BIT30));
+
+  Tmp = isbR32m(HTE, 0x00020011);
+  Tmp = Tmp | BIT9;
+  Tmp = Tmp & ~(BIT13 | BIT12);
+  isbW32m(HTE, 0x00020011, Tmp);
+
+  LEAVEFN();
+}
+
+STATIC VOID ClearHteErrorRegisters(
+    VOID)
+/*++
+
+ Routine Description:
+
+ Clears registers related with errors in the HTE.
+
+ Returns:
+
+ None
+
+ --*/
+{
+  UINT32 Tmp;
+
+  //
+  // Clear all HTE errors and enable error checking
+  // for burst and chunk.
+  //
+  Tmp = isbR32m(HTE, 0x000200A1);
+  Tmp |= BIT8;
+  isbW32m(HTE, 0x000200A1, Tmp);
+}
+
+UINT32 HteMemInit(
+    MRC_PARAMS *CurrentMrcData,
+    UINT8 MemInitFlag,
+    UINT8 HaltHteEngineOnError)
+
+/*++
+
+ Routine Description:
+
+ Uses HW HTE engine to initialize or test all memory attached to a given DUNIT.
+ If MemInitFlag is 1, this routine writes 0s to all memory locations to initialize
+ ECC.
+ If MemInitFlag is 0, this routine will send an 5AA55AA5 pattern to all memory
+ locations on the RankMask and then read it back.  Then it sends an A55AA55A
+ pattern to all memory locations on the RankMask and reads it back.
+
+ Arguments:
+
+ CurrentMrcData: Host struture for all MRC global data.
+ MemInitFlag: 0 for memtest, 1 for meminit.
+ HaltHteEngineOnError:  Halt the HTE engine on first error observed, or keep
+ running to see how many errors are found.
+
+ Returns:
+ Errors register showing HTE failures.
+ Also prints out which rank failed the HTE test if failure occurs.
+ For rank detection to work, the address map must be left in its default
+ state.  If MRC changes the address map, this function must be modified
+ to change it back to default at the beginning, then restore it at the end.
+
+ --*/
+{
+  UINT32 Offset;
+  UINT8 TestNum;
+  UINT8 i;
+
+  //
+  // Clear out the error registers at the start of each memory
+  // init or memory test run.
+  //
+  ClearHteErrorRegisters();
+
+  isbW32m(HTE, 0x00020062, 0x00000015);
+
+  for (Offset = 0x80; Offset <= 0x8F; Offset++)
+  {
+    isbW32m(HTE, Offset, ((Offset & 1) ? 0xA55A : 0x5AA5));
+  }
+
+  isbW32m(HTE, 0x00020021, 0x00000000);
+#ifdef QUICKSIM
+  // Just do 4 cache lines for simulation memtest to save time.
+  isbW32m(HTE, 0x00020022, 4-1);
+#else
+  isbW32m(HTE, 0x00020022, (CurrentMrcData->mem_size >> 6) - 1);
+#endif
+
+  isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
+  isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
+  isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
+  isbW32m(HTE, 0x00020066, 0x03000000);
+
+  switch (MemInitFlag)
+  {
+  case MrcMemInit:
+    TestNum = 1; // Only 1 write pass through memory is needed to initialize ECC.
+    break;
+  case MrcMemTest:
+    TestNum = 4; // Write/read then write/read with inverted pattern.
+    break;
+  default:
+    DPF(D_INFO, "Unknown parameter for MemInitFlag: %d\n", MemInitFlag);
+    return 0xFFFFFFFF;
+    break;
+  }
+
+  DPF(D_INFO, "HteMemInit");
+  for (i = 0; i < TestNum; i++)
+  {
+    DPF(D_INFO, ".");
+
+    if (i == 0)
+    {
+      isbW32m(HTE, 0x00020061, 0x00000000);
+      isbW32m(HTE, 0x00020020, 0x00110010);
+    }
+    else if (i == 1)
+    {
+      isbW32m(HTE, 0x00020061, 0x00000000);
+      isbW32m(HTE, 0x00020020, 0x00010010);
+    }
+    else if (i == 2)
+    {
+      isbW32m(HTE, 0x00020061, 0x00010100);
+      isbW32m(HTE, 0x00020020, 0x00110010);
+    }
+    else
+    {
+      isbW32m(HTE, 0x00020061, 0x00010100);
+      isbW32m(HTE, 0x00020020, 0x00010010);
+    }
+
+    isbW32m(HTE, 0x00020011, 0x00111000);
+    isbW32m(HTE, 0x00020011, 0x00111100);
+
+    WaitForHteComplete();
+
+    //
+    // If this is a READ pass, check for errors at the end.
+    //
+    if ((i % 2) == 1)
+    {
+      //
+      // Return immediately if  error.
+      //
+      if (CheckHteErrors())
+      {
+        break;
+      }
+    }
+  }
+
+  DPF(D_INFO, "done\n", i);
+  return CheckHteErrors();
+}
+
+STATIC UINT16 BasicDataCompareHte(
+    MRC_PARAMS *CurrentMrcData,
+    UINT32 Address,
+    UINT8 FirstRun,
+    UINT8 Mode)
+/*++
+
+ Routine Description:
+
+ Execute basic single cache line memory write/read/verify test using simple constant
+ pattern (different for READ_RAIN and WRITE_TRAIN modes.
+ See BasicWriteReadHTE which is external visible wrapper.
+
+ Arguments:
+
+ CurrentMrcData: Host struture for all MRC global data.
+ Address: memory adress being tested (must hit specific channel/rank)
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+ Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
+
+ Returns:
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)
+
+ --*/
+{
+  UINT32 Pattern;
+  UINT32 Offset;
+
+  if (FirstRun)
+  {
+    isbW32m(HTE, 0x00020020, 0x01B10021);
+    isbW32m(HTE, 0x00020021, 0x06000000);
+    isbW32m(HTE, 0x00020022, Address >> 6);
+    isbW32m(HTE, 0x00020062, 0x00800015);
+    isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
+    isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
+    isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
+    isbW32m(HTE, 0x00020061, 0x00030008);
+
+    if (Mode == WRITE_TRAIN)
+    {
+      Pattern = 0xC33C0000;
+    }
+    else // READ_TRAIN
+    {
+      Pattern = 0xAA5555AA;
+    }
+
+    for (Offset = 0x80; Offset <= 0x8F; Offset++)
+    {
+      isbW32m(HTE, Offset, Pattern);
+    }
+  }
+
+  isbW32m(HTE, 0x000200A1, 0xFFFF1000);
+
+  isbW32m(HTE, 0x00020011, 0x00011000);
+  isbW32m(HTE, 0x00020011, 0x00011100);
+
+  WaitForHteComplete();
+
+  //
+  // Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for any bytelane errors.
+  //
+  return ((CheckHteErrors() >> 8) & 0xFF);
+}
+
+STATIC UINT16 ReadWriteDataCompareHte(
+    MRC_PARAMS *CurrentMrcData,
+    UINT32 Address,
+    UINT8 LoopCount,
+    UINT32 LfsrSeedVictim,
+    UINT32 LfsrSeedAggressor,
+    UINT8 VictimBit,
+    UINT8 FirstRun)
+/*++
+
+ Routine Description:
+
+ Examines single cache line memory with write/read/verify test using
+ multiple data patterns (victim-aggressor algorithm).
+ See WriteStressBitLanesHTE which is external visible wrapper.
+
+ Arguments:
+
+ CurrentMrcData: host struture for all MRC global data.
+ Address: memory adress being tested (must hit specific channel/rank)
+ LoopCount: number of test iterations
+ LfsrSeedXxx: victim aggressor data pattern seed
+ VictimBit: should be 0 as auto rotate feature is in use.
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+
+ Returns:
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)
+
+ --*/
+{
+  UINT32 Offset;
+  UINT32 Tmp;
+
+  if (FirstRun)
+  {
+    isbW32m(HTE, 0x00020020, 0x00910024);
+    isbW32m(HTE, 0x00020023, 0x00810024);
+    isbW32m(HTE, 0x00020021, 0x06070000);
+    isbW32m(HTE, 0x00020024, 0x06070000);
+    isbW32m(HTE, 0x00020022, Address >> 6);
+    isbW32m(HTE, 0x00020025, Address >> 6);
+    isbW32m(HTE, 0x00020062, 0x0000002A);
+    isbW32m(HTE, 0x00020063, LfsrSeedVictim);
+    isbW32m(HTE, 0x00020064, LfsrSeedAggressor);
+    isbW32m(HTE, 0x00020065, LfsrSeedVictim);
+
+    //
+    // Write the pattern buffers to select the victim bit. Start with bit0.
+    //
+    for (Offset = 0x80; Offset <= 0x8F; Offset++)
+    {
+      if ((Offset % 8) == VictimBit)
+      {
+        isbW32m(HTE, Offset, 0x55555555);
+      }
+      else
+      {
+        isbW32m(HTE, Offset, 0xCCCCCCCC);
+      }
+    }
+
+    isbW32m(HTE, 0x00020061, 0x00000000);
+    isbW32m(HTE, 0x00020066, 0x03440000);
+    isbW32m(HTE, 0x000200A1, 0xFFFF1000);
+  }
+
+  Tmp = 0x10001000 | (LoopCount << 16);
+  isbW32m(HTE, 0x00020011, Tmp);
+  isbW32m(HTE, 0x00020011, Tmp | BIT8);
+
+  WaitForHteComplete();
+
+  return (CheckHteErrors() >> 8) & 0xFF;
+}
+
+UINT16 BasicWriteReadHTE(
+    MRC_PARAMS *CurrentMrcData,
+    UINT32 Address,
+    UINT8 FirstRun,
+    UINT8 Mode)
+/*++
+
+ Routine Description:
+
+ Execute basic single cache line memory write/read/verify test using simple constant
+ pattern (different for READ_RAIN and WRITE_TRAIN modes.
+
+ Arguments:
+
+ CurrentMrcData: Host struture for all MRC global data.
+ Address: memory adress being tested (must hit specific channel/rank)
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+ Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
+
+ Returns:
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)
+
+ --*/
+{
+  UINT16 ByteLaneErrors;
+
+  ENTERFN();
+
+  //
+  // Enable all error reporting in preparation for HTE test.
+  //
+  EnableAllHteErrors(0xFF);
+  ClearHteErrorRegisters();
+
+  ByteLaneErrors = BasicDataCompareHte(CurrentMrcData, Address, FirstRun,
+      Mode);
+
+  LEAVEFN();
+  return ByteLaneErrors;
+}
+
+UINT16 WriteStressBitLanesHTE(
+    MRC_PARAMS *CurrentMrcData,
+    UINT32 Address,
+    UINT8 FirstRun)
+/*++
+
+ Routine Description:
+
+ Examines single cache line memory with write/read/verify test using
+ multiple data patterns (victim-aggressor algorithm).
+
+ Arguments:
+
+ CurrentMrcData: host struture for all MRC global data.
+ Address: memory adress being tested (must hit specific channel/rank)
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+
+ Returns:
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)
+
+ --*/
+{
+  UINT16 ByteLaneErrors;
+  UINT8 VictimBit = 0;
+
+  ENTERFN();
+
+  //
+  // Enable all error reporting in preparation for HTE test.
+  //
+  EnableAllHteErrors(0xFF);
+  ClearHteErrorRegisters();
+
+  //
+  // Loop through each bit in the bytelane.  Each pass creates a victim bit
+  // while keeping all other bits the same - as aggressors.
+  // AVN HTE adds an auto-rotate feature which allows us to program the entire victim/aggressor
+  // sequence in 1 step. The victim bit rotates on each pass so no need to have software implement
+  // a victim bit loop like on VLV.
+  //
+  ByteLaneErrors = ReadWriteDataCompareHte(CurrentMrcData, Address,
+      HTE_LOOP_CNT, HTE_LFSR_VICTIM_SEED, HTE_LFSR_AGRESSOR_SEED, VictimBit,
+      FirstRun);
+
+  LEAVEFN();
+  return ByteLaneErrors;
+}
+
+VOID HteMemOp(
+    UINT32 Address,
+    UINT8 FirstRun,
+    UINT8 IsWrite)
+/*++
+
+ Routine Description:
+
+ Execute basic single cache line memory write or read.
+ This is just for receive enable / fine write levelling purpose.
+
+ Arguments:
+
+ CurrentMrcData: Host structure for all MRC global data.
+ Address: memory address used (must hit specific channel/rank)
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+ IsWrite: When non-zero memory write operation executed, otherwise read
+
+ Returns:
+ None
+
+ --*/
+{
+  UINT32 Offset;
+  UINT32 Tmp;
+
+  EnableAllHteErrors(0xFF);
+  ClearHteErrorRegisters();
+
+  if (FirstRun)
+  {
+    Tmp = IsWrite ? 0x01110021 : 0x01010021;
+    isbW32m(HTE, 0x00020020, Tmp);
+
+    isbW32m(HTE, 0x00020021, 0x06000000);
+    isbW32m(HTE, 0x00020022, Address >> 6);
+    isbW32m(HTE, 0x00020062, 0x00800015);
+    isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
+    isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
+    isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
+    isbW32m(HTE, 0x00020061, 0x00030008);
+
+    for (Offset = 0x80; Offset <= 0x8F; Offset++)
+    {
+      isbW32m(HTE, Offset, 0xC33C0000);
+    }
+  }
+
+  isbW32m(HTE, 0x000200A1, 0xFFFF1000);
+  isbW32m(HTE, 0x00020011, 0x00011000);
+  isbW32m(HTE, 0x00020011, 0x00011100);
+
+  WaitForHteComplete();
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h
new file mode 100644
index 0000000000..1ad13342af
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h
@@ -0,0 +1,66 @@
+/** @file
+HTE handling routines for MRC use.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __HTE_H
+#define __HTE_H
+
+#define STATIC   static
+#define VOID     void
+
+#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L)
+typedef uint32_t UINT32;
+typedef uint16_t UINT16;
+typedef uint8_t UINT8;
+#endif
+
+typedef enum
+{
+  MrcNoHaltSystemOnError,
+  MrcHaltSystemOnError,
+  MrcHaltHteEngineOnError,
+  MrcNoHaltHteEngineOnError
+} HALT_TYPE;
+
+typedef enum
+{
+  MrcMemInit, MrcMemTest
+} MEM_INIT_OR_TEST;
+
+#define READ_TRAIN      1
+#define WRITE_TRAIN     2
+
+#define HTE_MEMTEST_NUM                 2
+#define HTE_LOOP_CNT                    5  // EXP_LOOP_CNT field of HTE_CMD_CTL. This CANNOT be less than 4
+#define HTE_LFSR_VICTIM_SEED   0xF294BA21  // Random seed for victim.
+#define HTE_LFSR_AGRESSOR_SEED 0xEBA7492D  // Random seed for aggressor.
+UINT32
+HteMemInit(
+    MRC_PARAMS *CurrentMrcData,
+    UINT8 MemInitFlag,
+    UINT8 HaltHteEngineOnError);
+
+UINT16
+BasicWriteReadHTE(
+    MRC_PARAMS *CurrentMrcData,
+    UINT32 Address,
+    UINT8 FirstRun,
+    UINT8 Mode);
+
+UINT16
+WriteStressBitLanesHTE(
+    MRC_PARAMS *CurrentMrcData,
+    UINT32 Address,
+    UINT8 FirstRun);
+
+VOID
+HteMemOp(
+    UINT32 Address,
+    UINT8 FirstRun,
+    UINT8 IsWrite);
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h
new file mode 100644
index 0000000000..e2f7916014
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h
@@ -0,0 +1,132 @@
+/** @file
+Declaration of IO handling routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __IO_H
+#define __IO_H
+
+#include "core_types.h"
+
+#include "general_definitions.h"
+#include "gen5_iosf_sb_definitions.h"
+
+// Instruction not present on Quark
+#define SFENCE()
+
+#define DEAD_LOOP()   for(;;);
+
+////
+// Define each of the IOSF_SB ports used by MRC
+//
+
+//
+// Has to be 0 because of emulation static data
+// initialisation:
+//   Space_t EmuSpace[ SPACE_COUNT] = {0};
+//
+#define FREE                0x000
+
+// Pseudo side-band ports for access abstraction
+// See Wr32/Rd32 functions
+#define MEM                 0x101
+#define MMIO                0x102
+#define DCMD                0x0A0
+
+// Real side-band ports
+// See Wr32/Rd32 functions
+#define MCU                 0x001
+#define HOST_BRIDGE               0x003
+#define MEMORY_MANAGER               0x005
+#define HTE                0x011
+#define DDRPHY              0x012
+#define FUSE                0x033
+
+// End of IOSF_SB ports
+////
+
+// Pciexbar address
+#define EC_BASE          0xE0000000
+
+#define PCIADDR(bus,dev,fn,reg) ( \
+        (EC_BASE) + \
+    ((bus) << 20) + \
+    ((dev) << 15) + \
+    ((fn)  << 12) + \
+    (reg))
+
+// Various offsets used in the building sideband commands.
+#define SB_OPCODE_OFFSET      24
+#define SB_PORT_OFFSET        16
+#define SB_REG_OFFEST          8
+
+// Sideband opcodes
+#define SB_REG_READ_OPCODE        0x10
+#define SB_REG_WRITE_OPCODE       0x11
+
+#define SB_FUSE_REG_READ_OPCODE    0x06
+#define SB_FUSE_REG_WRITE_OPCODE  0x07
+
+#define SB_DDRIO_REG_READ_OPCODE  0x06
+#define SB_DDRIO_REG_WRITE_OPCODE 0x07
+
+#define SB_DRAM_CMND_OPCODE       0x68
+#define SB_WAKE_CMND_OPCODE       0xCA
+#define SB_SUSPEND_CMND_OPCODE    0xCC
+
+// Register addresses for sideband command and data.
+#define SB_PACKET_REG        0x00D0
+#define SB_DATA_REG          0x00D4
+#define SB_HADR_REG          0x00D8
+
+// We always flag all 4 bytes in the register reads/writes as required.
+#define SB_ALL_BYTES_ENABLED  0xF0
+
+#define SB_COMMAND(Opcode, Port, Reg)  \
+ ((Opcode << SB_OPCODE_OFFSET) |  \
+  (Port   << SB_PORT_OFFSET) |  \
+  (Reg    << SB_REG_OFFEST) |  \
+   SB_ALL_BYTES_ENABLED)
+
+// iosf
+#define isbM32m   WrMask32
+#define isbW32m   Wr32
+#define isbR32m   Rd32
+
+// pci
+
+void pciwrite32(
+    uint32_t bus,
+    uint32_t dev,
+    uint32_t fn,
+    uint32_t reg,
+    uint32_t data);
+
+uint32_t pciread32(
+    uint32_t bus,
+    uint32_t dev,
+    uint32_t fn,
+    uint32_t reg);
+
+// general
+
+uint32_t Rd32(
+    uint32_t unit,
+    uint32_t addr);
+
+void Wr32(
+    uint32_t unit,
+    uint32_t addr,
+    uint32_t data);
+
+void WrMask32(
+    uint32_t unit,
+    uint32_t addr,
+    uint32_t data,
+    uint32_t mask);
+
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c
new file mode 100644
index 0000000000..21d935bc65
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c
@@ -0,0 +1,382 @@
+/** @file
+Serial conole output and string formating.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "memory_options.h"
+#include "general_definitions.h"
+
+// Resource programmed to PCI bridge, 1MB bound alignment is needed.
+// The default value is overwritten by MRC parameter, assuming code
+// relocated to eSRAM.
+uint32_t UartMmioBase = 0;
+
+// Serial port registers based on SerialPortLib.c
+#define R_UART_BAUD_THR       0
+#define R_UART_LSR            20
+
+#define   B_UART_LSR_RXRDY    BIT0
+#define   B_UART_LSR_TXRDY    BIT5
+#define   B_UART_LSR_TEMT     BIT6
+
+// Print mask see DPF and D_Xxxx
+#define DPF_MASK  DpfPrintMask
+
+// Select class of messages enabled for printing
+uint32_t DpfPrintMask =
+    D_ERROR |
+    D_INFO |
+    // D_REGRD |
+    // D_REGWR |
+    // D_FCALL |
+    // D_TRN |
+    0;
+
+#ifdef NDEBUG
+// Don't generate debug code
+void dpf( uint32_t mask, char_t* bla, ...)
+{
+  return;
+}
+
+uint8_t mgetc(void)
+{
+  return 0;
+}
+
+uint8_t mgetch(void)
+{
+  return 0;
+}
+
+#else
+
+#ifdef SIM
+// Use Vpi console in simulation environment
+#include <vpi_user.h>
+
+void dpf( uint32_t mask, char_t* bla, ...)
+{
+  va_list va;
+
+  if( 0 == (mask & DPF_MASK)) return;
+
+  va_start( va, bla);
+  vpi_vprintf( bla, va);
+  va_end(va);
+}
+
+#else
+
+#ifdef EMU
+// Use standard console in windows environment
+#include <stdio.h>
+#endif
+
+// Read character from serial port
+uint8_t mgetc(void)
+{
+#ifdef EMU
+
+  // Emulation in Windows environment uses console
+  getchar();
+
+#else
+  uint8_t c;
+
+  while ((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) == 0);
+  c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
+
+  return c;
+#endif
+}
+
+
+uint8_t mgetch(void)
+{
+#ifdef EMU
+  return 0;
+#else
+  uint8_t c = 0;
+
+  if((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) != 0)
+  {
+    c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
+  }
+
+  return c;
+#endif
+}
+
+// Print single character
+static void printc(
+    uint8_t c)
+{
+#ifdef EMU
+
+  // Emulation in Windows environment uses console output
+  putchar(c);
+
+#else
+
+  //
+  // Use MMIO access to serial port on PCI
+  //   while( 0 == (0x20 & inp(0x3f8 + 5)));
+  //   outp(0x3f8 + 0, c);
+  //
+  while (0
+      == (B_UART_LSR_TEMT & *((volatile uint8_t*) (UartMmioBase + R_UART_LSR))))
+    ;
+  *((volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR)) = c;
+#endif
+}
+
+// Print 0 terminated string on serial console
+static void printstr(
+    char_t *str)
+{
+  while (*str)
+  {
+    printc(*str++);
+  }
+}
+// Print 64bit number as hex string on serial console
+// the width parameters allows skipping leading zeros
+static void printhexx(
+    uint64_t val,
+    uint32_t width)
+{
+  uint32_t i;
+  uint8_t c;
+  uint8_t empty = 1;
+
+  // 64bit number has 16 characters in hex representation
+  for (i = 16; i > 0; i--)
+  {
+    c = *(((uint8_t *)&val) + ((i - 1) >> 1));
+    if (((i - 1) & 1) != 0)
+      c = c >> 4;
+    c = c & 0x0F;
+
+    if (c > 9)
+      c += 'A' - 10;
+    else
+      c += '0';
+
+    if (c != '0')
+    {
+      // end of leading zeros
+      empty = 0;
+    }
+
+    // don't print leading zero
+    if (!empty || i <= width)
+    {
+      printc(c);
+    }
+  }
+}
+// Print 32bit number as hex string on serial console
+// the width parameters allows skipping leading zeros
+static void printhex(
+    uint32_t val,
+    uint32_t width)
+{
+  uint32_t i;
+  uint8_t c;
+  uint8_t empty = 1;
+
+  // 32bit number has 8 characters in hex representation
+  for (i = 8; i > 0; i--)
+  {
+    c = (uint8_t) ((val >> 28) & 0x0F);
+    if (c > 9)
+      c += 'A' - 10;
+    else
+      c += '0';
+
+    val = val << 4;
+
+    if (c != '0')
+    {
+      // end of leading zeros
+      empty = 0;
+    }
+
+    // don't print leading zero
+    if (!empty || i <= width)
+    {
+      printc(c);
+    }
+  }
+}
+// Print 32bit number as decimal string on serial console
+// the width parameters allows skipping leading zeros
+static void printdec(
+    uint32_t val,
+    uint32_t width)
+{
+  uint32_t i;
+  uint8_t c = 0;
+  uint8_t empty = 1;
+
+  // Ten digits is enough for 32bit number in decimal
+  uint8_t buf[10];
+
+  for (i = 0; i < sizeof(buf); i++)
+  {
+    c = (uint8_t) (val % 10);
+    buf[i] = c + '0';
+    val = val / 10;
+  }
+
+  while (i > 0)
+  {
+    c = buf[--i];
+
+    if (c != '0')
+    {
+      // end of leading zeros
+      empty = 0;
+    }
+
+    // don't print leading zero
+    if (!empty || i < width)
+    {
+      printc(c);
+    }
+  }
+}
+
+// Consume numeric substring leading the given string
+// Return pointer to the first non-numeric character
+// Buffer reference by width is updated with number
+// converted from the numeric substring.
+static char_t *getwidth(
+    char_t *bla,
+    uint32_t *width)
+{
+  uint32_t val = 0;
+
+  while (*bla >= '0' && *bla <= '9')
+  {
+    val = val * 10 + *bla - '0';
+    bla += 1;
+  }
+
+  if (val > 0)
+  {
+    *width = val;
+  }
+  return bla;
+}
+
+// Consume print format designator from the head of given string
+// Return pointer to first character after format designator
+// input fmt
+// ----- ---
+//  s   -> s
+//  d   -> d
+//  X   -> X
+//  llX -> L
+static char_t *getformat(
+    char_t *bla,
+    uint8_t *fmt)
+{
+  if (bla[0] == 's')
+  {
+    bla += 1;
+    *fmt = 's';
+  }
+  else if (bla[0] == 'd')
+  {
+    bla += 1;
+    *fmt = 'd';
+  }
+  else if (bla[0] == 'X' || bla[0] == 'x')
+  {
+    bla += 1;
+    *fmt = 'X';
+  }
+  else if (bla[0] == 'l' && bla[1] == 'l' && bla[2] == 'X')
+  {
+    bla += 3;
+    *fmt = 'L';
+  }
+
+  return bla;
+}
+
+// Simplified implementation of standard printf function
+// The output is directed to serial console. Only selected
+// class of messages is printed (mask has to match DpfPrintMask)
+// Supported print formats: %[n]s,%[n]d,%[n]X,,%[n]llX
+// The width is ignored for %s format.
+void dpf(
+    uint32_t mask,
+    char_t* bla,
+    ...)
+{
+  uint32_t* arg = (uint32_t*) (&bla + 1);
+
+  // Check UART MMIO base configured
+  if (0 == UartMmioBase)
+    return;
+
+  // Check event not masked
+  if (0 == (mask & DPF_MASK))
+    return;
+
+  for (;;)
+  {
+    uint8_t x = *bla++;
+    if (x == 0)
+      break;
+
+    if (x == '\n')
+    {
+      printc('\r');
+      printc('\n');
+    }
+    else if (x == '%')
+    {
+      uint8_t fmt = 0;
+      uint32_t width = 1;
+
+      bla = getwidth(bla, &width);
+      bla = getformat(bla, &fmt);
+
+      // Print value
+      if (fmt == 'd')
+      {
+        printdec(*arg, width);
+        arg += 1;
+      }
+      else if (fmt == 'X')
+      {
+        printhex(*arg, width);
+        arg += 1;
+      }
+      else if (fmt == 'L')
+      {
+        printhexx(*(uint64_t*) arg, width);
+        arg += 2;
+      }
+      else if (fmt == 's')
+      {
+        printstr(*(char**) arg);
+        arg += 1;
+      }
+    }
+    else
+    {
+      printc(x);
+    }
+  }
+}
+
+#endif  //SIM
+#endif  //NDEBUG
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c
new file mode 100644
index 0000000000..64f0a1130e
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c
@@ -0,0 +1,2638 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ * This file contains all of the Cat Mountain Memory Reference Code (MRC).
+ *
+ * These functions are generic and should work for any Cat Mountain config.
+ *
+ * MRC requires two data structures to be passed in which are initialised by "PreMemInit()".
+ *
+ * The basic flow is as follows:
+ * 01) Check for supported DDR speed configuration
+ * 02) Set up MEMORY_MANAGER buffer as pass-through (POR)
+ * 03) Set Channel Interleaving Mode and Channel Stride to the most aggressive setting possible
+ * 04) Set up the MCU logic
+ * 05) Set up the DDR_PHY logic
+ * 06) Initialise the DRAMs (JEDEC)
+ * 07) Perform the Receive Enable Calibration algorithm
+ * 08) Perform the Write Leveling algorithm
+ * 09) Perform the Read Training algorithm (includes internal Vref)
+ * 10) Perform the Write Training algorithm
+ * 11) Set Channel Interleaving Mode and Channel Stride to the desired settings
+ *
+ * Dunit configuration based on Valleyview MRC.
+ *
+ ***************************************************************************/
+
+#include "mrc.h"
+#include "memory_options.h"
+
+#include "meminit.h"
+#include "meminit_utils.h"
+#include "hte.h"
+#include "io.h"
+
+// Override ODT to off state if requested
+#define DRMC_DEFAULT    (mrc_params->rd_odt_value==0?BIT12:0)
+
+
+// tRFC values (in picoseconds) per density
+const uint32_t tRFC[5] =
+{
+    90000,  // 512Mb
+    110000, // 1Gb
+    160000, // 2Gb
+    300000, // 4Gb
+    350000, // 8Gb
+    };
+
+// tCK clock period in picoseconds per speed index 800, 1066, 1333
+const uint32_t tCK[3] =
+{
+    2500,
+    1875,
+    1500
+};
+
+#ifdef SIM
+// Select static timings specific to simulation environment
+#define PLATFORM_ID    0
+#else
+// Select static timings specific to ClantonPeek platform
+#define PLATFORM_ID    1
+#endif
+
+
+// Global variables
+const uint16_t ddr_wclk[] =
+    {193, 158};
+
+const uint16_t ddr_wctl[] =
+    {  1, 217};
+
+const uint16_t ddr_wcmd[] =
+    {  1, 220};
+
+
+#ifdef BACKUP_RCVN
+const uint16_t ddr_rcvn[] =
+    {129, 498};
+#endif // BACKUP_RCVN
+
+#ifdef BACKUP_WDQS
+const uint16_t ddr_wdqs[] =
+    { 65, 289};
+#endif // BACKUP_WDQS
+
+#ifdef BACKUP_RDQS
+const uint8_t ddr_rdqs[] =
+    { 32,  24};
+#endif // BACKUP_RDQS
+
+#ifdef BACKUP_WDQ
+const uint16_t ddr_wdq[] =
+    { 32, 257};
+#endif // BACKUP_WDQ
+
+
+
+// Select MEMORY_MANAGER as the source for PRI interface
+static void select_memory_manager(
+    MRCParams_t *mrc_params)
+{
+  RegDCO Dco;
+
+  ENTERFN();
+
+  Dco.raw = isbR32m(MCU, DCO);
+  Dco.field.PMICTL = 0;          //0 - PRI owned by MEMORY_MANAGER
+  isbW32m(MCU, DCO, Dco.raw);
+
+  LEAVEFN();
+}
+
+// Select HTE as the source for PRI interface
+void select_hte(
+    MRCParams_t *mrc_params)
+{
+  RegDCO Dco;
+
+  ENTERFN();
+
+  Dco.raw = isbR32m(MCU, DCO);
+  Dco.field.PMICTL = 1;          //1 - PRI owned by HTE
+  isbW32m(MCU, DCO, Dco.raw);
+
+  LEAVEFN();
+}
+
+// Send DRAM command, data should be formated
+// using DCMD_Xxxx macro or emrsXCommand structure.
+static void dram_init_command(
+    uint32_t data)
+{
+  Wr32(DCMD, 0, data);
+}
+
+// Send DRAM wake command using special MCU side-band WAKE opcode
+static void dram_wake_command(
+    void)
+{
+  ENTERFN();
+
+  Wr32(MMIO, PCIADDR(0,0,0,SB_PACKET_REG),
+      (uint32_t) SB_COMMAND(SB_WAKE_CMND_OPCODE, MCU, 0));
+
+  LEAVEFN();
+}
+
+// Stop self refresh driven by MCU
+static void clear_self_refresh(
+    MRCParams_t *mrc_params)
+{
+  ENTERFN();
+
+  // clear the PMSTS Channel Self Refresh bits
+  isbM32m(MCU, PMSTS, BIT0, BIT0);
+
+  LEAVEFN();
+}
+
+// Configure MCU before jedec init sequence
+static void prog_decode_before_jedec(
+    MRCParams_t *mrc_params)
+{
+  RegDRP Drp;
+  RegDRCF Drfc;
+  RegDCAL Dcal;
+  RegDSCH Dsch;
+  RegDPMC0 Dpmc0;
+
+  ENTERFN();
+
+  // Disable power saving features
+  Dpmc0.raw = isbR32m(MCU, DPMC0);
+  Dpmc0.field.CLKGTDIS = 1;
+  Dpmc0.field.DISPWRDN = 1;
+  Dpmc0.field.DYNSREN = 0;
+  Dpmc0.field.PCLSTO = 0;
+  isbW32m(MCU, DPMC0, Dpmc0.raw);
+
+  // Disable out of order transactions
+  Dsch.raw = isbR32m(MCU, DSCH);
+  Dsch.field.OOODIS = 1;
+  Dsch.field.NEWBYPDIS = 1;
+  isbW32m(MCU, DSCH, Dsch.raw);
+
+  // Disable issuing the REF command
+  Drfc.raw = isbR32m(MCU, DRFC);
+  Drfc.field.tREFI = 0;
+  isbW32m(MCU, DRFC, Drfc.raw);
+
+  // Disable ZQ calibration short
+  Dcal.raw = isbR32m(MCU, DCAL);
+  Dcal.field.ZQCINT = 0;
+  Dcal.field.SRXZQCL = 0;
+  isbW32m(MCU, DCAL, Dcal.raw);
+
+  // Training performed in address mode 0, rank population has limited impact, however
+  // simulator complains if enabled non-existing rank.
+  Drp.raw = 0;
+  if (mrc_params->rank_enables & 1)
+    Drp.field.rank0Enabled = 1;
+  if (mrc_params->rank_enables & 2)
+    Drp.field.rank1Enabled = 1;
+  isbW32m(MCU, DRP, Drp.raw);
+
+  LEAVEFN();
+}
+
+// After Cold Reset, BIOS should set COLDWAKE bit to 1 before
+// sending the WAKE message to the Dunit.
+// For Standby Exit, or any other mode in which the DRAM is in
+// SR, this bit must be set to 0.
+static void perform_ddr_reset(
+    MRCParams_t *mrc_params)
+{
+  ENTERFN();
+
+  // Set COLDWAKE bit before sending the WAKE message
+  isbM32m(MCU, DRMC, BIT16, BIT16);
+
+  // Send wake command to DUNIT (MUST be done before JEDEC)
+  dram_wake_command();
+
+  // Set default value
+  isbW32m(MCU, DRMC, DRMC_DEFAULT);
+
+  LEAVEFN();
+}
+
+// Dunit Initialisation Complete.
+// Indicates that initialisation of the Dunit has completed.
+// Memory accesses are permitted and maintenance operation
+// begins. Until this bit is set to a 1, the memory controller will
+// not accept DRAM requests from the MEMORY_MANAGER or HTE.
+static void set_ddr_init_complete(
+    MRCParams_t *mrc_params)
+{
+  RegDCO Dco;
+
+  ENTERFN();
+
+  Dco.raw = isbR32m(MCU, DCO);
+  Dco.field.PMICTL = 0;          //0 - PRI owned by MEMORY_MANAGER
+  Dco.field.IC = 1;              //1 - initialisation complete
+  isbW32m(MCU, DCO, Dco.raw);
+
+  LEAVEFN();
+}
+
+static void prog_page_ctrl(
+    MRCParams_t *mrc_params)
+{
+  RegDPMC0 Dpmc0;
+
+  ENTERFN();
+
+  Dpmc0.raw = isbR32m(MCU, DPMC0);
+
+  Dpmc0.field.PCLSTO = 0x4;
+  Dpmc0.field.PREAPWDEN = 1;
+
+  isbW32m(MCU, DPMC0, Dpmc0.raw);
+}
+
+// Configure MCU Power Management Control Register
+// and Scheduler Control Register.
+static void prog_ddr_control(
+    MRCParams_t *mrc_params)
+{
+  RegDSCH Dsch;
+  RegDPMC0 Dpmc0;
+
+  ENTERFN();
+
+  Dpmc0.raw = isbR32m(MCU, DPMC0);
+  Dsch.raw = isbR32m(MCU, DSCH);
+
+  Dpmc0.field.DISPWRDN = mrc_params->power_down_disable;
+  Dpmc0.field.CLKGTDIS = 0;
+  Dpmc0.field.PCLSTO = 4;
+  Dpmc0.field.PREAPWDEN = 1;
+
+  Dsch.field.OOODIS = 0;
+  Dsch.field.OOOST3DIS = 0;
+  Dsch.field.NEWBYPDIS = 0;
+
+  isbW32m(MCU, DSCH, Dsch.raw);
+  isbW32m(MCU, DPMC0, Dpmc0.raw);
+
+  // CMDTRIST = 2h - CMD/ADDR are tristated when no valid command
+  isbM32m(MCU, DPMC1, 2 << 4, BIT5|BIT4);
+
+  LEAVEFN();
+}
+
+// After training complete configure MCU Rank Population Register
+// specifying: ranks enabled, device width, density, address mode.
+static void prog_dra_drb(
+    MRCParams_t *mrc_params)
+{
+  RegDRP Drp;
+  RegDCO Dco;
+
+  ENTERFN();
+
+  Dco.raw = isbR32m(MCU, DCO);
+  Dco.field.IC = 0;
+  isbW32m(MCU, DCO, Dco.raw);
+
+  Drp.raw = 0;
+  if (mrc_params->rank_enables & 1)
+    Drp.field.rank0Enabled = 1;
+  if (mrc_params->rank_enables & 2)
+    Drp.field.rank1Enabled = 1;
+  if (mrc_params->dram_width == x16)
+  {
+    Drp.field.dimm0DevWidth = 1;
+    Drp.field.dimm1DevWidth = 1;
+  }
+  // Density encoding in DRAMParams_t 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
+  // has to be mapped RANKDENSx encoding (0=1Gb)
+  Drp.field.dimm0DevDensity = mrc_params->params.DENSITY - 1;
+  Drp.field.dimm1DevDensity = mrc_params->params.DENSITY - 1;
+
+  // Address mode can be overwritten if ECC enabled
+  Drp.field.addressMap = mrc_params->address_mode;
+
+  isbW32m(MCU, DRP, Drp.raw);
+
+  Dco.field.PMICTL = 0;          //0 - PRI owned by MEMORY_MANAGER
+  Dco.field.IC = 1;              //1 - initialisation complete
+  isbW32m(MCU, DCO, Dco.raw);
+
+  LEAVEFN();
+}
+
+// Configure refresh rate and short ZQ calibration interval.
+// Activate dynamic self refresh.
+static void change_refresh_period(
+    MRCParams_t *mrc_params)
+{
+  RegDRCF Drfc;
+  RegDCAL Dcal;
+  RegDPMC0 Dpmc0;
+
+  ENTERFN();
+
+  Drfc.raw = isbR32m(MCU, DRFC);
+  Drfc.field.tREFI = mrc_params->refresh_rate;
+  Drfc.field.REFDBTCLR = 1;
+  isbW32m(MCU, DRFC, Drfc.raw);
+
+  Dcal.raw = isbR32m(MCU, DCAL);
+  Dcal.field.ZQCINT = 3; // 63ms
+  isbW32m(MCU, DCAL, Dcal.raw);
+
+  Dpmc0.raw = isbR32m(MCU, DPMC0);
+  Dpmc0.field.ENPHYCLKGATE = 1;
+  Dpmc0.field.DYNSREN = 1;
+  isbW32m(MCU, DPMC0, Dpmc0.raw);
+
+  LEAVEFN();
+}
+
+// Send DRAM wake command
+static void perform_wake(
+    MRCParams_t *mrc_params)
+{
+  ENTERFN();
+
+  dram_wake_command();
+
+  LEAVEFN();
+}
+
+// prog_ddr_timing_control (aka mcu_init):
+// POST_CODE[major] == 0x02
+//
+// It will initialise timing registers in the MCU (DTR0..DTR4).
+static void prog_ddr_timing_control(
+    MRCParams_t *mrc_params)
+{
+  uint8_t TCL, WL;
+  uint8_t TRP, TRCD, TRAS, TWR, TWTR, TRRD, TRTP, TFAW;
+  uint32_t TCK;
+
+  RegDTR0 Dtr0;
+  RegDTR1 Dtr1;
+  RegDTR2 Dtr2;
+  RegDTR3 Dtr3;
+  RegDTR4 Dtr4;
+
+  ENTERFN();
+
+  // mcu_init starts
+  post_code(0x02, 0x00);
+
+  Dtr0.raw = isbR32m(MCU, DTR0);
+  Dtr1.raw = isbR32m(MCU, DTR1);
+  Dtr2.raw = isbR32m(MCU, DTR2);
+  Dtr3.raw = isbR32m(MCU, DTR3);
+  Dtr4.raw = isbR32m(MCU, DTR4);
+
+  TCK = tCK[mrc_params->ddr_speed];  // Clock in picoseconds
+  TCL = mrc_params->params.tCL;      // CAS latency in clocks
+  TRP = TCL;  // Per CAT MRC
+  TRCD = TCL;  // Per CAT MRC
+  TRAS = MCEIL(mrc_params->params.tRAS, TCK);
+  TWR = MCEIL(15000, TCK);   // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600
+
+  TWTR = MCEIL(mrc_params->params.tWTR, TCK);
+  TRRD = MCEIL(mrc_params->params.tRRD, TCK);
+  TRTP = 4;  // Valid for 800 and 1066, use 5 for 1333
+  TFAW = MCEIL(mrc_params->params.tFAW, TCK);
+
+  WL = 5 + mrc_params->ddr_speed;
+
+  Dtr0.field.dramFrequency = mrc_params->ddr_speed;
+
+  Dtr0.field.tCL = TCL - 5;            //Convert from TCL (DRAM clocks) to VLV indx
+  Dtr0.field.tRP = TRP - 5;            //5 bit DRAM Clock
+  Dtr0.field.tRCD = TRCD - 5;          //5 bit DRAM Clock
+
+  Dtr1.field.tWCL = WL - 3;            //Convert from WL (DRAM clocks)  to VLV indx
+  Dtr1.field.tWTP = WL + 4 + TWR - 14;  //Change to tWTP
+  Dtr1.field.tRTP = MMAX(TRTP, 4) - 3;  //4 bit DRAM Clock
+  Dtr1.field.tRRD = TRRD - 4;        //4 bit DRAM Clock
+  Dtr1.field.tCMD = 1;             //2N
+  Dtr1.field.tRAS = TRAS - 14;      //6 bit DRAM Clock
+
+  Dtr1.field.tFAW = ((TFAW + 1) >> 1) - 5;    //4 bit DRAM Clock
+  Dtr1.field.tCCD = 0;                        //Set 4 Clock CAS to CAS delay (multi-burst)
+  Dtr2.field.tRRDR = 1;
+  Dtr2.field.tWWDR = 2;
+  Dtr2.field.tRWDR = 2;
+  Dtr3.field.tWRDR = 2;
+  Dtr3.field.tWRDD = 2;
+
+  if (mrc_params->ddr_speed == DDRFREQ_800)
+  {
+     // Extended RW delay (+1)
+     Dtr3.field.tRWSR = TCL - 5 + 1;
+  }
+  else if(mrc_params->ddr_speed == DDRFREQ_1066)
+  {
+     // Extended RW delay (+1)
+     Dtr3.field.tRWSR = TCL - 5 + 1;
+  }
+
+  Dtr3.field.tWRSR = 4 + WL + TWTR - 11;
+
+  if (mrc_params->ddr_speed == DDRFREQ_800)
+  {
+    Dtr3.field.tXP = MMAX(0, 1 - Dtr1.field.tCMD);
+  }
+  else
+  {
+    Dtr3.field.tXP = MMAX(0, 2 - Dtr1.field.tCMD);
+  }
+
+  Dtr4.field.WRODTSTRT = Dtr1.field.tCMD;
+  Dtr4.field.WRODTSTOP = Dtr1.field.tCMD;
+  Dtr4.field.RDODTSTRT = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2; //Convert from WL (DRAM clocks)  to VLV indx
+  Dtr4.field.RDODTSTOP = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2;
+  Dtr4.field.TRGSTRDIS = 0;
+  Dtr4.field.ODTDIS = 0;
+
+  isbW32m(MCU, DTR0, Dtr0.raw);
+  isbW32m(MCU, DTR1, Dtr1.raw);
+  isbW32m(MCU, DTR2, Dtr2.raw);
+  isbW32m(MCU, DTR3, Dtr3.raw);
+  isbW32m(MCU, DTR4, Dtr4.raw);
+
+  LEAVEFN();
+}
+
+// ddrphy_init:
+// POST_CODE[major] == 0x03
+//
+// This function performs some initialisation on the DDRIO unit.
+// This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.
+static void ddrphy_init(MRCParams_t *mrc_params)
+{
+  uint32_t tempD; // temporary DWORD
+  uint8_t channel_i; // channel counter
+  uint8_t rank_i; // rank counter
+  uint8_t bl_grp_i; // byte lane group counter (2 BLs per module)
+
+  uint8_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/1; // byte lane divisor
+  uint8_t speed = mrc_params->ddr_speed & (BIT1|BIT0); // For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333
+  uint8_t tCAS;
+  uint8_t tCWL;
+
+  ENTERFN();
+
+  tCAS = mrc_params->params.tCL;
+  tCWL = 5 + mrc_params->ddr_speed;
+
+  // ddrphy_init starts
+  post_code(0x03, 0x00);
+
+  // HSD#231531
+  // Make sure IOBUFACT is deasserted before initialising the DDR PHY.
+  // HSD#234845
+  // Make sure WRPTRENABLE is deasserted before initialising the DDR PHY.
+  for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+    if (mrc_params->channel_enables & (1<<channel_i)) {
+      // Deassert DDRPHY Initialisation Complete
+      isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT20, BIT20); // SPID_INIT_COMPLETE=0
+      // Deassert IOBUFACT
+      isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT2, BIT2); // IOBUFACTRST_N=0
+      // Disable WRPTR
+      isbM32m(DDRPHY, (CMDPTRREG + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT0, BIT0); // WRPTRENABLE=0
+    } // if channel enabled
+  } // channel_i loop
+
+  // Put PHY in reset
+  isbM32m(DDRPHY, MASTERRSTN, 0, BIT0); // PHYRSTN=0
+
+  // Initialise DQ01,DQ23,CMD,CLK-CTL,COMP modules
+  // STEP0:
+  post_code(0x03, 0x10);
+  for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+    if (mrc_params->channel_enables & (1<<channel_i)) {
+
+      // DQ01-DQ23
+      for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+        isbM32m(DDRPHY, (DQOBSCKEBBCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((bl_grp_i) ? (0x00) : (BIT22)), (BIT22)); // Analog MUX select - IO2xCLKSEL
+
+        // ODT Strength
+        switch (mrc_params->rd_odt_value) {
+          case 1: tempD = 0x3; break; // 60 ohm
+          case 2: tempD = 0x3; break; // 120 ohm
+          case 3: tempD = 0x3; break; // 180 ohm
+          default: tempD = 0x3; break; // 120 ohm
+        }
+        isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD<<5), (BIT6|BIT5)); // ODT strength
+        isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD<<5), (BIT6|BIT5)); // ODT strength
+        // Dynamic ODT/DIFFAMP
+        tempD = (((tCAS)<<24)|((tCAS)<<16)|((tCAS)<<8)|((tCAS)<<0));
+        switch (speed) {
+          case 0: tempD -= 0x01010101; break; // 800
+          case 1: tempD -= 0x02020202; break; // 1066
+          case 2: tempD -= 0x03030303; break; // 1333
+          case 3: tempD -= 0x04040404; break; // 1600
+        }
+        isbM32m(DDRPHY, (B01LATCTL1 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // Launch Time: ODT, DIFFAMP, ODT, DIFFAMP
+        switch (speed) {
+          // HSD#234715
+          case 0: tempD = ((0x06<<16)|(0x07<<8)); break; // 800
+          case 1: tempD = ((0x07<<16)|(0x08<<8)); break; // 1066
+          case 2: tempD = ((0x09<<16)|(0x0A<<8)); break; // 1333
+          case 3: tempD = ((0x0A<<16)|(0x0B<<8)); break; // 1600
+        }
+        isbM32m(DDRPHY, (B0ONDURCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT13|BIT12|BIT11|BIT10|BIT9|BIT8))); // On Duration: ODT, DIFFAMP
+        isbM32m(DDRPHY, (B1ONDURCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT13|BIT12|BIT11|BIT10|BIT9|BIT8))); // On Duration: ODT, DIFFAMP
+
+        switch (mrc_params->rd_odt_value) {
+          case 0:  tempD = ((0x3F<<16)|(0x3f<<10)); break; // override DIFFAMP=on, ODT=off
+          default: tempD = ((0x3F<<16)|(0x2A<<10)); break; // override DIFFAMP=on, ODT=on
+        }
+        isbM32m(DDRPHY, (B0OVRCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT
+        isbM32m(DDRPHY, (B1OVRCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT
+
+        // DLL Setup
+        // 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO)
+        isbM32m(DDRPHY, (B0LATCTL0 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (((tCAS+7)<<16)|((tCAS-4)<<8)|((tCWL-2)<<0)), ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // 1xCLK: tEDP, RCVEN, WDQS
+        isbM32m(DDRPHY, (B1LATCTL0 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (((tCAS+7)<<16)|((tCAS-4)<<8)|((tCWL-2)<<0)), ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // 1xCLK: tEDP, RCVEN, WDQS
+
+        // RCVEN Bypass (PO)
+        isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x0<<7)|(0x0<<0)), (BIT7|BIT0)); // AFE Bypass, RCVEN DIFFAMP
+        isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x0<<7)|(0x0<<0)), (BIT7|BIT0)); // AFE Bypass, RCVEN DIFFAMP
+        // TX
+        isbM32m(DDRPHY, (DQCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT16), (BIT16)); // 0 means driving DQ during DQS-preamble
+        isbM32m(DDRPHY, (B01PTRCTL1 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT8), (BIT8)); // WR_LVL mode disable
+        // RX (PO)
+        isbM32m(DDRPHY, (B0VREFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x03<<2)|(0x0<<1)|(0x0<<0)), ((BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|BIT1|BIT0)); // Internal Vref Code, Enable#, Ext_or_Int (1=Ext)
+        isbM32m(DDRPHY, (B1VREFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x03<<2)|(0x0<<1)|(0x0<<0)), ((BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|BIT1|BIT0)); // Internal Vref Code, Enable#, Ext_or_Int (1=Ext)
+        isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (0), (BIT4)); // Per-Bit De-Skew Enable
+        isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (0), (BIT4)); // Per-Bit De-Skew Enable
+      }
+      // CLKEBB
+      isbM32m(DDRPHY, (CMDOBSCKEBBCTL + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT23));
+
+      // Enable tristate control of cmd/address bus
+      isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT1|BIT0));
+
+      // ODT RCOMP
+      isbM32m(DDRPHY, (CMDRCOMPODT + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x03<<5)|(0x03<<0)), ((BIT9|BIT8|BIT7|BIT6|BIT5)|(BIT4|BIT3|BIT2|BIT1|BIT0)));
+
+      // CMDPM* registers must be programmed in this order...
+      isbM32m(DDRPHY, (CMDPMDLYREG4 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFFFU<<16)|(0xFFFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8|BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Turn On Delays: SFR (regulator), MPLL
+      isbM32m(DDRPHY, (CMDPMDLYREG3 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFU<<28)|(0xFFF<<16)|(0xF<<12)|(0x616<<0)), ((BIT31|BIT30|BIT29|BIT28)|(BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8|BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Delays: ASSERT_IOBUFACT_to_ALLON0_for_PM_MSG_3, VREG (MDLL) Turn On, ALLON0_to_DEASSERT_IOBUFACT_for_PM_MSG_gt0, MDLL Turn On
+      isbM32m(DDRPHY, (CMDPMDLYREG2 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFU<<24)|(0xFF<<16)|(0xFF<<8)|(0xFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // MPLL Divider Reset Delays
+      isbM32m(DDRPHY, (CMDPMDLYREG1 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFU<<24)|(0xFF<<16)|(0xFF<<8)|(0xFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Turn Off Delays: VREG, Staggered MDLL, MDLL, PI
+      isbM32m(DDRPHY, (CMDPMDLYREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFU<<24)|(0xFF<<16)|(0xFF<<8)|(0xFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Turn On Delays: MPLL, Staggered MDLL, PI, IOBUFACT
+      isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x6<<8)|BIT6|(0x4<<0)), (BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|(BIT11|BIT10|BIT9|BIT8)|BIT6|(BIT3|BIT2|BIT1|BIT0))); // Allow PUnit signals
+      isbM32m(DDRPHY, (CMDMDLLCTL +   (channel_i * DDRIOCCC_CH_OFFSET)), ((0x3<<4)|(0x7<<0)), ((BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // DLL_VREG Bias Trim, VREF Tuning for DLL_VREG
+      // CLK-CTL
+      isbM32m(DDRPHY, (CCOBSCKEBBCTL + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT24)); // CLKEBB
+      isbM32m(DDRPHY, (CCCFGREG0 +     (channel_i * DDRIOCCC_CH_OFFSET)), ((0x0<<16)|(0x0<<12)|(0x0<<8)|(0xF<<4)|BIT0), ((BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|BIT0)); // Buffer Enable: CS,CKE,ODT,CLK
+      isbM32m(DDRPHY, (CCRCOMPODT +    (channel_i * DDRIOCCC_CH_OFFSET)), ((0x03<<8)|(0x03<<0)), ((BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT RCOMP
+      isbM32m(DDRPHY, (CCMDLLCTL +     (channel_i * DDRIOCCC_CH_OFFSET)), ((0x3<<4)|(0x7<<0)), ((BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // DLL_VREG Bias Trim, VREF Tuning for DLL_VREG
+
+      // COMP (RON channel specific)
+      // - DQ/DQS/DM RON: 32 Ohm
+      // - CTRL/CMD RON: 27 Ohm
+      // - CLK RON: 26 Ohm
+      isbM32m(DDRPHY, (DQVREFCH0 +  (channel_i * DDRCOMP_CH_OFFSET)), ((0x08<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)));  // RCOMP Vref PU/PD
+      isbM32m(DDRPHY, (CMDVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0C<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)));  // RCOMP Vref PU/PD
+      isbM32m(DDRPHY, (CLKVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0F<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)));  // RCOMP Vref PU/PD
+      isbM32m(DDRPHY, (DQSVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x08<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)));  // RCOMP Vref PU/PD
+      isbM32m(DDRPHY, (CTLVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0C<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)));  // RCOMP Vref PU/PD
+
+      // DQS Swapped Input Enable
+      isbM32m(DDRPHY, (COMPEN1CH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT19|BIT17),           ((BIT31|BIT30)|BIT19|BIT17|(BIT15|BIT14)));
+
+      // ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50)
+      isbM32m(DDRPHY, (DQVREFCH0 +  (channel_i * DDRCOMP_CH_OFFSET)), ((0x32<<8)|(0x03<<0)),   ((BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT Vref PU/PD
+      isbM32m(DDRPHY, (DQSVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x32<<8)|(0x03<<0)),   ((BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT Vref PU/PD
+      isbM32m(DDRPHY, (CLKVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0E<<8)|(0x05<<0)),   ((BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT Vref PU/PD
+
+      // Slew rate settings are frequency specific, numbers below are for 800Mhz (speed == 0)
+      // - DQ/DQS/DM/CLK SR: 4V/ns,
+      // - CTRL/CMD SR: 1.5V/ns
+      tempD = (0x0E<<16)|(0x0E<<12)|(0x08<<8)|(0x0B<<4)|(0x0B<<0);
+      isbM32m(DDRPHY, (DLYSELCH0 +   (channel_i * DDRCOMP_CH_OFFSET)), (tempD), ((BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // DCOMP Delay Select: CTL,CMD,CLK,DQS,DQ
+      isbM32m(DDRPHY, (TCOVREFCH0 +  (channel_i * DDRCOMP_CH_OFFSET)), ((0x05<<16)|(0x05<<8)|(0x05<<0)), ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // TCO Vref CLK,DQS,DQ
+      isbM32m(DDRPHY, (CCBUFODTCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x03<<8)|(0x03<<0)), ((BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // ODTCOMP CMD/CTL PU/PD
+      isbM32m(DDRPHY, (COMPEN0CH0 +  (channel_i * DDRCOMP_CH_OFFSET)), (0), ((BIT31|BIT30)|BIT8)); // COMP
+
+      #ifdef BACKUP_COMPS
+      // DQ COMP Overrides
+      isbM32m(DDRPHY, (DQDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+      isbM32m(DDRPHY, (DQDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+      isbM32m(DDRPHY, (DQDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+      isbM32m(DDRPHY, (DQDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+      isbM32m(DDRPHY, (DQODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU
+      isbM32m(DDRPHY, (DQODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD
+      isbM32m(DDRPHY, (DQTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU
+      isbM32m(DDRPHY, (DQTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD
+      // DQS COMP Overrides
+      isbM32m(DDRPHY, (DQSDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+      isbM32m(DDRPHY, (DQSDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+      isbM32m(DDRPHY, (DQSDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+      isbM32m(DDRPHY, (DQSDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+      isbM32m(DDRPHY, (DQSODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU
+      isbM32m(DDRPHY, (DQSODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD
+      isbM32m(DDRPHY, (DQSTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU
+      isbM32m(DDRPHY, (DQSTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD
+      // CLK COMP Overrides
+      isbM32m(DDRPHY, (CLKDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0C<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+      isbM32m(DDRPHY, (CLKDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0C<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+      isbM32m(DDRPHY, (CLKDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x07<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+      isbM32m(DDRPHY, (CLKDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x07<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+      isbM32m(DDRPHY, (CLKODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU
+      isbM32m(DDRPHY, (CLKODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD
+      isbM32m(DDRPHY, (CLKTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU
+      isbM32m(DDRPHY, (CLKTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD
+      // CMD COMP Overrides
+      isbM32m(DDRPHY, (CMDDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+      isbM32m(DDRPHY, (CMDDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+      isbM32m(DDRPHY, (CMDDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+      isbM32m(DDRPHY, (CMDDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+      // CTL COMP Overrides
+      isbM32m(DDRPHY, (CTLDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+      isbM32m(DDRPHY, (CTLDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+      isbM32m(DDRPHY, (CTLDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+      isbM32m(DDRPHY, (CTLDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+      #else
+      // DQ TCOCOMP Overrides
+      isbM32m(DDRPHY, (DQTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU
+      isbM32m(DDRPHY, (DQTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD
+      // DQS TCOCOMP Overrides
+      isbM32m(DDRPHY, (DQSTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU
+      isbM32m(DDRPHY, (DQSTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD
+      // CLK TCOCOMP Overrides
+      isbM32m(DDRPHY, (CLKTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU
+      isbM32m(DDRPHY, (CLKTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD
+      #endif // BACKUP_COMPS
+      // program STATIC delays
+      #ifdef BACKUP_WCMD
+      set_wcmd(channel_i, ddr_wcmd[PLATFORM_ID]);
+      #else
+      set_wcmd(channel_i, ddr_wclk[PLATFORM_ID] + HALF_CLK);
+      #endif // BACKUP_WCMD
+      for (rank_i=0; rank_i<NUM_RANKS; rank_i++) {
+        if (mrc_params->rank_enables & (1<<rank_i)) {
+          set_wclk(channel_i, rank_i, ddr_wclk[PLATFORM_ID]);
+          #ifdef BACKUP_WCTL
+          set_wctl(channel_i, rank_i, ddr_wctl[PLATFORM_ID]);
+          #else
+          set_wctl(channel_i, rank_i, ddr_wclk[PLATFORM_ID] + HALF_CLK);
+          #endif // BACKUP_WCTL
+        }
+      }
+    }
+  }
+  // COMP (non channel specific)
+  //isbM32m(DDRPHY, (), (), ());
+  isbM32m(DDRPHY, (DQANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (DQANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (CMDANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (CMDANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (CLKANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (CLKANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (DQSANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (DQSANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (CTLANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (CTLANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (DQANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable
+  isbM32m(DDRPHY, (DQANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable
+  isbM32m(DDRPHY, (CLKANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable
+  isbM32m(DDRPHY, (CLKANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable
+  isbM32m(DDRPHY, (DQSANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable
+  isbM32m(DDRPHY, (DQSANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable
+  isbM32m(DDRPHY, (DQANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (DQANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (CMDANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (CMDANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (CLKANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (CLKANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (DQSANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (DQSANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (CTLANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+  isbM32m(DDRPHY, (CTLANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+  isbM32m(DDRPHY, (DQANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable
+  isbM32m(DDRPHY, (DQANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable
+  isbM32m(DDRPHY, (CLKANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable
+  isbM32m(DDRPHY, (CLKANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable
+  isbM32m(DDRPHY, (DQSANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable
+  isbM32m(DDRPHY, (DQSANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable
+  isbM32m(DDRPHY, (TCOCNTCTRL), (0x1<<0), (BIT1|BIT0)); // TCOCOMP: Pulse Count
+  isbM32m(DDRPHY, (CHNLBUFSTATIC), ((0x03<<24)|(0x03<<16)), ((BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODT: CMD/CTL PD/PU
+  isbM32m(DDRPHY, (MSCNTR), (0x64<<0), (BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0)); // Set 1us counter
+  isbM32m(DDRPHY, (LATCH1CTL), (0x1<<28), (BIT30|BIT29|BIT28)); // ???
+
+  // Release PHY from reset
+  isbM32m(DDRPHY, MASTERRSTN, BIT0, BIT0); // PHYRSTN=1
+
+  // STEP1:
+  post_code(0x03, 0x11);
+  for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+    if (mrc_params->channel_enables & (1<<channel_i)) {
+      // DQ01-DQ23
+      for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+        isbM32m(DDRPHY, (DQMDLLCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG
+        delay_n(3);
+      }
+      // ECC
+      isbM32m(DDRPHY, (ECCMDLLCTL), (BIT13), (BIT13)); // Enable VREG
+      delay_n(3);
+      // CMD
+      isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG
+      delay_n(3);
+      // CLK-CTL
+      isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG
+      delay_n(3);
+    }
+  }
+
+  // STEP2:
+  post_code(0x03, 0x12);
+  delay_n(200);
+  for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+    if (mrc_params->channel_enables & (1<<channel_i)) {
+      // DQ01-DQ23
+      for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+        isbM32m(DDRPHY, (DQMDLLCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT17), (BIT17)); // Enable MCDLL
+        delay_n(50);
+      }
+      // ECC
+      isbM32m(DDRPHY, (ECCMDLLCTL), (BIT17), (BIT17)); // Enable MCDLL
+      delay_n(50);
+      // CMD
+      isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT18), (BIT18)); // Enable MCDLL
+      delay_n(50);
+      // CLK-CTL
+      isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT18), (BIT18)); // Enable MCDLL
+      delay_n(50);
+    }
+  }
+
+  // STEP3:
+  post_code(0x03, 0x13);
+  delay_n(100);
+  for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+    if (mrc_params->channel_enables & (1<<channel_i)) {
+      // DQ01-DQ23
+      for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+#ifdef FORCE_16BIT_DDRIO
+        tempD = ((bl_grp_i) && (mrc_params->channel_width == x16)) ? ((0x1<<12)|(0x1<<8)|(0xF<<4)|(0xF<<0)) : ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0));
+#else
+        tempD = ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0));
+#endif
+        isbM32m(DDRPHY, (DQDLLTXCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL
+        delay_n(3);
+        isbM32m(DDRPHY, (DQDLLRXCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT3|BIT2|BIT1|BIT0), (BIT3|BIT2|BIT1|BIT0)); // Enable RXDLL
+        delay_n(3);
+        isbM32m(DDRPHY, (B0OVRCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT3|BIT2|BIT1|BIT0), (BIT3|BIT2|BIT1|BIT0)); // Enable RXDLL Overrides BL0
+      }
+
+      // ECC
+      tempD = ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0));
+      isbM32m(DDRPHY, (ECCDLLTXCTL), (tempD), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL
+      delay_n(3);
+
+      // CMD (PO)
+      isbM32m(DDRPHY, (CMDDLLTXCTL + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0)), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL
+      delay_n(3);
+    }
+  }
+
+
+  // STEP4:
+  post_code(0x03, 0x14);
+  for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+    if (mrc_params->channel_enables & (1<<channel_i)) {
+      // Host To Memory Clock Alignment (HMC) for 800/1066
+      for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+        isbM32m(DDRPHY, (DQCLKALIGNREG2 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((bl_grp_i)?(0x3):(0x1)), (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID
+      }
+      isbM32m(DDRPHY, (ECCCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x2, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID
+      isbM32m(DDRPHY, (CMDCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x0, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID
+      isbM32m(DDRPHY, (CCCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x2, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID
+      isbM32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), (0x2<<4), (BIT5|BIT4)); // CLK_ALIGN_MODE
+      isbM32m(DDRPHY, (CMDCLKALIGNREG1 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x18<<16)|(0x10<<8)|(0x8<<2)|(0x1<<0)), ((BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|(BIT1|BIT0))); // NUM_SAMPLES, MAX_SAMPLES, MACRO_PI_STEP, MICRO_PI_STEP
+      isbM32m(DDRPHY, (CMDCLKALIGNREG2 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x10<<16)|(0x4<<8)|(0x2<<4)), ((BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4))); // ???, TOTAL_NUM_MODULES, FIRST_U_PARTITION
+      #ifdef HMC_TEST
+      isbM32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT24, BIT24); // START_CLK_ALIGN=1
+      while (isbR32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET))) & BIT24); // wait for START_CLK_ALIGN=0
+      #endif // HMC_TEST
+
+      // Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN
+      isbM32m(DDRPHY, (CMDPTRREG + (channel_i * DDRIOCCC_CH_OFFSET)), BIT0, BIT0); // WRPTRENABLE=1
+
+
+#ifdef SIM
+      // comp is not working on simulator
+#else
+      // COMP initial
+      isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), BIT5, BIT5); // enable bypass for CLK buffer (PO)
+      isbM32m(DDRPHY, (CMPCTRL), (BIT0), (BIT0)); // Initial COMP Enable
+      while (isbR32m(DDRPHY, (CMPCTRL)) & BIT0); // wait for Initial COMP Enable = 0
+      isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), ~BIT5, BIT5); // disable bypass for CLK buffer (PO)
+#endif
+
+      // IOBUFACT
+      // STEP4a
+      isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT2, BIT2); // IOBUFACTRST_N=1
+
+      // DDRPHY initialisation complete
+      isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT20, BIT20); // SPID_INIT_COMPLETE=1
+    }
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// jedec_init (aka PerformJedecInit):
+// This function performs JEDEC initialisation on all enabled channels.
+static void jedec_init(
+    MRCParams_t *mrc_params,
+    uint32_t silent)
+{
+  uint8_t TWR, WL, Rank;
+  uint32_t TCK;
+
+  RegDTR0 DTR0reg;
+
+  DramInitDDR3MRS0 mrs0Command;
+  DramInitDDR3EMR1 emrs1Command;
+  DramInitDDR3EMR2 emrs2Command;
+  DramInitDDR3EMR3 emrs3Command;
+
+  ENTERFN();
+
+  // jedec_init starts
+  if (!silent)
+  {
+    post_code(0x04, 0x00);
+  }
+
+  // Assert RESET# for 200us
+  isbM32m(DDRPHY, CCDDR3RESETCTL, BIT1, (BIT8|BIT1)); // DDR3_RESET_SET=0, DDR3_RESET_RESET=1
+#ifdef QUICKSIM
+      // Don't waste time during simulation
+      delay_u(2);
+#else
+  delay_u(200);
+#endif
+  isbM32m(DDRPHY, CCDDR3RESETCTL, BIT8, (BIT8|BIT1)); // DDR3_RESET_SET=1, DDR3_RESET_RESET=0
+
+  DTR0reg.raw = isbR32m(MCU, DTR0);
+
+  // Set CKEVAL for populated ranks
+  // then send NOP to each rank (#4550197)
+  {
+    uint32_t DRPbuffer;
+    uint32_t DRMCbuffer;
+
+    DRPbuffer = isbR32m(MCU, DRP);
+    DRPbuffer &= 0x3;
+    DRMCbuffer = isbR32m(MCU, DRMC);
+    DRMCbuffer &= 0xFFFFFFFC;
+    DRMCbuffer |= (BIT4 | DRPbuffer);
+
+    isbW32m(MCU, DRMC, DRMCbuffer);
+
+    for (Rank = 0; Rank < NUM_RANKS; Rank++)
+    {
+      // Skip to next populated rank
+      if ((mrc_params->rank_enables & (1 << Rank)) == 0)
+      {
+        continue;
+      }
+
+      dram_init_command(DCMD_NOP(Rank));
+    }
+
+    isbW32m(MCU, DRMC, DRMC_DEFAULT);
+  }
+
+  // setup for emrs 2
+  // BIT[15:11] --> Always "0"
+  // BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0)
+  // BIT[08]    --> Always "0"
+  // BIT[07]    --> SRT: use sr_temp_range
+  // BIT[06]    --> ASR: want "Manual SR Reference" (0)
+  // BIT[05:03] --> CWL: use oem_tCWL
+  // BIT[02:00] --> PASR: want "Full Array" (0)
+  emrs2Command.raw = 0;
+  emrs2Command.field.bankAddress = 2;
+
+  WL = 5 + mrc_params->ddr_speed;
+  emrs2Command.field.CWL = WL - 5;
+  emrs2Command.field.SRT = mrc_params->sr_temp_range;
+
+  // setup for emrs 3
+  // BIT[15:03] --> Always "0"
+  // BIT[02]    --> MPR: want "Normal Operation" (0)
+  // BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0)
+  emrs3Command.raw = 0;
+  emrs3Command.field.bankAddress = 3;
+
+  // setup for emrs 1
+  // BIT[15:13]     --> Always "0"
+  // BIT[12:12]     --> Qoff: want "Output Buffer Enabled" (0)
+  // BIT[11:11]     --> TDQS: want "Disabled" (0)
+  // BIT[10:10]     --> Always "0"
+  // BIT[09,06,02]  --> Rtt_nom: use rtt_nom_value
+  // BIT[08]        --> Always "0"
+  // BIT[07]        --> WR_LVL: want "Disabled" (0)
+  // BIT[05,01]     --> DIC: use ron_value
+  // BIT[04:03]     --> AL: additive latency want "0" (0)
+  // BIT[00]        --> DLL: want "Enable" (0)
+  //
+  // (BIT5|BIT1) set Ron value
+  // 00 --> RZQ/6 (40ohm)
+  // 01 --> RZQ/7 (34ohm)
+  // 1* --> RESERVED
+  //
+  // (BIT9|BIT6|BIT2) set Rtt_nom value
+  // 000 --> Disabled
+  // 001 --> RZQ/4 ( 60ohm)
+  // 010 --> RZQ/2 (120ohm)
+  // 011 --> RZQ/6 ( 40ohm)
+  // 1** --> RESERVED
+  emrs1Command.raw = 0;
+  emrs1Command.field.bankAddress = 1;
+  emrs1Command.field.dllEnabled = 0; // 0 = Enable , 1 = Disable
+
+  if (mrc_params->ron_value == 0)
+  {
+    emrs1Command.field.DIC0 = DDR3_EMRS1_DIC_34;
+  }
+  else
+  {
+    emrs1Command.field.DIC0 = DDR3_EMRS1_DIC_40;
+  }
+
+
+  if (mrc_params->rtt_nom_value == 0)
+  {
+    emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_40 << 6);
+  }
+  else if (mrc_params->rtt_nom_value == 1)
+  {
+    emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_60 << 6);
+  }
+  else if (mrc_params->rtt_nom_value == 2)
+  {
+    emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_120 << 6);
+  }
+
+  // save MRS1 value (excluding control fields)
+  mrc_params->mrs1 = emrs1Command.raw >> 6;
+
+  // setup for mrs 0
+  // BIT[15:13]     --> Always "0"
+  // BIT[12]        --> PPD: for Quark (1)
+  // BIT[11:09]     --> WR: use oem_tWR
+  // BIT[08]        --> DLL: want "Reset" (1, self clearing)
+  // BIT[07]        --> MODE: want "Normal" (0)
+  // BIT[06:04,02]  --> CL: use oem_tCAS
+  // BIT[03]        --> RD_BURST_TYPE: want "Interleave" (1)
+  // BIT[01:00]     --> BL: want "8 Fixed" (0)
+  // WR:
+  // 0 --> 16
+  // 1 --> 5
+  // 2 --> 6
+  // 3 --> 7
+  // 4 --> 8
+  // 5 --> 10
+  // 6 --> 12
+  // 7 --> 14
+  // CL:
+  // BIT[02:02] "0" if oem_tCAS <= 11 (1866?)
+  // BIT[06:04] use oem_tCAS-4
+  mrs0Command.raw = 0;
+  mrs0Command.field.bankAddress = 0;
+  mrs0Command.field.dllReset = 1;
+  mrs0Command.field.BL = 0;
+  mrs0Command.field.PPD = 1;
+  mrs0Command.field.casLatency = DTR0reg.field.tCL + 1;
+
+  TCK = tCK[mrc_params->ddr_speed];
+  TWR = MCEIL(15000, TCK);   // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600
+  mrs0Command.field.writeRecovery = TWR - 4;
+
+  for (Rank = 0; Rank < NUM_RANKS; Rank++)
+  {
+    // Skip to next populated rank
+    if ((mrc_params->rank_enables & (1 << Rank)) == 0)
+    {
+      continue;
+    }
+
+    emrs2Command.field.rankSelect = Rank;
+    dram_init_command(emrs2Command.raw);
+
+    emrs3Command.field.rankSelect = Rank;
+    dram_init_command(emrs3Command.raw);
+
+    emrs1Command.field.rankSelect = Rank;
+    dram_init_command(emrs1Command.raw);
+
+    mrs0Command.field.rankSelect = Rank;
+    dram_init_command(mrs0Command.raw);
+
+    dram_init_command(DCMD_ZQCL(Rank));
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// rcvn_cal:
+// POST_CODE[major] == 0x05
+//
+// This function will perform our RCVEN Calibration Algorithm.
+// We will only use the 2xCLK domain timings to perform RCVEN Calibration.
+// All byte lanes will be calibrated "simultaneously" per channel per rank.
+static void rcvn_cal(
+    MRCParams_t *mrc_params)
+{
+  uint8_t channel_i; // channel counter
+  uint8_t rank_i; // rank counter
+  uint8_t bl_i; // byte lane counter
+  uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+
+#ifdef R2R_SHARING
+  uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs
+#ifndef BACKUP_RCVN
+  uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs
+#endif // BACKUP_RCVN
+#endif // R2R_SHARING
+
+#ifdef BACKUP_RCVN
+#else
+  uint32_t tempD; // temporary DWORD
+  uint32_t delay[NUM_BYTE_LANES]; // absolute PI value to be programmed on the byte lane
+  RegDTR1 dtr1;
+  RegDTR1 dtr1save;
+#endif // BACKUP_RCVN
+  ENTERFN();
+
+  // rcvn_cal starts
+  post_code(0x05, 0x00);
+
+#ifndef BACKUP_RCVN
+  // need separate burst to sample DQS preamble
+  dtr1.raw = dtr1save.raw = isbR32m(MCU, DTR1);
+  dtr1.field.tCCD = 1;
+  isbW32m(MCU, DTR1, dtr1.raw);
+#endif
+
+#ifdef R2R_SHARING
+  // need to set "final_delay[][]" elements to "0"
+  memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));
+#endif // R2R_SHARING
+
+  // loop through each enabled channel
+  for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1 << channel_i))
+    {
+      // perform RCVEN Calibration on a per rank basis
+      for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1 << rank_i))
+        {
+          // POST_CODE here indicates the current channel and rank being calibrated
+          post_code(0x05, (0x10 + ((channel_i << 4) | rank_i)));
+
+#ifdef BACKUP_RCVN
+          // set hard-coded timing values
+          for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+          {
+            set_rcvn(channel_i, rank_i, bl_i, ddr_rcvn[PLATFORM_ID]);
+          }
+#else
+          // enable FIFORST
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i += 2)
+          {
+            isbM32m(DDRPHY, (B01PTRCTL1 + ((bl_i >> 1) * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), 0,
+                BIT8); // 0 is enabled
+          } // bl_i loop
+          // initialise the starting delay to 128 PI (tCAS +1 CLK)
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+#ifdef SIM
+            // Original value was late at the end of DQS sequence
+            delay[bl_i] = 3 * FULL_CLK;
+#else
+            delay[bl_i] = (4 + 1) * FULL_CLK; // 1x CLK domain timing is tCAS-4
+#endif
+
+            set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);
+          } // bl_i loop
+
+          // now find the rising edge
+          find_rising_edge(mrc_params, delay, channel_i, rank_i, true);
+          // Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse.
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+            delay[bl_i] += QRTR_CLK;
+            set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);
+          } // bl_i loop
+          // Now decrement delay by 128 PI (1 CLK) until we sample a "0"
+          do
+          {
+
+            tempD = sample_dqs(mrc_params, channel_i, rank_i, true);
+            for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+            {
+              if (tempD & (1 << bl_i))
+              {
+                if (delay[bl_i] >= FULL_CLK)
+                {
+                  delay[bl_i] -= FULL_CLK;
+                  set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);
+                }
+                else
+                {
+                  // not enough delay
+                  training_message(channel_i, rank_i, bl_i);
+                  post_code(0xEE, 0x50);
+                }
+              }
+            } // bl_i loop
+          } while (tempD & 0xFF);
+
+#ifdef R2R_SHARING
+          // increment "num_ranks_enabled"
+          num_ranks_enabled++;
+          // Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble.
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+            delay[bl_i] += QRTR_CLK;
+            // add "delay[]" values to "final_delay[][]" for rolling average
+            final_delay[channel_i][bl_i] += delay[bl_i];
+            // set timing based on rolling average values
+            set_rcvn(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));
+          } // bl_i loop
+#else
+          // Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble.
+          for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+          {
+            delay[bl_i] += QRTR_CLK;
+            set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);
+          } // bl_i loop
+
+#endif // R2R_SHARING
+
+          // disable FIFORST
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i += 2)
+          {
+            isbM32m(DDRPHY, (B01PTRCTL1 + ((bl_i >> 1) * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), BIT8,
+                BIT8); // 1 is disabled
+          } // bl_i loop
+
+#endif // BACKUP_RCVN
+
+        } // if rank is enabled
+      } // rank_i loop
+    } // if channel is enabled
+  } // channel_i loop
+
+#ifndef BACKUP_RCVN
+  // restore original
+  isbW32m(MCU, DTR1, dtr1save.raw);
+#endif
+
+#ifdef MRC_SV
+  if (mrc_params->tune_rcvn)
+  {
+    uint32_t rcven, val;
+    uint32_t rdcmd2rcven;
+
+    /*
+     Formulas for RDCMD2DATAVALID & DIFFAMP dynamic timings
+
+     1. Set after RCVEN training
+
+     //Tune RDCMD2DATAVALID
+
+     x80/x84[21:16]
+     MAX OF 2 RANKS : round up (rdcmd2rcven (rcven 1x) + 2x x 2 + PI/128) + 5
+
+     //rdcmd2rcven x80/84[12:8]
+     //rcven 2x x70[23:20] & [11:8]
+
+     //Tune DIFFAMP Timings
+
+     //diffampen launch x88[20:16] & [4:0]  -- B01LATCTL1
+     MIN OF 2 RANKS : round down (rcven 1x + 2x x 2 + PI/128) - 1
+
+     //diffampen length x8C/x90 [13:8]   -- B0ONDURCTL B1ONDURCTL
+     MAX OF 2 RANKS : roundup (rcven 1x + 2x x 2 + PI/128) + 5
+
+
+     2. need to do a fiforst after settings these values
+    */
+
+    DPF(D_INFO, "BEFORE\n");
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0LATCTL0));
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B01LATCTL1));
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0ONDURCTL));
+
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1LATCTL0));
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1ONDURCTL));
+
+    rcven = get_rcvn(0, 0, 0) / 128;
+    rdcmd2rcven = (isbR32m(DDRPHY, B0LATCTL0) >> 8) & 0x1F;
+    val = rdcmd2rcven + rcven + 6;
+    isbM32m(DDRPHY, B0LATCTL0, val << 16, (BIT21|BIT20|BIT19|BIT18|BIT17|BIT16));
+
+    val = rdcmd2rcven + rcven - 1;
+    isbM32m(DDRPHY, B01LATCTL1, val << 0, (BIT4|BIT3|BIT2|BIT1|BIT0));
+
+    val = rdcmd2rcven + rcven + 5;
+    isbM32m(DDRPHY, B0ONDURCTL, val << 8, (BIT13|BIT12|BIT11|BIT10|BIT9|BIT8));
+
+    rcven = get_rcvn(0, 0, 1) / 128;
+    rdcmd2rcven = (isbR32m(DDRPHY, B1LATCTL0) >> 8) & 0x1F;
+    val = rdcmd2rcven + rcven + 6;
+    isbM32m(DDRPHY, B1LATCTL0, val << 16, (BIT21|BIT20|BIT19|BIT18|BIT17|BIT16));
+
+    val = rdcmd2rcven + rcven - 1;
+    isbM32m(DDRPHY, B01LATCTL1, val << 16, (BIT20|BIT19|BIT18|BIT17|BIT16));
+
+    val = rdcmd2rcven + rcven + 5;
+    isbM32m(DDRPHY, B1ONDURCTL, val << 8, (BIT13|BIT12|BIT11|BIT10|BIT9|BIT8));
+
+    DPF(D_INFO, "AFTER\n");
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0LATCTL0));
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B01LATCTL1));
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0ONDURCTL));
+
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1LATCTL0));
+    DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1ONDURCTL));
+
+    DPF(D_INFO, "\nPress a key\n");
+    mgetc();
+
+    // fifo reset
+    isbM32m(DDRPHY, B01PTRCTL1, 0, BIT8); // 0 is enabled
+    delay_n(3);
+    isbM32m(DDRPHY, B01PTRCTL1, BIT8, BIT8); // 1 is disabled
+  }
+#endif
+
+  LEAVEFN();
+  return;
+}
+
+// Check memory executing write/read/verify of many data patterns
+// at the specified address. Bits in the result indicate failure
+// on specific byte lane.
+static uint32_t check_bls_ex(
+    MRCParams_t *mrc_params,
+    uint32_t address)
+{
+  uint32_t result;
+  uint8_t first_run = 0;
+
+  if (mrc_params->hte_setup)
+  {
+    mrc_params->hte_setup = 0;
+
+    first_run = 1;
+    select_hte(mrc_params);
+  }
+
+  result = WriteStressBitLanesHTE(mrc_params, address, first_run);
+
+  DPF(D_TRN, "check_bls_ex result is %x\n", result);
+  return result;
+}
+
+// Check memory executing simple write/read/verify at
+// the specified address. Bits in the result indicate failure
+// on specific byte lane.
+static uint32_t check_rw_coarse(
+    MRCParams_t *mrc_params,
+    uint32_t address)
+{
+  uint32_t result = 0;
+  uint8_t first_run = 0;
+
+  if (mrc_params->hte_setup)
+  {
+    mrc_params->hte_setup = 0;
+
+    first_run = 1;
+    select_hte(mrc_params);
+  }
+
+  result = BasicWriteReadHTE(mrc_params, address, first_run, WRITE_TRAIN);
+
+  DPF(D_TRN, "check_rw_coarse result is %x\n", result);
+  return result;
+}
+
+// wr_level:
+// POST_CODE[major] == 0x06
+//
+// This function will perform the Write Levelling algorithm (align WCLK and WDQS).
+// This algorithm will act on each rank in each channel separately.
+static void wr_level(
+    MRCParams_t *mrc_params)
+{
+  uint8_t channel_i; // channel counter
+  uint8_t rank_i; // rank counter
+  uint8_t bl_i; // byte lane counter
+  uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+
+#ifdef R2R_SHARING
+  uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs
+#ifndef BACKUP_WDQS
+  uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs
+#endif // BACKUP_WDQS
+#endif // R2R_SHARING
+
+#ifdef BACKUP_WDQS
+#else
+  bool all_edges_found; // determines stop condition for CRS_WR_LVL
+  uint32_t delay[NUM_BYTE_LANES]; // absolute PI value to be programmed on the byte lane
+  // static makes it so the data is loaded in the heap once by shadow(), where
+  // non-static copies the data onto the stack every time this function is called.
+
+  uint32_t address; // address to be checked during COARSE_WR_LVL
+  RegDTR4 dtr4;
+  RegDTR4 dtr4save;
+#endif // BACKUP_WDQS
+
+  ENTERFN();
+
+  // wr_level starts
+  post_code(0x06, 0x00);
+
+#ifdef R2R_SHARING
+  // need to set "final_delay[][]" elements to "0"
+  memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));
+#endif // R2R_SHARING
+  // loop through each enabled channel
+  for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1 << channel_i))
+    {
+      // perform WRITE LEVELING algorithm on a per rank basis
+      for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1 << rank_i))
+        {
+          // POST_CODE here indicates the current rank and channel being calibrated
+          post_code(0x06, (0x10 + ((channel_i << 4) | rank_i)));
+
+#ifdef BACKUP_WDQS
+          for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+          {
+            set_wdqs(channel_i, rank_i, bl_i, ddr_wdqs[PLATFORM_ID]);
+            set_wdq(channel_i, rank_i, bl_i, (ddr_wdqs[PLATFORM_ID] - QRTR_CLK));
+          }
+#else
+
+          { // Begin product specific code
+
+            // perform a single PRECHARGE_ALL command to make DRAM state machine go to IDLE state
+            dram_init_command(DCMD_PREA(rank_i));
+
+            // enable Write Levelling Mode (EMRS1 w/ Write Levelling Mode Enable)
+            dram_init_command(DCMD_MRS1(rank_i,0x0082));
+
+            // set ODT DRAM Full Time Termination disable in MCU
+            dtr4.raw = dtr4save.raw = isbR32m(MCU, DTR4);
+            dtr4.field.ODTDIS = 1;
+            isbW32m(MCU, DTR4, dtr4.raw);
+
+            for (bl_i = 0; bl_i < ((NUM_BYTE_LANES / bl_divisor) / 2); bl_i++)
+            {
+              isbM32m(DDRPHY, DQCTL + (DDRIODQ_BL_OFFSET * bl_i) + (DDRIODQ_CH_OFFSET * channel_i),
+                  (BIT28 | (0x1 << 8) | (0x1 << 6) | (0x1 << 4) | (0x1 << 2)),
+                  (BIT28 | (BIT9|BIT8) | (BIT7|BIT6) | (BIT5|BIT4) | (BIT3|BIT2))); // Enable Sandy Bridge Mode (WDQ Tri-State) & Ensure 5 WDQS pulses during Write Leveling
+            }
+
+            isbM32m(DDRPHY, CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * channel_i), (BIT16), (BIT16)); // Write Leveling Mode enabled in IO
+          } // End product specific code
+          // Initialise the starting delay to WCLK
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+            { // Begin product specific code
+              // CLK0 --> RK0
+              // CLK1 --> RK1
+              delay[bl_i] = get_wclk(channel_i, rank_i);
+            } // End product specific code
+            set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]);
+          } // bl_i loop
+          // now find the rising edge
+          find_rising_edge(mrc_params, delay, channel_i, rank_i, false);
+          { // Begin product specific code
+            // disable Write Levelling Mode
+            isbM32m(DDRPHY, CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * channel_i), (0), (BIT16)); // Write Leveling Mode disabled in IO
+
+            for (bl_i = 0; bl_i < ((NUM_BYTE_LANES / bl_divisor) / 2); bl_i++)
+            {
+              isbM32m(DDRPHY, DQCTL + (DDRIODQ_BL_OFFSET * bl_i) + (DDRIODQ_CH_OFFSET * channel_i),
+                  ((0x1 << 8) | (0x1 << 6) | (0x1 << 4) | (0x1 << 2)),
+                  (BIT28 | (BIT9|BIT8) | (BIT7|BIT6) | (BIT5|BIT4) | (BIT3|BIT2))); // Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation
+            } // bl_i loop
+
+            // restore original DTR4
+            isbW32m(MCU, DTR4, dtr4save.raw);
+
+            // restore original value (Write Levelling Mode Disable)
+            dram_init_command(DCMD_MRS1(rank_i, mrc_params->mrs1));
+
+            // perform a single PRECHARGE_ALL command to make DRAM state machine go to IDLE state
+            dram_init_command(DCMD_PREA(rank_i));
+          } // End product specific code
+
+          post_code(0x06, (0x30 + ((channel_i << 4) | rank_i)));
+
+          // COARSE WRITE LEVEL:
+          // check that we're on the correct clock edge
+
+          // hte reconfiguration request
+          mrc_params->hte_setup = 1;
+
+          // start CRS_WR_LVL with WDQS = WDQS + 128 PI
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+            delay[bl_i] = get_wdqs(channel_i, rank_i, bl_i) + FULL_CLK;
+            set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]);
+            // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI)
+            set_wdq(channel_i, rank_i, bl_i, (delay[bl_i] - QRTR_CLK));
+          } // bl_i loop
+
+          // get an address in the targeted channel/rank
+          address = get_addr(mrc_params, channel_i, rank_i);
+          do
+          {
+            uint32_t coarse_result = 0x00;
+            uint32_t coarse_result_mask = byte_lane_mask(mrc_params);
+            all_edges_found = true; // assume pass
+
+#ifdef SIM
+            // need restore memory to idle state as write can be in bad sync
+            dram_init_command (DCMD_PREA(rank_i));
+#endif
+
+            mrc_params->hte_setup = 1;
+            coarse_result = check_rw_coarse(mrc_params, address);
+
+            // check for failures and margin the byte lane back 128 PI (1 CLK)
+            for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+            {
+              if (coarse_result & (coarse_result_mask << bl_i))
+              {
+                all_edges_found = false;
+                delay[bl_i] -= FULL_CLK;
+                set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]);
+                // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI)
+                set_wdq(channel_i, rank_i, bl_i, (delay[bl_i] - QRTR_CLK));
+              }
+            } // bl_i loop
+
+          } while (!all_edges_found);
+
+#ifdef R2R_SHARING
+          // increment "num_ranks_enabled"
+          num_ranks_enabled++;
+          // accumulate "final_delay[][]" values from "delay[]" values for rolling average
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+            final_delay[channel_i][bl_i] += delay[bl_i];
+            set_wdqs(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));
+            // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI)
+            set_wdq(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled) - QRTR_CLK);
+          } // bl_i loop
+#endif // R2R_SHARING
+#endif // BACKUP_WDQS
+
+        } // if rank is enabled
+      } // rank_i loop
+    } // if channel is enabled
+  } // channel_i loop
+
+  LEAVEFN();
+  return;
+}
+
+// rd_train:
+// POST_CODE[major] == 0x07
+//
+// This function will perform the READ TRAINING Algorithm on all channels/ranks/byte_lanes simultaneously to minimize execution time.
+// The idea here is to train the VREF and RDQS (and eventually RDQ) values to achieve maximum READ margins.
+// The algorithm will first determine the X coordinate (RDQS setting).
+// This is done by collapsing the VREF eye until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX.
+// Then we take the averages of the RDQS eye at VREF_MIN and VREF_MAX, then average those; this will be the final X coordinate.
+// The algorithm will then determine the Y coordinate (VREF setting).
+// This is done by collapsing the RDQS eye until we find a minimum required VREF eye for RDQS_MIN and RDQS_MAX.
+// Then we take the averages of the VREF eye at RDQS_MIN and RDQS_MAX, then average those; this will be the final Y coordinate.
+// NOTE: this algorithm assumes the eye curves have a one-to-one relationship, meaning for each X the curve has only one Y and vice-a-versa.
+static void rd_train(
+    MRCParams_t *mrc_params)
+{
+
+#define MIN_RDQS_EYE 10 // in PI Codes
+#define MIN_VREF_EYE 10 // in VREF Codes
+#define RDQS_STEP 1     // how many RDQS codes to jump while margining
+#define VREF_STEP 1     // how many VREF codes to jump while margining
+#define VREF_MIN (0x00) // offset into "vref_codes[]" for minimum allowed VREF setting
+#define VREF_MAX (0x3F) // offset into "vref_codes[]" for maximum allowed VREF setting
+#define RDQS_MIN (0x00) // minimum RDQS delay value
+#define RDQS_MAX (0x3F) // maximum RDQS delay value
+#define B 0 // BOTTOM VREF
+#define T 1 // TOP VREF
+#define L 0 // LEFT RDQS
+#define R 1 // RIGHT RDQS
+
+  uint8_t channel_i; // channel counter
+  uint8_t rank_i; // rank counter
+  uint8_t bl_i; // byte lane counter
+  uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+#ifdef BACKUP_RDQS
+#else
+  uint8_t side_x; // tracks LEFT/RIGHT approach vectors
+  uint8_t side_y; // tracks BOTTOM/TOP approach vectors
+  uint8_t x_coordinate[2/*side_x*/][2/*side_y*/][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // X coordinate data (passing RDQS values) for approach vectors
+  uint8_t y_coordinate[2/*side_x*/][2/*side_y*/][NUM_CHANNELS][NUM_BYTE_LANES]; // Y coordinate data (passing VREF values) for approach vectors
+  uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // centered X (RDQS)
+  uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES]; // centered Y (VREF)
+  uint32_t address; // target address for "check_bls_ex()"
+  uint32_t result; // result of "check_bls_ex()"
+  uint32_t bl_mask; // byte lane mask for "result" checking
+#ifdef R2R_SHARING
+  uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs
+  uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs
+#endif // R2R_SHARING
+#endif // BACKUP_RDQS
+  // rd_train starts
+  post_code(0x07, 0x00);
+
+  ENTERFN();
+
+#ifdef BACKUP_RDQS
+  for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1<<channel_i))
+    {
+      for (rank_i=0; rank_i<NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1<<rank_i))
+        {
+          for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+          {
+            set_rdqs(channel_i, rank_i, bl_i, ddr_rdqs[PLATFORM_ID]);
+          } // bl_i loop
+        } // if rank is enabled
+      } // rank_i loop
+    } // if channel is enabled
+  } // channel_i loop
+#else
+  // initialise x/y_coordinate arrays
+  for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1 << channel_i))
+    {
+      for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1 << rank_i))
+        {
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+            // x_coordinate:
+            x_coordinate[L][B][channel_i][rank_i][bl_i] = RDQS_MIN;
+            x_coordinate[R][B][channel_i][rank_i][bl_i] = RDQS_MAX;
+            x_coordinate[L][T][channel_i][rank_i][bl_i] = RDQS_MIN;
+            x_coordinate[R][T][channel_i][rank_i][bl_i] = RDQS_MAX;
+            // y_coordinate:
+            y_coordinate[L][B][channel_i][bl_i] = VREF_MIN;
+            y_coordinate[R][B][channel_i][bl_i] = VREF_MIN;
+            y_coordinate[L][T][channel_i][bl_i] = VREF_MAX;
+            y_coordinate[R][T][channel_i][bl_i] = VREF_MAX;
+          } // bl_i loop
+        } // if rank is enabled
+      } // rank_i loop
+    } // if channel is enabled
+  } // channel_i loop
+
+  // initialise other variables
+  bl_mask = byte_lane_mask(mrc_params);
+  address = get_addr(mrc_params, 0, 0);
+
+#ifdef R2R_SHARING
+  // need to set "final_delay[][]" elements to "0"
+  memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));
+#endif // R2R_SHARING
+
+  // look for passing coordinates
+  for (side_y = B; side_y <= T; side_y++)
+  {
+    for (side_x = L; side_x <= R; side_x++)
+    {
+
+      post_code(0x07, (0x10 + (side_y * 2) + (side_x)));
+
+      // find passing values
+      for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+      {
+        if (mrc_params->channel_enables & (0x1 << channel_i))
+        {
+          for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+          {
+
+            if (mrc_params->rank_enables & (0x1 << rank_i))
+            {
+              // set x/y_coordinate search starting settings
+              for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+              {
+                set_rdqs(channel_i, rank_i, bl_i, x_coordinate[side_x][side_y][channel_i][rank_i][bl_i]);
+                set_vref(channel_i, bl_i, y_coordinate[side_x][side_y][channel_i][bl_i]);
+              } // bl_i loop
+              // get an address in the target channel/rank
+              address = get_addr(mrc_params, channel_i, rank_i);
+
+              // request HTE reconfiguration
+              mrc_params->hte_setup = 1;
+
+              // test the settings
+              do
+              {
+
+                // result[07:00] == failing byte lane (MAX 8)
+                result = check_bls_ex( mrc_params, address);
+
+                // check for failures
+                if (result & 0xFF)
+                {
+                  // at least 1 byte lane failed
+                  for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+                  {
+                    if (result & (bl_mask << bl_i))
+                    {
+                      // adjust the RDQS values accordingly
+                      if (side_x == L)
+                      {
+                        x_coordinate[L][side_y][channel_i][rank_i][bl_i] += RDQS_STEP;
+                      }
+                      else
+                      {
+                        x_coordinate[R][side_y][channel_i][rank_i][bl_i] -= RDQS_STEP;
+                      }
+                      // check that we haven't closed the RDQS_EYE too much
+                      if ((x_coordinate[L][side_y][channel_i][rank_i][bl_i] > (RDQS_MAX - MIN_RDQS_EYE)) ||
+                          (x_coordinate[R][side_y][channel_i][rank_i][bl_i] < (RDQS_MIN + MIN_RDQS_EYE))
+                          ||
+                          (x_coordinate[L][side_y][channel_i][rank_i][bl_i]
+                              == x_coordinate[R][side_y][channel_i][rank_i][bl_i]))
+                      {
+                        // not enough RDQS margin available at this VREF
+                        // update VREF values accordingly
+                        if (side_y == B)
+                        {
+                          y_coordinate[side_x][B][channel_i][bl_i] += VREF_STEP;
+                        }
+                        else
+                        {
+                          y_coordinate[side_x][T][channel_i][bl_i] -= VREF_STEP;
+                        }
+                        // check that we haven't closed the VREF_EYE too much
+                        if ((y_coordinate[side_x][B][channel_i][bl_i] > (VREF_MAX - MIN_VREF_EYE)) ||
+                            (y_coordinate[side_x][T][channel_i][bl_i] < (VREF_MIN + MIN_VREF_EYE)) ||
+                            (y_coordinate[side_x][B][channel_i][bl_i] == y_coordinate[side_x][T][channel_i][bl_i]))
+                        {
+                          // VREF_EYE collapsed below MIN_VREF_EYE
+                          training_message(channel_i, rank_i, bl_i);
+                          post_code(0xEE, (0x70 + (side_y * 2) + (side_x)));
+                        }
+                        else
+                        {
+                          // update the VREF setting
+                          set_vref(channel_i, bl_i, y_coordinate[side_x][side_y][channel_i][bl_i]);
+                          // reset the X coordinate to begin the search at the new VREF
+                          x_coordinate[side_x][side_y][channel_i][rank_i][bl_i] =
+                              (side_x == L) ? (RDQS_MIN) : (RDQS_MAX);
+                        }
+                      }
+                      // update the RDQS setting
+                      set_rdqs(channel_i, rank_i, bl_i, x_coordinate[side_x][side_y][channel_i][rank_i][bl_i]);
+                    } // if bl_i failed
+                  } // bl_i loop
+                } // at least 1 byte lane failed
+              } while (result & 0xFF);
+            } // if rank is enabled
+          } // rank_i loop
+        } // if channel is enabled
+      } // channel_i loop
+    } // side_x loop
+  } // side_y loop
+
+  post_code(0x07, 0x20);
+
+  // find final RDQS (X coordinate) & final VREF (Y coordinate)
+  for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1 << channel_i))
+    {
+      for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1 << rank_i))
+        {
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+            uint32_t tempD1;
+            uint32_t tempD2;
+
+            // x_coordinate:
+            DPF(D_INFO, "RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n", rank_i, bl_i,
+                x_coordinate[L][T][channel_i][rank_i][bl_i],
+                x_coordinate[R][T][channel_i][rank_i][bl_i],
+                x_coordinate[L][B][channel_i][rank_i][bl_i],
+                x_coordinate[R][B][channel_i][rank_i][bl_i]);
+
+            tempD1 = (x_coordinate[R][T][channel_i][rank_i][bl_i] + x_coordinate[L][T][channel_i][rank_i][bl_i]) / 2; // average the TOP side LEFT & RIGHT values
+            tempD2 = (x_coordinate[R][B][channel_i][rank_i][bl_i] + x_coordinate[L][B][channel_i][rank_i][bl_i]) / 2; // average the BOTTOM side LEFT & RIGHT values
+            x_center[channel_i][rank_i][bl_i] = (uint8_t) ((tempD1 + tempD2) / 2); // average the above averages
+
+            // y_coordinate:
+            DPF(D_INFO, "VREF R/L eye lane%d : %d-%d %d-%d\n", bl_i,
+                y_coordinate[R][B][channel_i][bl_i],
+                y_coordinate[R][T][channel_i][bl_i],
+                y_coordinate[L][B][channel_i][bl_i],
+                y_coordinate[L][T][channel_i][bl_i]);
+
+            tempD1 = (y_coordinate[R][T][channel_i][bl_i] + y_coordinate[R][B][channel_i][bl_i]) / 2; // average the RIGHT side TOP & BOTTOM values
+            tempD2 = (y_coordinate[L][T][channel_i][bl_i] + y_coordinate[L][B][channel_i][bl_i]) / 2; // average the LEFT side TOP & BOTTOM values
+            y_center[channel_i][bl_i] = (uint8_t) ((tempD1 + tempD2) / 2); // average the above averages
+          } // bl_i loop
+        } // if rank is enabled
+      } // rank_i loop
+    } // if channel is enabled
+  } // channel_i loop
+
+#ifdef RX_EYE_CHECK
+  // perform an eye check
+  for (side_y=B; side_y<=T; side_y++)
+  {
+    for (side_x=L; side_x<=R; side_x++)
+    {
+
+      post_code(0x07, (0x30 + (side_y * 2) + (side_x)));
+
+      // update the settings for the eye check
+      for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++)
+      {
+        if (mrc_params->channel_enables & (1<<channel_i))
+        {
+          for (rank_i=0; rank_i<NUM_RANKS; rank_i++)
+          {
+            if (mrc_params->rank_enables & (1<<rank_i))
+            {
+              for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+              {
+                if (side_x == L)
+                {
+                  set_rdqs(channel_i, rank_i, bl_i, (x_center[channel_i][rank_i][bl_i] - (MIN_RDQS_EYE / 2)));
+                }
+                else
+                {
+                  set_rdqs(channel_i, rank_i, bl_i, (x_center[channel_i][rank_i][bl_i] + (MIN_RDQS_EYE / 2)));
+                }
+                if (side_y == B)
+                {
+                  set_vref(channel_i, bl_i, (y_center[channel_i][bl_i] - (MIN_VREF_EYE / 2)));
+                }
+                else
+                {
+                  set_vref(channel_i, bl_i, (y_center[channel_i][bl_i] + (MIN_VREF_EYE / 2)));
+                }
+              } // bl_i loop
+            } // if rank is enabled
+          } // rank_i loop
+        } // if channel is enabled
+      } // channel_i loop
+
+      // request HTE reconfiguration
+      mrc_params->hte_setup = 1;
+
+      // check the eye
+      if (check_bls_ex( mrc_params, address) & 0xFF)
+      {
+        // one or more byte lanes failed
+        post_code(0xEE, (0x74 + (side_x * 2) + (side_y)));
+      }
+    } // side_x loop
+  } // side_y loop
+#endif // RX_EYE_CHECK
+
+  post_code(0x07, 0x40);
+
+  // set final placements
+  for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1 << channel_i))
+    {
+      for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1 << rank_i))
+        {
+#ifdef R2R_SHARING
+          // increment "num_ranks_enabled"
+          num_ranks_enabled++;
+#endif // R2R_SHARING
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+            // x_coordinate:
+#ifdef R2R_SHARING
+            final_delay[channel_i][bl_i] += x_center[channel_i][rank_i][bl_i];
+            set_rdqs(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));
+#else
+            set_rdqs(channel_i, rank_i, bl_i, x_center[channel_i][rank_i][bl_i]);
+#endif // R2R_SHARING
+            // y_coordinate:
+            set_vref(channel_i, bl_i, y_center[channel_i][bl_i]);
+          } // bl_i loop
+        } // if rank is enabled
+      } // rank_i loop
+    } // if channel is enabled
+  } // channel_i loop
+#endif // BACKUP_RDQS
+  LEAVEFN();
+  return;
+}
+
+// wr_train:
+// POST_CODE[major] == 0x08
+//
+// This function will perform the WRITE TRAINING Algorithm on all channels/ranks/byte_lanes simultaneously to minimize execution time.
+// The idea here is to train the WDQ timings to achieve maximum WRITE margins.
+// The algorithm will start with WDQ at the current WDQ setting (tracks WDQS in WR_LVL) +/- 32 PIs (+/- 1/4 CLK) and collapse the eye until all data patterns pass.
+// This is because WDQS will be aligned to WCLK by the Write Leveling algorithm and WDQ will only ever have a 1/2 CLK window of validity.
+static void wr_train(
+    MRCParams_t *mrc_params)
+{
+
+#define WDQ_STEP 1 // how many WDQ codes to jump while margining
+#define L 0 // LEFT side loop value definition
+#define R 1 // RIGHT side loop value definition
+
+  uint8_t channel_i; // channel counter
+  uint8_t rank_i; // rank counter
+  uint8_t bl_i; // byte lane counter
+  uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+#ifdef BACKUP_WDQ
+#else
+  uint8_t side_i; // LEFT/RIGHT side indicator (0=L, 1=R)
+  uint32_t tempD; // temporary DWORD
+  uint32_t delay[2/*side_i*/][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // 2 arrays, for L & R side passing delays
+  uint32_t address; // target address for "check_bls_ex()"
+  uint32_t result; // result of "check_bls_ex()"
+  uint32_t bl_mask; // byte lane mask for "result" checking
+#ifdef R2R_SHARING
+  uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs
+  uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs
+#endif // R2R_SHARING
+#endif // BACKUP_WDQ
+
+  // wr_train starts
+  post_code(0x08, 0x00);
+
+  ENTERFN();
+
+#ifdef BACKUP_WDQ
+  for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1<<channel_i))
+    {
+      for (rank_i=0; rank_i<NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1<<rank_i))
+        {
+          for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+          {
+            set_wdq(channel_i, rank_i, bl_i, ddr_wdq[PLATFORM_ID]);
+          } // bl_i loop
+        } // if rank is enabled
+      } // rank_i loop
+    } // if channel is enabled
+  } // channel_i loop
+#else
+  // initialise "delay"
+  for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1 << channel_i))
+    {
+      for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1 << rank_i))
+        {
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+            // want to start with WDQ = (WDQS - QRTR_CLK) +/- QRTR_CLK
+            tempD = get_wdqs(channel_i, rank_i, bl_i) - QRTR_CLK;
+            delay[L][channel_i][rank_i][bl_i] = tempD - QRTR_CLK;
+            delay[R][channel_i][rank_i][bl_i] = tempD + QRTR_CLK;
+          } // bl_i loop
+        } // if rank is enabled
+      } // rank_i loop
+    } // if channel is enabled
+  } // channel_i loop
+
+  // initialise other variables
+  bl_mask = byte_lane_mask(mrc_params);
+  address = get_addr(mrc_params, 0, 0);
+
+#ifdef R2R_SHARING
+  // need to set "final_delay[][]" elements to "0"
+  memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));
+#endif // R2R_SHARING
+
+  // start algorithm on the LEFT side and train each channel/bl until no failures are observed, then repeat for the RIGHT side.
+  for (side_i = L; side_i <= R; side_i++)
+  {
+    post_code(0x08, (0x10 + (side_i)));
+
+    // set starting values
+    for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+    {
+      if (mrc_params->channel_enables & (1 << channel_i))
+      {
+        for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+        {
+          if (mrc_params->rank_enables & (1 << rank_i))
+          {
+            for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+            {
+              set_wdq(channel_i, rank_i, bl_i, delay[side_i][channel_i][rank_i][bl_i]);
+            } // bl_i loop
+          } // if rank is enabled
+        } // rank_i loop
+      } // if channel is enabled
+    } // channel_i loop
+
+    // find passing values
+    for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+    {
+      if (mrc_params->channel_enables & (0x1 << channel_i))
+      {
+        for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+        {
+          if (mrc_params->rank_enables & (0x1 << rank_i))
+          {
+            // get an address in the target channel/rank
+            address = get_addr(mrc_params, channel_i, rank_i);
+
+            // request HTE reconfiguration
+            mrc_params->hte_setup = 1;
+
+            // check the settings
+            do
+            {
+
+#ifdef SIM
+              // need restore memory to idle state as write can be in bad sync
+              dram_init_command (DCMD_PREA(rank_i));
+#endif
+
+              // result[07:00] == failing byte lane (MAX 8)
+              result = check_bls_ex( mrc_params, address);
+              // check for failures
+              if (result & 0xFF)
+              {
+                // at least 1 byte lane failed
+                for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+                {
+                  if (result & (bl_mask << bl_i))
+                  {
+                    if (side_i == L)
+                    {
+                      delay[L][channel_i][rank_i][bl_i] += WDQ_STEP;
+                    }
+                    else
+                    {
+                      delay[R][channel_i][rank_i][bl_i] -= WDQ_STEP;
+                    }
+                    // check for algorithm failure
+                    if (delay[L][channel_i][rank_i][bl_i] != delay[R][channel_i][rank_i][bl_i])
+                    {
+                      // margin available, update delay setting
+                      set_wdq(channel_i, rank_i, bl_i, delay[side_i][channel_i][rank_i][bl_i]);
+                    }
+                    else
+                    {
+                      // no margin available, notify the user and halt
+                      training_message(channel_i, rank_i, bl_i);
+                      post_code(0xEE, (0x80 + side_i));
+                    }
+                  } // if bl_i failed
+                } // bl_i loop
+              } // at least 1 byte lane failed
+            } while (result & 0xFF); // stop when all byte lanes pass
+          } // if rank is enabled
+        } // rank_i loop
+      } // if channel is enabled
+    } // channel_i loop
+  } // side_i loop
+
+  // program WDQ to the middle of passing window
+  for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1 << channel_i))
+    {
+      for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1 << rank_i))
+        {
+#ifdef R2R_SHARING
+          // increment "num_ranks_enabled"
+          num_ranks_enabled++;
+#endif // R2R_SHARING
+          for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+          {
+
+            DPF(D_INFO, "WDQ eye rank%d lane%d : %d-%d\n", rank_i, bl_i,
+                delay[L][channel_i][rank_i][bl_i],
+                delay[R][channel_i][rank_i][bl_i]);
+
+            tempD = (delay[R][channel_i][rank_i][bl_i] + delay[L][channel_i][rank_i][bl_i]) / 2;
+
+#ifdef R2R_SHARING
+            final_delay[channel_i][bl_i] += tempD;
+            set_wdq(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));
+#else
+            set_wdq(channel_i, rank_i, bl_i, tempD);
+#endif // R2R_SHARING
+
+          } // bl_i loop
+        } // if rank is enabled
+      } // rank_i loop
+    } // if channel is enabled
+  } // channel_i loop
+#endif // BACKUP_WDQ
+  LEAVEFN();
+  return;
+}
+
+// Wrapper for jedec initialisation routine
+static void perform_jedec_init(
+    MRCParams_t *mrc_params)
+{
+  jedec_init(mrc_params, 0);
+}
+
+// Configure DDRPHY for Auto-Refresh, Periodic Compensations,
+// Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
+static void set_auto_refresh(
+    MRCParams_t *mrc_params)
+{
+  uint32_t channel_i;
+  uint32_t rank_i;
+  uint32_t bl_i;
+  uint32_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/1;
+  uint32_t tempD;
+
+  ENTERFN();
+
+  // enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
+  for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+  {
+    if (mrc_params->channel_enables & (1 << channel_i))
+    {
+      // Enable Periodic RCOMPS
+      isbM32m(DDRPHY, CMPCTRL, (BIT1), (BIT1));
+
+
+      // Enable Dynamic DiffAmp & Set Read ODT Value
+      switch (mrc_params->rd_odt_value)
+      {
+        case 0: tempD = 0x3F; break;  // OFF
+        default: tempD = 0x00; break; // Auto
+      } // rd_odt_value switch
+
+      for (bl_i=0; bl_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_i++)
+      {
+        isbM32m(DDRPHY, (B0OVRCTL + (bl_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)),
+            ((0x00<<16)|(tempD<<10)),
+            ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT
+
+        isbM32m(DDRPHY, (B1OVRCTL + (bl_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)),
+            ((0x00<<16)|(tempD<<10)),
+            ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10)));// Override: DIFFAMP, ODT
+      } // bl_i loop
+
+      // Issue ZQCS command
+      for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+      {
+        if (mrc_params->rank_enables & (1 << rank_i))
+        {
+          dram_init_command(DCMD_ZQCS(rank_i));
+        } // if rank_i enabled
+      } // rank_i loop
+
+    } // if channel_i enabled
+  } // channel_i loop
+
+  clear_pointers();
+
+  LEAVEFN();
+  return;
+}
+
+// Depending on configuration enables ECC support.
+// Available memory size is decresed, and updated with 0s
+// in order to clear error status. Address mode 2 forced.
+static void ecc_enable(
+    MRCParams_t *mrc_params)
+{
+  RegDRP Drp;
+  RegDSCH Dsch;
+  RegDECCCTRL Ctr;
+
+  if (mrc_params->ecc_enables == 0) return;
+
+  ENTERFN();
+
+  // Configuration required in ECC mode
+  Drp.raw = isbR32m(MCU, DRP);
+  Drp.field.addressMap = 2;
+  Drp.field.split64 = 1;
+  isbW32m(MCU, DRP, Drp.raw);
+
+  // Disable new request bypass
+  Dsch.raw = isbR32m(MCU, DSCH);
+  Dsch.field.NEWBYPDIS = 1;
+  isbW32m(MCU, DSCH, Dsch.raw);
+
+  // Enable ECC
+  Ctr.raw = 0;
+  Ctr.field.SBEEN = 1;
+  Ctr.field.DBEEN = 1;
+  Ctr.field.ENCBGEN = 1;
+  isbW32m(MCU, DECCCTRL, Ctr.raw);
+
+#ifdef SIM
+  // Read back to be sure writing took place
+  Ctr.raw = isbR32m(MCU, DECCCTRL);
+#endif
+
+  // Assume 8 bank memory, one bank is gone for ECC
+  mrc_params->mem_size -= mrc_params->mem_size / 8;
+
+  // For S3 resume memory content has to be preserved
+  if (mrc_params->boot_mode != bmS3)
+  {
+    select_hte(mrc_params);
+    HteMemInit(mrc_params, MrcMemInit, MrcHaltHteEngineOnError);
+    select_memory_manager(mrc_params);
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// Lock MCU registers at the end of initialisation sequence.
+static void lock_registers(
+    MRCParams_t *mrc_params)
+{
+  RegDCO Dco;
+
+  ENTERFN();
+
+  Dco.raw = isbR32m(MCU, DCO);
+  Dco.field.PMIDIS = 0;          //0 - PRI enabled
+  Dco.field.PMICTL = 0;          //0 - PRI owned by MEMORY_MANAGER
+  Dco.field.DRPLOCK = 1;
+  Dco.field.REUTLOCK = 1;
+  isbW32m(MCU, DCO, Dco.raw);
+
+  LEAVEFN();
+
+}
+
+#ifdef MRC_SV
+
+// cache write back invalidate
+static void asm_wbinvd(void)
+{
+#if defined (SIM) || defined (GCC)
+  asm(
+    "wbinvd;"
+  );
+#else
+  __asm wbinvd;
+#endif
+}
+
+// cache invalidate
+static void asm_invd(void)
+{
+#if defined (SIM) || defined (GCC)
+  asm(
+      "invd;"
+  );
+#else
+  __asm invd;
+#endif
+}
+
+
+static void cpu_read(void)
+{
+  uint32_t adr, dat, limit;
+
+  asm_invd();
+
+  limit = 8 * 1024;
+  for (adr = 0; adr < limit; adr += 4)
+  {
+    dat = *(uint32_t*) adr;
+    if ((adr & 0x0F) == 0)
+    {
+      DPF(D_INFO, "\n%x : ", adr);
+    }
+    DPF(D_INFO, "%x ", dat);
+  }
+  DPF(D_INFO, "\n");
+
+  DPF(D_INFO, "CPU read done\n");
+}
+
+
+static void cpu_write(void)
+{
+  uint32_t adr, limit;
+
+  limit = 8 * 1024;
+  for (adr = 0; adr < limit; adr += 4)
+  {
+    *(uint32_t*) adr = 0xDEAD0000 + adr;
+  }
+
+  asm_wbinvd();
+
+  DPF(D_INFO, "CPU write done\n");
+}
+
+
+static void cpu_memory_test(
+    MRCParams_t *mrc_params)
+{
+  uint32_t result = 0;
+  uint32_t val, dat, adr, adr0, step, limit;
+  uint64_t my_tsc;
+
+  ENTERFN();
+
+  asm_invd();
+
+  adr0 = 1 * 1024 * 1024;
+  limit = 256 * 1024 * 1024;
+
+  for (step = 0; step <= 4; step++)
+  {
+    DPF(D_INFO, "Mem test step %d starting from %xh\n", step, adr0);
+
+    my_tsc = read_tsc();
+    for (adr = adr0; adr < limit; adr += sizeof(uint32_t))
+    {
+      if (step == 0)      dat = adr;
+      else if (step == 1) dat = (1 << ((adr >> 2) & 0x1f));
+      else if (step == 2) dat = ~(1 << ((adr >> 2) & 0x1f));
+      else if (step == 3) dat = 0x5555AAAA;
+      else if (step == 4) dat = 0xAAAA5555;
+
+      *(uint32_t*) adr = dat;
+    }
+    DPF(D_INFO, "Write time %llXh\n", read_tsc() - my_tsc);
+
+    my_tsc = read_tsc();
+    for (adr = adr0; adr < limit; adr += sizeof(uint32_t))
+    {
+      if (step == 0)      dat = adr;
+      else if (step == 1) dat = (1 << ((adr >> 2) & 0x1f));
+      else if (step == 2) dat = ~(1 << ((adr >> 2) & 0x1f));
+      else if (step == 3) dat = 0x5555AAAA;
+      else if (step == 4) dat = 0xAAAA5555;
+
+      val = *(uint32_t*) adr;
+
+      if (val != dat)
+      {
+        DPF(D_INFO, "%x vs. %x@%x\n", dat, val, adr);
+        result = adr|BIT31;
+      }
+    }
+    DPF(D_INFO, "Read time %llXh\n", read_tsc() - my_tsc);
+  }
+
+  DPF( D_INFO, "Memory test result %x\n", result);
+  LEAVEFN();
+}
+#endif // MRC_SV
+
+
+// Execute memory test, if error dtected it is
+// indicated in mrc_params->status.
+static void memory_test(
+  MRCParams_t *mrc_params)
+{
+  uint32_t result = 0;
+
+  ENTERFN();
+
+  select_hte(mrc_params);
+  result = HteMemInit(mrc_params, MrcMemTest, MrcHaltHteEngineOnError);
+  select_memory_manager(mrc_params);
+
+  DPF(D_INFO, "Memory test result %x\n", result);
+  mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST);
+  LEAVEFN();
+}
+
+
+// Force same timings as with backup settings
+static void static_timings(
+  MRCParams_t *mrc_params)
+
+{
+  uint8_t ch, rk, bl;
+
+  for (ch = 0; ch < NUM_CHANNELS; ch++)
+  {
+    for (rk = 0; rk < NUM_RANKS; rk++)
+    {
+      for (bl = 0; bl < NUM_BYTE_LANES; bl++)
+      {
+        set_rcvn(ch, rk, bl, 498);  // RCVN
+        set_rdqs(ch, rk, bl,  24);  // RDQS
+        set_wdqs(ch, rk, bl, 292);  // WDQS
+        set_wdq( ch, rk, bl, 260);  // WDQ
+        if (rk == 0)
+        {
+          set_vref(ch, bl, 32); // VREF (RANK0 only)
+        }
+      }
+      set_wctl(ch, rk, 217); // WCTL
+    }
+    set_wcmd(ch, 220); // WCMD
+  }
+
+  return;
+}
+
+//
+// Initialise system memory.
+//
+void MemInit(
+  MRCParams_t *mrc_params)
+{
+  static const MemInit_t init[] =
+  {
+    { 0x0101, bmCold|bmFast|bmWarm|bmS3, clear_self_refresh       }, //0
+    { 0x0200, bmCold|bmFast|bmWarm|bmS3, prog_ddr_timing_control  }, //1  initialise the MCU
+    { 0x0103, bmCold|bmFast            , prog_decode_before_jedec }, //2
+    { 0x0104, bmCold|bmFast            , perform_ddr_reset        }, //3
+    { 0x0300, bmCold|bmFast       |bmS3, ddrphy_init              }, //4  initialise the DDRPHY
+    { 0x0400, bmCold|bmFast            , perform_jedec_init       }, //5  perform JEDEC initialisation of DRAMs
+    { 0x0105, bmCold|bmFast            , set_ddr_init_complete    }, //6
+    { 0x0106,        bmFast|bmWarm|bmS3, restore_timings          }, //7
+    { 0x0106, bmCold                   , default_timings          }, //8
+    { 0x0500, bmCold                   , rcvn_cal                 }, //9  perform RCVN_CAL algorithm
+    { 0x0600, bmCold                   , wr_level                 }, //10  perform WR_LEVEL algorithm
+    { 0x0120, bmCold                   , prog_page_ctrl           }, //11
+    { 0x0700, bmCold                   , rd_train                 }, //12  perform RD_TRAIN algorithm
+    { 0x0800, bmCold                   , wr_train                 }, //13  perform WR_TRAIN algorithm
+    { 0x010B, bmCold                   , store_timings            }, //14
+    { 0x010C, bmCold|bmFast|bmWarm|bmS3, enable_scrambling        }, //15
+    { 0x010D, bmCold|bmFast|bmWarm|bmS3, prog_ddr_control         }, //16
+    { 0x010E, bmCold|bmFast|bmWarm|bmS3, prog_dra_drb             }, //17
+    { 0x010F,               bmWarm|bmS3, perform_wake             }, //18
+    { 0x0110, bmCold|bmFast|bmWarm|bmS3, change_refresh_period    }, //19
+    { 0x0111, bmCold|bmFast|bmWarm|bmS3, set_auto_refresh         }, //20
+    { 0x0112, bmCold|bmFast|bmWarm|bmS3, ecc_enable               }, //21
+    { 0x0113, bmCold|bmFast            , memory_test              }, //22
+    { 0x0114, bmCold|bmFast|bmWarm|bmS3, lock_registers           }  //23 set init done
+  };
+
+  uint32_t i;
+
+  ENTERFN();
+
+  DPF(D_INFO, "Meminit build %s %s\n", __DATE__, __TIME__);
+
+  // MRC started
+  post_code(0x01, 0x00);
+
+  if (mrc_params->boot_mode != bmCold)
+  {
+    if (mrc_params->ddr_speed != mrc_params->timings.ddr_speed)
+    {
+      // full training required as frequency changed
+      mrc_params->boot_mode = bmCold;
+    }
+  }
+
+  for (i = 0; i < MCOUNT(init); i++)
+  {
+    uint64_t my_tsc;
+
+#ifdef MRC_SV
+    if (mrc_params->menu_after_mrc && i > 14)
+    {
+      uint8_t ch;
+
+      mylop:
+
+      DPF(D_INFO, "-- c - continue --\n");
+      DPF(D_INFO, "-- j - move to jedec init --\n");
+      DPF(D_INFO, "-- m - memory test --\n");
+      DPF(D_INFO, "-- r - cpu read --\n");
+      DPF(D_INFO, "-- w - cpu write --\n");
+      DPF(D_INFO, "-- b - hte base test --\n");
+      DPF(D_INFO, "-- g - hte extended test --\n");
+
+      ch = mgetc();
+      switch (ch)
+      {
+      case 'c':
+        break;
+      case 'j':  //move to jedec init
+        i = 5;
+        break;
+
+      case 'M':
+      case 'N':
+        {
+    uint32_t n, res, cnt=0;
+
+    for(n=0; mgetch()==0; n++)
+    {
+      if( ch == 'M' || n % 256 == 0)
+      {
+        DPF(D_INFO, "n=%d e=%d\n", n, cnt);
+      }
+
+      res = 0;
+
+      if( ch == 'M')
+      {
+        memory_test(mrc_params);
+        res |= mrc_params->status;
+            }
+
+      mrc_params->hte_setup = 1;
+            res |= check_bls_ex(mrc_params, 0x00000000);
+            res |= check_bls_ex(mrc_params, 0x00000000);
+            res |= check_bls_ex(mrc_params, 0x00000000);
+            res |= check_bls_ex(mrc_params, 0x00000000);
+
+      if( mrc_params->rank_enables & 2)
+      {
+        mrc_params->hte_setup = 1;
+              res |= check_bls_ex(mrc_params, 0x40000000);
+              res |= check_bls_ex(mrc_params, 0x40000000);
+              res |= check_bls_ex(mrc_params, 0x40000000);
+              res |= check_bls_ex(mrc_params, 0x40000000);
+      }
+
+      if( res != 0)
+      {
+              DPF(D_INFO, "###########\n");
+              DPF(D_INFO, "#\n");
+              DPF(D_INFO, "# Error count %d\n", ++cnt);
+              DPF(D_INFO, "#\n");
+              DPF(D_INFO, "###########\n");
+      }
+
+    } // for
+
+          select_memory_manager(mrc_params);
+  }
+        goto mylop;
+      case 'm':
+        memory_test(mrc_params);
+        goto mylop;
+      case 'n':
+        cpu_memory_test(mrc_params);
+        goto mylop;
+
+      case 'l':
+        ch = mgetc();
+        if (ch <= '9') DpfPrintMask ^= (ch - '0') << 3;
+        DPF(D_INFO, "Log mask %x\n", DpfPrintMask);
+        goto mylop;
+      case 'p':
+        print_timings(mrc_params);
+        goto mylop;
+      case 'R':
+        rd_train(mrc_params);
+        goto mylop;
+      case 'W':
+        wr_train(mrc_params);
+        goto mylop;
+
+      case 'r':
+        cpu_read();
+        goto mylop;
+      case 'w':
+        cpu_write();
+        goto mylop;
+
+      case 'g':
+        {
+        uint32_t result;
+        select_hte(mrc_params);
+        mrc_params->hte_setup = 1;
+        result = check_bls_ex(mrc_params, 0);
+        DPF(D_INFO, "Extended test result %x\n", result);
+        select_memory_manager(mrc_params);
+        }
+        goto mylop;
+      case 'b':
+        {
+        uint32_t result;
+        select_hte(mrc_params);
+        mrc_params->hte_setup = 1;
+        result = check_rw_coarse(mrc_params, 0);
+        DPF(D_INFO, "Base test result %x\n", result);
+        select_memory_manager(mrc_params);
+        }
+        goto mylop;
+      case 'B':
+        select_hte(mrc_params);
+        HteMemOp(0x2340, 1, 1);
+        select_memory_manager(mrc_params);
+        goto mylop;
+
+      case '3':
+        {
+        RegDPMC0 DPMC0reg;
+
+        DPF( D_INFO, "===>> Start suspend\n");
+        isbR32m(MCU, DSTAT);
+
+        DPMC0reg.raw = isbR32m(MCU, DPMC0);
+        DPMC0reg.field.DYNSREN = 0;
+        DPMC0reg.field.powerModeOpCode = 0x05;    // Disable Master DLL
+        isbW32m(MCU, DPMC0, DPMC0reg.raw);
+
+        // Should be off for negative test case verification
+        #if 1
+        Wr32(MMIO, PCIADDR(0,0,0,SB_PACKET_REG),
+            (uint32_t)SB_COMMAND(SB_SUSPEND_CMND_OPCODE, MCU, 0));
+        #endif
+
+        DPF( D_INFO, "press key\n");
+        mgetc();
+        DPF( D_INFO, "===>> Start resume\n");
+        isbR32m(MCU, DSTAT);
+
+        mrc_params->boot_mode = bmS3;
+        i = 0;
+        }
+
+      } // switch
+
+    } // if( menu
+#endif //MRC_SV
+
+    if (mrc_params->boot_mode & init[i].boot_path)
+    {
+      uint8_t major = init[i].post_code >> 8 & 0xFF;
+      uint8_t minor = init[i].post_code >> 0 & 0xFF;
+      post_code(major, minor);
+
+      my_tsc = read_tsc();
+      init[i].init_fn(mrc_params);
+      DPF(D_TIME, "Execution time %llX", read_tsc() - my_tsc);
+    }
+  }
+
+  // display the timings
+  print_timings(mrc_params);
+
+  // MRC is complete.
+  post_code(0x01, 0xFF);
+
+  LEAVEFN();
+  return;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h
new file mode 100644
index 0000000000..961bbef9c7
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h
@@ -0,0 +1,22 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ ************************************************************************/
+#ifndef _MEMINIT_H_
+#define _MEMINIT_H_
+
+// function prototypes
+void MemInit(MRCParams_t *mrc_params);
+
+typedef void (*MemInitFn_t)(MRCParams_t *mrc_params);
+
+typedef struct MemInit_s {
+  uint16_t    post_code;
+  uint16_t    boot_path;
+  MemInitFn_t init_fn;
+} MemInit_t;
+
+#endif // _MEMINIT_H_
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c
new file mode 100644
index 0000000000..84de65955f
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c
@@ -0,0 +1,1574 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ ***************************************************************************/
+
+#include "mrc.h"
+#include "memory_options.h"
+
+#include "meminit_utils.h"
+#include "hte.h"
+#include "io.h"
+
+void select_hte(
+    MRCParams_t *mrc_params);
+
+static uint8_t first_run = 0;
+
+const uint8_t vref_codes[64] =
+{ // lowest to highest
+    0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, // 00 - 15
+    0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, // 16 - 31
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 32 - 47
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F  // 48 - 63
+};
+
+#ifdef EMU
+// Track current post code for debugging purpose
+uint32_t PostCode;
+#endif
+
+// set_rcvn:
+//
+// This function will program the RCVEN delays.
+// (currently doesn't comprehend rank)
+void set_rcvn(
+    uint8_t channel,
+    uint8_t rank,
+    uint8_t byte_lane,
+    uint32_t pi_count)
+{
+  uint32_t reg;
+  uint32_t msk;
+  uint32_t tempD;
+
+  ENTERFN();
+  DPF(D_TRN, "Rcvn ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);
+
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
+  // BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
+  reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+  msk = (byte_lane & BIT0) ? (BIT23 | BIT22 | BIT21 | BIT20) : (BIT11 | BIT10 | BIT9 | BIT8);
+  tempD = (byte_lane & BIT0) ? ((pi_count / HALF_CLK) << 20) : ((pi_count / HALF_CLK) << 8);
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // Adjust PI_COUNT
+  pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
+  // BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
+  reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+  reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+  msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24);
+  tempD = pi_count << 24;
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // DEADBAND
+  // BL0/1 -> B01DBCTL1[08/11] (+1 select)
+  // BL0/1 -> B01DBCTL1[02/05] (enable)
+  reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+  msk = 0x00;
+  tempD = 0x00;
+  // enable
+  msk |= (byte_lane & BIT0) ? (BIT5) : (BIT2);
+  if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+  {
+    tempD |= msk;
+  }
+  // select
+  msk |= (byte_lane & BIT0) ? (BIT11) : (BIT8);
+  if (pi_count < EARLY_DB)
+  {
+    tempD |= msk;
+  }
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // error check
+  if (pi_count > 0x3F)
+  {
+    training_message(channel, rank, byte_lane);
+    post_code(0xEE, 0xE0);
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// get_rcvn:
+//
+// This function will return the current RCVEN delay on the given channel, rank, byte_lane as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_rcvn(
+    uint8_t channel,
+    uint8_t rank,
+    uint8_t byte_lane)
+{
+  uint32_t reg;
+  uint32_t tempD;
+  uint32_t pi_count;
+
+  ENTERFN();
+
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
+  // BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
+  reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= (byte_lane & BIT0) ? (20) : (8);
+  tempD &= 0xF;
+
+  // Adjust PI_COUNT
+  pi_count = tempD * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
+  // BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
+  reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+  reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= 24;
+  tempD &= 0x3F;
+
+  // Adjust PI_COUNT
+  pi_count += tempD;
+
+  LEAVEFN();
+  return pi_count;
+}
+
+// set_rdqs:
+//
+// This function will program the RDQS delays based on an absolute amount of PIs.
+// (currently doesn't comprehend rank)
+void set_rdqs(
+    uint8_t channel,
+    uint8_t rank,
+    uint8_t byte_lane,
+    uint32_t pi_count)
+{
+  uint32_t reg;
+  uint32_t msk;
+  uint32_t tempD;
+
+  ENTERFN();
+  DPF(D_TRN, "Rdqs ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);
+
+  // PI (1/128 MCLK)
+  // BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
+  // BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
+  reg = (byte_lane & BIT0) ? (B1RXDQSPICODE) : (B0RXDQSPICODE);
+  reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+  msk = (BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+  tempD = pi_count << 0;
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // error check (shouldn't go above 0x3F)
+  if (pi_count > 0x47)
+  {
+    training_message(channel, rank, byte_lane);
+    post_code(0xEE, 0xE1);
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// get_rdqs:
+//
+// This function will return the current RDQS delay on the given channel, rank, byte_lane as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_rdqs(
+    uint8_t channel,
+    uint8_t rank,
+    uint8_t byte_lane)
+{
+  uint32_t reg;
+  uint32_t tempD;
+  uint32_t pi_count;
+
+  ENTERFN();
+
+  // PI (1/128 MCLK)
+  // BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
+  // BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
+  reg = (byte_lane & BIT0) ? (B1RXDQSPICODE) : (B0RXDQSPICODE);
+  reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+  tempD = isbR32m(DDRPHY, reg);
+
+  // Adjust PI_COUNT
+  pi_count = tempD & 0x7F;
+
+  LEAVEFN();
+  return pi_count;
+}
+
+// set_wdqs:
+//
+// This function will program the WDQS delays based on an absolute amount of PIs.
+// (currently doesn't comprehend rank)
+void set_wdqs(
+    uint8_t channel,
+    uint8_t rank,
+    uint8_t byte_lane,
+    uint32_t pi_count)
+{
+  uint32_t reg;
+  uint32_t msk;
+  uint32_t tempD;
+
+  ENTERFN();
+  DPF(D_TRN, "Wdqs ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);
+
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
+  // BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
+  reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+  msk = (byte_lane & BIT0) ? (BIT19 | BIT18 | BIT17 | BIT16) : (BIT7 | BIT6 | BIT5 | BIT4);
+  tempD = pi_count / HALF_CLK;
+  tempD <<= (byte_lane & BIT0) ? (16) : (4);
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // Adjust PI_COUNT
+  pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
+  // BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
+  reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+  reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+  msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16);
+  tempD = pi_count << 16;
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // DEADBAND
+  // BL0/1 -> B01DBCTL1[07/10] (+1 select)
+  // BL0/1 -> B01DBCTL1[01/04] (enable)
+  reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+  msk = 0x00;
+  tempD = 0x00;
+  // enable
+  msk |= (byte_lane & BIT0) ? (BIT4) : (BIT1);
+  if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+  {
+    tempD |= msk;
+  }
+  // select
+  msk |= (byte_lane & BIT0) ? (BIT10) : (BIT7);
+  if (pi_count < EARLY_DB)
+  {
+    tempD |= msk;
+  }
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // error check
+  if (pi_count > 0x3F)
+  {
+    training_message(channel, rank, byte_lane);
+    post_code(0xEE, 0xE2);
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// get_wdqs:
+//
+// This function will return the amount of WDQS delay on the given channel, rank, byte_lane as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_wdqs(
+    uint8_t channel,
+    uint8_t rank,
+    uint8_t byte_lane)
+{
+  uint32_t reg;
+  uint32_t tempD;
+  uint32_t pi_count;
+
+  ENTERFN();
+
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
+  // BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
+  reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= (byte_lane & BIT0) ? (16) : (4);
+  tempD &= 0xF;
+
+  // Adjust PI_COUNT
+  pi_count = (tempD * HALF_CLK);
+
+  // PI (1/64 MCLK, 1 PIs)
+  // BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
+  // BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
+  reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+  reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= 16;
+  tempD &= 0x3F;
+
+  // Adjust PI_COUNT
+  pi_count += tempD;
+
+  LEAVEFN();
+  return pi_count;
+}
+
+// set_wdq:
+//
+// This function will program the WDQ delays based on an absolute number of PIs.
+// (currently doesn't comprehend rank)
+void set_wdq(
+    uint8_t channel,
+    uint8_t rank,
+    uint8_t byte_lane,
+    uint32_t pi_count)
+{
+  uint32_t reg;
+  uint32_t msk;
+  uint32_t tempD;
+
+  ENTERFN();
+  DPF(D_TRN, "Wdq ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);
+
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
+  // BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
+  reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+  msk = (byte_lane & BIT0) ? (BIT15 | BIT14 | BIT13 | BIT12) : (BIT3 | BIT2 | BIT1 | BIT0);
+  tempD = pi_count / HALF_CLK;
+  tempD <<= (byte_lane & BIT0) ? (12) : (0);
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // Adjust PI_COUNT
+  pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
+  // BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
+  reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+  reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+  msk = (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8);
+  tempD = pi_count << 8;
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // DEADBAND
+  // BL0/1 -> B01DBCTL1[06/09] (+1 select)
+  // BL0/1 -> B01DBCTL1[00/03] (enable)
+  reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+  msk = 0x00;
+  tempD = 0x00;
+  // enable
+  msk |= (byte_lane & BIT0) ? (BIT3) : (BIT0);
+  if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+  {
+    tempD |= msk;
+  }
+  // select
+  msk |= (byte_lane & BIT0) ? (BIT9) : (BIT6);
+  if (pi_count < EARLY_DB)
+  {
+    tempD |= msk;
+  }
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // error check
+  if (pi_count > 0x3F)
+  {
+    training_message(channel, rank, byte_lane);
+    post_code(0xEE, 0xE3);
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// get_wdq:
+//
+// This function will return the amount of WDQ delay on the given channel, rank, byte_lane as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_wdq(
+    uint8_t channel,
+    uint8_t rank,
+    uint8_t byte_lane)
+{
+  uint32_t reg;
+  uint32_t tempD;
+  uint32_t pi_count;
+
+  ENTERFN();
+
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
+  // BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
+  reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= (byte_lane & BIT0) ? (12) : (0);
+  tempD &= 0xF;
+
+  // Adjust PI_COUNT
+  pi_count = (tempD * HALF_CLK);
+
+  // PI (1/64 MCLK, 1 PIs)
+  // BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
+  // BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
+  reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+  reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= 8;
+  tempD &= 0x3F;
+
+  // Adjust PI_COUNT
+  pi_count += tempD;
+
+  LEAVEFN();
+  return pi_count;
+}
+
+// set_wcmd:
+//
+// This function will program the WCMD delays based on an absolute number of PIs.
+void set_wcmd(
+    uint8_t channel,
+    uint32_t pi_count)
+{
+  uint32_t reg;
+  uint32_t msk;
+  uint32_t tempD;
+
+  ENTERFN();
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // CMDPTRREG[11:08] (0x0-0xF)
+  reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+  msk = (BIT11 | BIT10 | BIT9 | BIT8);
+  tempD = pi_count / HALF_CLK;
+  tempD <<= 8;
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // Adjust PI_COUNT
+  pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
+  // CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
+  // CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
+  // CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
+  // CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
+  // CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
+  // CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
+  // CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
+  reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET);
+
+  msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24) | (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16)
+      | (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8) | (BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+
+  tempD = (pi_count << 24) | (pi_count << 16) | (pi_count << 8) | (pi_count << 0);
+
+  isbM32m(DDRPHY, reg, tempD, msk);
+  reg = CMDDLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET); // PO
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // DEADBAND
+  // CMDCFGREG0[17] (+1 select)
+  // CMDCFGREG0[16] (enable)
+  reg = CMDCFGREG0 + (channel * DDRIOCCC_CH_OFFSET);
+  msk = 0x00;
+  tempD = 0x00;
+  // enable
+  msk |= BIT16;
+  if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+  {
+    tempD |= msk;
+  }
+  // select
+  msk |= BIT17;
+  if (pi_count < EARLY_DB)
+  {
+    tempD |= msk;
+  }
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // error check
+  if (pi_count > 0x3F)
+  {
+    post_code(0xEE, 0xE4);
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// get_wcmd:
+//
+// This function will return the amount of WCMD delay on the given channel as an absolute PI count.
+uint32_t get_wcmd(
+    uint8_t channel)
+{
+  uint32_t reg;
+  uint32_t tempD;
+  uint32_t pi_count;
+
+  ENTERFN();
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // CMDPTRREG[11:08] (0x0-0xF)
+  reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= 8;
+  tempD &= 0xF;
+
+  // Adjust PI_COUNT
+  pi_count = tempD * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
+  // CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
+  // CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
+  // CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
+  // CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
+  // CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
+  // CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
+  // CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
+  reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET);
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= 16;
+  tempD &= 0x3F;
+
+  // Adjust PI_COUNT
+  pi_count += tempD;
+
+  LEAVEFN();
+  return pi_count;
+}
+
+// set_wclk:
+//
+// This function will program the WCLK delays based on an absolute number of PIs.
+void set_wclk(
+    uint8_t channel,
+    uint8_t rank,
+    uint32_t pi_count)
+{
+  uint32_t reg;
+  uint32_t msk;
+  uint32_t tempD;
+
+  ENTERFN();
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // CCPTRREG[15:12] -> CLK1 (0x0-0xF)
+  // CCPTRREG[11:08] -> CLK0 (0x0-0xF)
+  reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+  msk = (BIT15 | BIT14 | BIT13 | BIT12) | (BIT11 | BIT10 | BIT9 | BIT8);
+  tempD = ((pi_count / HALF_CLK) << 12) | ((pi_count / HALF_CLK) << 8);
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // Adjust PI_COUNT
+  pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
+  // ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
+  reg = (rank) ? (ECCB1DLLPICODER0) : (ECCB1DLLPICODER0);
+  reg += (channel * DDRIOCCC_CH_OFFSET);
+  msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16) | (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8);
+  tempD = (pi_count << 16) | (pi_count << 8);
+  isbM32m(DDRPHY, reg, tempD, msk);
+  reg = (rank) ? (ECCB1DLLPICODER1) : (ECCB1DLLPICODER1);
+  reg += (channel * DDRIOCCC_CH_OFFSET);
+  isbM32m(DDRPHY, reg, tempD, msk);
+  reg = (rank) ? (ECCB1DLLPICODER2) : (ECCB1DLLPICODER2);
+  reg += (channel * DDRIOCCC_CH_OFFSET);
+  isbM32m(DDRPHY, reg, tempD, msk);
+  reg = (rank) ? (ECCB1DLLPICODER3) : (ECCB1DLLPICODER3);
+  reg += (channel * DDRIOCCC_CH_OFFSET);
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // DEADBAND
+  // CCCFGREG1[11:08] (+1 select)
+  // CCCFGREG1[03:00] (enable)
+  reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET);
+  msk = 0x00;
+  tempD = 0x00;
+  // enable
+  msk |= (BIT3 | BIT2 | BIT1 | BIT0); // only ??? matters
+  if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+  {
+    tempD |= msk;
+  }
+  // select
+  msk |= (BIT11 | BIT10 | BIT9 | BIT8); // only ??? matters
+  if (pi_count < EARLY_DB)
+  {
+    tempD |= msk;
+  }
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // error check
+  if (pi_count > 0x3F)
+  {
+    post_code(0xEE, 0xE5);
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// get_wclk:
+//
+// This function will return the amout of WCLK delay on the given channel, rank as an absolute PI count.
+uint32_t get_wclk(
+    uint8_t channel,
+    uint8_t rank)
+{
+  uint32_t reg;
+  uint32_t tempD;
+  uint32_t pi_count;
+
+  ENTERFN();
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // CCPTRREG[15:12] -> CLK1 (0x0-0xF)
+  // CCPTRREG[11:08] -> CLK0 (0x0-0xF)
+  reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= (rank) ? (12) : (8);
+  tempD &= 0xF;
+
+  // Adjust PI_COUNT
+  pi_count = tempD * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
+  // ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
+  reg = (rank) ? (ECCB1DLLPICODER0) : (ECCB1DLLPICODER0);
+  reg += (channel * DDRIOCCC_CH_OFFSET);
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= (rank) ? (16) : (8);
+  tempD &= 0x3F;
+
+  pi_count += tempD;
+
+  LEAVEFN();
+  return pi_count;
+}
+
+// set_wctl:
+//
+// This function will program the WCTL delays based on an absolute number of PIs.
+// (currently doesn't comprehend rank)
+void set_wctl(
+    uint8_t channel,
+    uint8_t rank,
+    uint32_t pi_count)
+{
+  uint32_t reg;
+  uint32_t msk;
+  uint32_t tempD;
+
+  ENTERFN();
+
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // CCPTRREG[31:28] (0x0-0xF)
+  // CCPTRREG[27:24] (0x0-0xF)
+  reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+  msk = (BIT31 | BIT30 | BIT29 | BIT28) | (BIT27 | BIT26 | BIT25 | BIT24);
+  tempD = ((pi_count / HALF_CLK) << 28) | ((pi_count / HALF_CLK) << 24);
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // Adjust PI_COUNT
+  pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // ECCB1DLLPICODER?[29:24] (0x00-0x3F)
+  // ECCB1DLLPICODER?[29:24] (0x00-0x3F)
+  reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET);
+  msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24);
+  tempD = (pi_count << 24);
+  isbM32m(DDRPHY, reg, tempD, msk);
+  reg = ECCB1DLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET);
+  isbM32m(DDRPHY, reg, tempD, msk);
+  reg = ECCB1DLLPICODER2 + (channel * DDRIOCCC_CH_OFFSET);
+  isbM32m(DDRPHY, reg, tempD, msk);
+  reg = ECCB1DLLPICODER3 + (channel * DDRIOCCC_CH_OFFSET);
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // DEADBAND
+  // CCCFGREG1[13:12] (+1 select)
+  // CCCFGREG1[05:04] (enable)
+  reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET);
+  msk = 0x00;
+  tempD = 0x00;
+  // enable
+  msk |= (BIT5 | BIT4); // only ??? matters
+  if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+  {
+    tempD |= msk;
+  }
+  // select
+  msk |= (BIT13 | BIT12); // only ??? matters
+  if (pi_count < EARLY_DB)
+  {
+    tempD |= msk;
+  }
+  isbM32m(DDRPHY, reg, tempD, msk);
+
+  // error check
+  if (pi_count > 0x3F)
+  {
+    post_code(0xEE, 0xE6);
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// get_wctl:
+//
+// This function will return the amount of WCTL delay on the given channel, rank as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_wctl(
+    uint8_t channel,
+    uint8_t rank)
+{
+  uint32_t reg;
+  uint32_t tempD;
+  uint32_t pi_count;
+
+  ENTERFN();
+
+  // RDPTR (1/2 MCLK, 64 PIs)
+  // CCPTRREG[31:28] (0x0-0xF)
+  // CCPTRREG[27:24] (0x0-0xF)
+  reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= 24;
+  tempD &= 0xF;
+
+  // Adjust PI_COUNT
+  pi_count = tempD * HALF_CLK;
+
+  // PI (1/64 MCLK, 1 PIs)
+  // ECCB1DLLPICODER?[29:24] (0x00-0x3F)
+  // ECCB1DLLPICODER?[29:24] (0x00-0x3F)
+  reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET);
+  tempD = isbR32m(DDRPHY, reg);
+  tempD >>= 24;
+  tempD &= 0x3F;
+
+  // Adjust PI_COUNT
+  pi_count += tempD;
+
+  LEAVEFN();
+  return pi_count;
+}
+
+// set_vref:
+//
+// This function will program the internal Vref setting in a given byte lane in a given channel.
+void set_vref(
+    uint8_t channel,
+    uint8_t byte_lane,
+    uint32_t setting)
+{
+  uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL);
+
+  ENTERFN();
+  DPF(D_TRN, "Vref ch%d ln%d : val=%03X\n", channel, byte_lane, setting);
+
+  isbM32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)),
+      (vref_codes[setting] << 2), (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2));
+  //isbM32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)), (setting<<2), (BIT7|BIT6|BIT5|BIT4|BIT3|BIT2));
+  // need to wait ~300ns for Vref to settle (check that this is necessary)
+  delay_n(300);
+  // ??? may need to clear pointers ???
+  LEAVEFN();
+  return;
+}
+
+// get_vref:
+//
+// This function will return the internal Vref setting for the given channel, byte_lane;
+uint32_t get_vref(
+    uint8_t channel,
+    uint8_t byte_lane)
+{
+  uint8_t j;
+  uint32_t ret_val = sizeof(vref_codes) / 2;
+  uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL);
+
+  uint32_t tempD;
+
+  ENTERFN();
+  tempD = isbR32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)));
+  tempD >>= 2;
+  tempD &= 0x3F;
+  for (j = 0; j < sizeof(vref_codes); j++)
+  {
+    if (vref_codes[j] == tempD)
+    {
+      ret_val = j;
+      break;
+    }
+  }
+  LEAVEFN();
+  return ret_val;
+}
+
+// clear_pointers:
+//
+// This function will be used to clear the pointers in a given byte lane in a given channel.
+void clear_pointers(
+    void)
+{
+  uint8_t channel_i;
+  uint8_t bl_i;
+
+  ENTERFN();
+  for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+  {
+    for (bl_i = 0; bl_i < NUM_BYTE_LANES; bl_i++)
+    {
+      isbM32m(DDRPHY, (B01PTRCTL1 + (channel_i * DDRIODQ_CH_OFFSET) + ((bl_i >> 1) * DDRIODQ_BL_OFFSET)), ~(BIT8),
+          (BIT8));
+      //delay_m(1); // DEBUG
+      isbM32m(DDRPHY, (B01PTRCTL1 + (channel_i * DDRIODQ_CH_OFFSET) + ((bl_i >> 1) * DDRIODQ_BL_OFFSET)), (BIT8),
+          (BIT8));
+    }
+  }
+  LEAVEFN();
+  return;
+}
+
+// void enable_cache:
+void enable_cache(
+    void)
+{
+  // Cache control not used in Quark MRC
+  return;
+}
+
+// void disable_cache:
+void disable_cache(
+    void)
+{
+  // Cache control not used in Quark MRC
+  return;
+}
+
+// Send DRAM command, data should be formated
+// using DCMD_Xxxx macro or emrsXCommand structure.
+static void dram_init_command(
+    uint32_t data)
+{
+  Wr32(DCMD, 0, data);
+}
+
+// find_rising_edge:
+//
+// This function will find the rising edge transition on RCVN or WDQS.
+void find_rising_edge(
+    MRCParams_t *mrc_params,
+    uint32_t delay[],
+    uint8_t channel,
+    uint8_t rank,
+    bool rcvn)
+{
+
+#define SAMPLE_CNT 3   // number of sample points
+#define SAMPLE_DLY 26  // number of PIs to increment per sample
+#define FORWARD true   // indicates to increase delays when looking for edge
+#define BACKWARD false // indicates to decrease delays when looking for edge
+
+  bool all_edges_found; // determines stop condition
+  bool direction[NUM_BYTE_LANES]; // direction indicator
+  uint8_t sample_i; // sample counter
+  uint8_t bl_i; // byte lane counter
+  uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+  uint32_t sample_result[SAMPLE_CNT]; // results of "sample_dqs()"
+  uint32_t tempD; // temporary DWORD
+  uint32_t transition_pattern;
+
+  ENTERFN();
+
+  // select hte and request initial configuration
+  select_hte(mrc_params);
+  first_run = 1;
+
+  // Take 3 sample points (T1,T2,T3) to obtain a transition pattern.
+  for (sample_i = 0; sample_i < SAMPLE_CNT; sample_i++)
+  {
+    // program the desired delays for sample
+    for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+    {
+      // increase sample delay by 26 PI (0.2 CLK)
+      if (rcvn)
+      {
+        set_rcvn(channel, rank, bl_i, delay[bl_i] + (sample_i * SAMPLE_DLY));
+      }
+      else
+      {
+        set_wdqs(channel, rank, bl_i, delay[bl_i] + (sample_i * SAMPLE_DLY));
+      }
+    } // bl_i loop
+    // take samples (Tsample_i)
+    sample_result[sample_i] = sample_dqs(mrc_params, channel, rank, rcvn);
+
+    DPF(D_TRN, "Find rising edge %s ch%d rnk%d: #%d dly=%d dqs=%02X\n",
+        (rcvn ? "RCVN" : "WDQS"), channel, rank,
+        sample_i, sample_i * SAMPLE_DLY, sample_result[sample_i]);
+
+  } // sample_i loop
+
+  // This pattern will help determine where we landed and ultimately how to place RCVEN/WDQS.
+  for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+  {
+    // build "transition_pattern" (MSB is 1st sample)
+    transition_pattern = 0x00;
+    for (sample_i = 0; sample_i < SAMPLE_CNT; sample_i++)
+    {
+      transition_pattern |= ((sample_result[sample_i] & (1 << bl_i)) >> bl_i) << (SAMPLE_CNT - 1 - sample_i);
+    } // sample_i loop
+
+    DPF(D_TRN, "=== transition pattern %d\n", transition_pattern);
+
+    // set up to look for rising edge based on "transition_pattern"
+    switch (transition_pattern)
+    {
+    case 0x00: // sampled 0->0->0
+      // move forward from T3 looking for 0->1
+      delay[bl_i] += 2 * SAMPLE_DLY;
+      direction[bl_i] = FORWARD;
+      break;
+    case 0x01: // sampled 0->0->1
+    case 0x05: // sampled 1->0->1 (bad duty cycle) *HSD#237503*
+      // move forward from T2 looking for 0->1
+      delay[bl_i] += 1 * SAMPLE_DLY;
+      direction[bl_i] = FORWARD;
+      break;
+// HSD#237503
+//      case 0x02: // sampled 0->1->0 (bad duty cycle)
+//        training_message(channel, rank, bl_i);
+//        post_code(0xEE, 0xE8);
+//        break;
+    case 0x02: // sampled 0->1->0 (bad duty cycle) *HSD#237503*
+    case 0x03: // sampled 0->1->1
+      // move forward from T1 looking for 0->1
+      delay[bl_i] += 0 * SAMPLE_DLY;
+      direction[bl_i] = FORWARD;
+      break;
+    case 0x04: // sampled 1->0->0 (assumes BL8, HSD#234975)
+      // move forward from T3 looking for 0->1
+      delay[bl_i] += 2 * SAMPLE_DLY;
+      direction[bl_i] = FORWARD;
+      break;
+// HSD#237503
+//      case 0x05: // sampled 1->0->1 (bad duty cycle)
+//        training_message(channel, rank, bl_i);
+//        post_code(0xEE, 0xE9);
+//        break;
+    case 0x06: // sampled 1->1->0
+    case 0x07: // sampled 1->1->1
+      // move backward from T1 looking for 1->0
+      delay[bl_i] += 0 * SAMPLE_DLY;
+      direction[bl_i] = BACKWARD;
+      break;
+    default:
+      post_code(0xEE, 0xEE);
+      break;
+    } // transition_pattern switch
+    // program delays
+    if (rcvn)
+    {
+      set_rcvn(channel, rank, bl_i, delay[bl_i]);
+    }
+    else
+    {
+      set_wdqs(channel, rank, bl_i, delay[bl_i]);
+    }
+  } // bl_i loop
+
+  // Based on the observed transition pattern on the byte lane,
+  // begin looking for a rising edge with single PI granularity.
+  do
+  {
+    all_edges_found = true; // assume all byte lanes passed
+    tempD = sample_dqs(mrc_params, channel, rank, rcvn); // take a sample
+    // check all each byte lane for proper edge
+    for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+    {
+      if (tempD & (1 << bl_i))
+      {
+        // sampled "1"
+        if (direction[bl_i] == BACKWARD)
+        {
+          // keep looking for edge on this byte lane
+          all_edges_found = false;
+          delay[bl_i] -= 1;
+          if (rcvn)
+          {
+            set_rcvn(channel, rank, bl_i, delay[bl_i]);
+          }
+          else
+          {
+            set_wdqs(channel, rank, bl_i, delay[bl_i]);
+          }
+        }
+      }
+      else
+      {
+        // sampled "0"
+        if (direction[bl_i] == FORWARD)
+        {
+          // keep looking for edge on this byte lane
+          all_edges_found = false;
+          delay[bl_i] += 1;
+          if (rcvn)
+          {
+            set_rcvn(channel, rank, bl_i, delay[bl_i]);
+          }
+          else
+          {
+            set_wdqs(channel, rank, bl_i, delay[bl_i]);
+          }
+        }
+      }
+    } // bl_i loop
+  } while (!all_edges_found);
+
+  // restore DDR idle state
+  dram_init_command(DCMD_PREA(rank));
+
+  DPF(D_TRN, "Delay %03X %03X %03X %03X\n",
+      delay[0], delay[1], delay[2], delay[3]);
+
+  LEAVEFN();
+  return;
+}
+
+// sample_dqs:
+//
+// This function will sample the DQTRAINSTS registers in the given channel/rank SAMPLE_SIZE times looking for a valid '0' or '1'.
+// It will return an encoded DWORD in which each bit corresponds to the sampled value on the byte lane.
+uint32_t sample_dqs(
+    MRCParams_t *mrc_params,
+    uint8_t channel,
+    uint8_t rank,
+    bool rcvn)
+{
+  uint8_t j; // just a counter
+  uint8_t bl_i; // which BL in the module (always 2 per module)
+  uint8_t bl_grp; // which BL module
+  uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+  uint32_t msk[2]; // BLx in module
+  uint32_t sampled_val[SAMPLE_SIZE]; // DQTRAINSTS register contents for each sample
+  uint32_t num_0s; // tracks the number of '0' samples
+  uint32_t num_1s; // tracks the number of '1' samples
+  uint32_t ret_val = 0x00; // assume all '0' samples
+  uint32_t address = get_addr(mrc_params, channel, rank);
+
+  // initialise "msk[]"
+  msk[0] = (rcvn) ? (BIT1) : (BIT9); // BL0
+  msk[1] = (rcvn) ? (BIT0) : (BIT8); // BL1
+
+
+  // cycle through each byte lane group
+  for (bl_grp = 0; bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2; bl_grp++)
+  {
+    // take SAMPLE_SIZE samples
+    for (j = 0; j < SAMPLE_SIZE; j++)
+    {
+      HteMemOp(address, first_run, rcvn?0:1);
+      first_run = 0;
+
+      // record the contents of the proper DQTRAINSTS register
+      sampled_val[j] = isbR32m(DDRPHY, (DQTRAINSTS + (bl_grp * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)));
+    }
+    // look for a majority value ( (SAMPLE_SIZE/2)+1 ) on the byte lane
+    // and set that value in the corresponding "ret_val" bit
+    for (bl_i = 0; bl_i < 2; bl_i++)
+    {
+      num_0s = 0x00; // reset '0' tracker for byte lane
+      num_1s = 0x00; // reset '1' tracker for byte lane
+      for (j = 0; j < SAMPLE_SIZE; j++)
+      {
+        if (sampled_val[j] & msk[bl_i])
+        {
+          num_1s++;
+        }
+        else
+        {
+          num_0s++;
+        }
+      }
+      if (num_1s > num_0s)
+      {
+        ret_val |= (1 << (bl_i + (bl_grp * 2)));
+      }
+    }
+  }
+
+  // "ret_val.0" contains the status of BL0
+  // "ret_val.1" contains the status of BL1
+  // "ret_val.2" contains the status of BL2
+  // etc.
+  return ret_val;
+}
+
+// get_addr:
+//
+// This function will return a 32 bit address in the desired channel and rank.
+uint32_t get_addr(
+    MRCParams_t *mrc_params,
+    uint8_t channel,
+    uint8_t rank)
+{
+  uint32_t offset = 0x02000000; // 32MB
+
+  // Begin product specific code
+  if (channel > 0)
+  {
+    DPF(D_ERROR, "ILLEGAL CHANNEL\n");
+    DEAD_LOOP();
+  }
+
+  if (rank > 1)
+  {
+    DPF(D_ERROR, "ILLEGAL RANK\n");
+    DEAD_LOOP();
+  }
+
+  // use 256MB lowest density as per DRP == 0x0003
+  offset += rank * (256 * 1024 * 1024);
+
+  return offset;
+}
+
+// byte_lane_mask:
+//
+// This function will return a 32 bit mask that will be used to check for byte lane failures.
+uint32_t byte_lane_mask(
+    MRCParams_t *mrc_params)
+{
+  uint32_t j;
+  uint32_t ret_val = 0x00;
+
+  // set "ret_val" based on NUM_BYTE_LANES such that you will check only BL0 in "result"
+  // (each bit in "result" represents a byte lane)
+  for (j = 0; j < MAX_BYTE_LANES; j += NUM_BYTE_LANES)
+  {
+    ret_val |= (1 << ((j / NUM_BYTE_LANES) * NUM_BYTE_LANES));
+  }
+
+  // HSD#235037
+  // need to adjust the mask for 16-bit mode
+  if (mrc_params->channel_width == x16)
+  {
+    ret_val |= (ret_val << 2);
+  }
+
+  return ret_val;
+}
+
+
+// read_tsc:
+//
+// This function will do some assembly to return TSC register contents as a uint64_t.
+uint64_t read_tsc(
+    void)
+{
+  volatile uint64_t tsc;  // EDX:EAX
+
+#if defined (SIM) || defined (GCC)
+  volatile uint32_t tscH; // EDX
+  volatile uint32_t tscL;// EAX
+
+  asm("rdtsc":"=a"(tscL),"=d"(tscH));
+  tsc = tscH;
+  tsc = (tsc<<32)|tscL;
+#else
+  tsc = __rdtsc();
+#endif
+
+  return tsc;
+}
+
+// get_tsc_freq:
+//
+// This function returns the TSC frequency in MHz
+uint32_t get_tsc_freq(
+    void)
+{
+  static uint32_t freq[] =
+  { 533, 400, 200, 100 };
+  uint32_t fuse;
+#if 0
+  fuse = (isbR32m(FUSE, 0) >> 12) & (BIT1|BIT0);
+#else
+  // todo!!! Fixed 533MHz for emulation or debugging
+  fuse = 0;
+#endif
+  return freq[fuse];
+}
+
+#ifndef SIM
+// delay_n:
+//
+// This is a simple delay function.
+// It takes "nanoseconds" as a parameter.
+void delay_n(
+    uint32_t nanoseconds)
+{
+  // 1000 MHz clock has 1ns period --> no conversion required
+  uint64_t final_tsc = read_tsc();
+  final_tsc += ((get_tsc_freq() * (nanoseconds)) / 1000);
+
+  while (read_tsc() < final_tsc)
+    ;
+  return;
+}
+#endif
+
+// delay_u:
+//
+// This is a simple delay function.
+// It takes "microseconds as a parameter.
+void delay_u(
+    uint32_t microseconds)
+{
+  // 64 bit math is not an option, just use loops
+  while (microseconds--)
+  {
+    delay_n(1000);
+  }
+  return;
+}
+
+// delay_m:
+//
+// This is a simple delay function.
+// It takes "milliseconds" as a parameter.
+void delay_m(
+    uint32_t milliseconds)
+{
+  // 64 bit math is not an option, just use loops
+  while (milliseconds--)
+  {
+    delay_u(1000);
+  }
+  return;
+}
+
+// delay_s:
+//
+// This is a simple delay function.
+// It takes "seconds" as a parameter.
+void delay_s(
+    uint32_t seconds)
+{
+  // 64 bit math is not an option, just use loops
+  while (seconds--)
+  {
+    delay_m(1000);
+  }
+  return;
+}
+
+// post_code:
+//
+// This function will output the POST CODE to the four 7-Segment LED displays.
+void post_code(
+    uint8_t major,
+    uint8_t minor)
+{
+#ifdef EMU
+  // Update global variable for execution tracking in debug env
+  PostCode = ((major << 8) | minor);
+#endif
+
+  // send message to UART
+  DPF(D_INFO, "POST: 0x%01X%02X\n", major, minor);
+
+  // error check:
+  if (major == 0xEE)
+  {
+    // todo!!! Consider updating error status and exit MRC
+#ifdef SIM
+    // enable Ctrl-C handling
+    for(;;) delay_n(100);
+#else
+    DEAD_LOOP();
+#endif
+  }
+}
+
+void training_message(
+    uint8_t channel,
+    uint8_t rank,
+    uint8_t byte_lane)
+{
+  // send message to UART
+  DPF(D_INFO, "CH%01X RK%01X BL%01X\n", channel, rank, byte_lane);
+  return;
+}
+
+void print_timings(
+    MRCParams_t *mrc_params)
+{
+  uint8_t algo_i;
+  uint8_t channel_i;
+  uint8_t rank_i;
+  uint8_t bl_i;
+  uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1;
+
+  DPF(D_INFO, "\n---------------------------");
+  DPF(D_INFO, "\nALGO[CH:RK] BL0 BL1 BL2 BL3");
+  DPF(D_INFO, "\n===========================");
+  for (algo_i = 0; algo_i < eMAX_ALGOS; algo_i++)
+  {
+    for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+    {
+      if (mrc_params->channel_enables & (1 << channel_i))
+      {
+        for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+        {
+          if (mrc_params->rank_enables & (1 << rank_i))
+          {
+            switch (algo_i)
+            {
+            case eRCVN:
+              DPF(D_INFO, "\nRCVN[%02d:%02d]", channel_i, rank_i);
+              break;
+            case eWDQS:
+              DPF(D_INFO, "\nWDQS[%02d:%02d]", channel_i, rank_i);
+              break;
+            case eWDQx:
+              DPF(D_INFO, "\nWDQx[%02d:%02d]", channel_i, rank_i);
+              break;
+            case eRDQS:
+              DPF(D_INFO, "\nRDQS[%02d:%02d]", channel_i, rank_i);
+              break;
+            case eVREF:
+              DPF(D_INFO, "\nVREF[%02d:%02d]", channel_i, rank_i);
+              break;
+            case eWCMD:
+              DPF(D_INFO, "\nWCMD[%02d:%02d]", channel_i, rank_i);
+              break;
+            case eWCTL:
+              DPF(D_INFO, "\nWCTL[%02d:%02d]", channel_i, rank_i);
+              break;
+            case eWCLK:
+              DPF(D_INFO, "\nWCLK[%02d:%02d]", channel_i, rank_i);
+              break;
+            default:
+              break;
+            } // algo_i switch
+            for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+            {
+              switch (algo_i)
+              {
+              case eRCVN:
+                DPF(D_INFO, " %03d", get_rcvn(channel_i, rank_i, bl_i));
+                break;
+              case eWDQS:
+                DPF(D_INFO, " %03d", get_wdqs(channel_i, rank_i, bl_i));
+                break;
+              case eWDQx:
+                DPF(D_INFO, " %03d", get_wdq(channel_i, rank_i, bl_i));
+                break;
+              case eRDQS:
+                DPF(D_INFO, " %03d", get_rdqs(channel_i, rank_i, bl_i));
+                break;
+              case eVREF:
+                DPF(D_INFO, " %03d", get_vref(channel_i, bl_i));
+                break;
+              case eWCMD:
+                DPF(D_INFO, " %03d", get_wcmd(channel_i));
+                break;
+              case eWCTL:
+                DPF(D_INFO, " %03d", get_wctl(channel_i, rank_i));
+                break;
+              case eWCLK:
+                DPF(D_INFO, " %03d", get_wclk(channel_i, rank_i));
+                break;
+              default:
+                break;
+              } // algo_i switch
+            } // bl_i loop
+          } // if rank_i enabled
+        } // rank_i loop
+      } // if channel_i enabled
+    } // channel_i loop
+  } // algo_i loop
+  DPF(D_INFO, "\n---------------------------");
+  DPF(D_INFO, "\n");
+  return;
+}
+
+// 32 bit LFSR with characteristic polynomial:  X^32 + X^22 +X^2 + X^1
+// The function takes pointer to previous 32 bit value and modifies it to next value.
+void lfsr32(
+    uint32_t *lfsr_ptr)
+{
+  uint32_t bit;
+  uint32_t lfsr;
+  uint32_t i;
+
+  lfsr = *lfsr_ptr;
+
+  for (i = 0; i < 32; i++)
+  {
+    bit = 1 ^ (lfsr & BIT0);
+    bit = bit ^ ((lfsr & BIT1) >> 1);
+    bit = bit ^ ((lfsr & BIT2) >> 2);
+    bit = bit ^ ((lfsr & BIT22) >> 22);
+
+    lfsr = ((lfsr >> 1) | (bit << 31));
+  }
+
+  *lfsr_ptr = lfsr;
+  return;
+}
+
+// The purpose of this function is to ensure the SEC comes out of reset
+// and IA initiates the SEC enabling Memory Scrambling.
+void enable_scrambling(
+    MRCParams_t *mrc_params)
+{
+  uint32_t lfsr = 0;
+  uint8_t i;
+
+  if (mrc_params->scrambling_enables == 0)
+    return;
+
+  ENTERFN();
+
+  // 32 bit seed is always stored in BIOS NVM.
+  lfsr = mrc_params->timings.scrambler_seed;
+
+  if (mrc_params->boot_mode == bmCold)
+  {
+    // factory value is 0 and in first boot, a clock based seed is loaded.
+    if (lfsr == 0)
+    {
+      lfsr = read_tsc() & 0x0FFFFFFF; // get seed from system clock and make sure it is not all 1's
+    }
+    // need to replace scrambler
+    // get next 32bit LFSR 16 times which is the last part of the previous scrambler vector.
+    else
+    {
+      for (i = 0; i < 16; i++)
+      {
+        lfsr32(&lfsr);
+      }
+    }
+    mrc_params->timings.scrambler_seed = lfsr;  // save new seed.
+  } // if (cold_boot)
+
+  // In warm boot or S3 exit, we have the previous seed.
+  // In cold boot, we have the last 32bit LFSR which is the new seed.
+  lfsr32(&lfsr); // shift to next value
+  isbW32m(MCU, SCRMSEED, (lfsr & 0x0003FFFF));
+  for (i = 0; i < 2; i++)
+  {
+    isbW32m(MCU, SCRMLO + i, (lfsr & 0xAAAAAAAA));
+  }
+
+  LEAVEFN();
+  return;
+}
+
+// This function will store relevant timing data
+// This data will be used on subsequent boots to speed up boot times
+// and is required for Suspend To RAM capabilities.
+void store_timings(
+    MRCParams_t *mrc_params)
+{
+  uint8_t ch, rk, bl;
+  MrcTimings_t *mt = &mrc_params->timings;
+
+  for (ch = 0; ch < NUM_CHANNELS; ch++)
+  {
+    for (rk = 0; rk < NUM_RANKS; rk++)
+    {
+      for (bl = 0; bl < NUM_BYTE_LANES; bl++)
+      {
+        mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl); // RCVN
+        mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl); // RDQS
+        mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl); // WDQS
+        mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl);  // WDQ
+        if (rk == 0)
+        {
+          mt->vref[ch][bl] = get_vref(ch, bl);  // VREF (RANK0 only)
+        }
+      }
+      mt->wctl[ch][rk] = get_wctl(ch, rk); // WCTL
+    }
+    mt->wcmd[ch] = get_wcmd(ch); // WCMD
+  }
+
+  // need to save for a case of changing frequency after warm reset
+  mt->ddr_speed = mrc_params->ddr_speed;
+
+  return;
+}
+
+// This function will retrieve relevant timing data
+// This data will be used on subsequent boots to speed up boot times
+// and is required for Suspend To RAM capabilities.
+void restore_timings(
+    MRCParams_t *mrc_params)
+{
+  uint8_t ch, rk, bl;
+  const MrcTimings_t *mt = &mrc_params->timings;
+
+  for (ch = 0; ch < NUM_CHANNELS; ch++)
+  {
+    for (rk = 0; rk < NUM_RANKS; rk++)
+    {
+      for (bl = 0; bl < NUM_BYTE_LANES; bl++)
+      {
+        set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]); // RCVN
+        set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]); // RDQS
+        set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]); // WDQS
+        set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]);  // WDQ
+        if (rk == 0)
+        {
+          set_vref(ch, bl, mt->vref[ch][bl]); // VREF (RANK0 only)
+        }
+      }
+      set_wctl(ch, rk, mt->wctl[ch][rk]); // WCTL
+    }
+    set_wcmd(ch, mt->wcmd[ch]); // WCMD
+  }
+
+  return;
+}
+
+// Configure default settings normally set as part of read training
+// Some defaults have to be set earlier as they may affect earlier
+// training steps.
+void default_timings(
+    MRCParams_t *mrc_params)
+{
+  uint8_t ch, rk, bl;
+
+  for (ch = 0; ch < NUM_CHANNELS; ch++)
+  {
+    for (rk = 0; rk < NUM_RANKS; rk++)
+    {
+      for (bl = 0; bl < NUM_BYTE_LANES; bl++)
+      {
+        set_rdqs(ch, rk, bl, 24); // RDQS
+        if (rk == 0)
+        {
+          set_vref(ch, bl, 32); // VREF (RANK0 only)
+        }
+      }
+    }
+  }
+
+  return;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h
new file mode 100644
index 0000000000..af7b8c8951
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h
@@ -0,0 +1,95 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2017 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ ***************************************************************************/
+#ifndef _MEMINIT_UTILS_H_
+#define _MEMINIT_UTILS_H_
+
+// General Definitions:
+#ifdef QUICKSIM
+#define SAMPLE_SIZE     4   // reduce number of training samples in simulation env
+#else
+#define SAMPLE_SIZE     6   // must be odd number
+#endif
+
+#define EARLY_DB    (0x12)  // must be less than this number to enable early deadband
+#define LATE_DB     (0x34)  // must be greater than this number to enable late deadband
+#define CHX_REGS    (11*4)
+#define FULL_CLK      128
+#define HALF_CLK       64
+#define QRTR_CLK       32
+
+
+
+#define MCEIL(num,den) ((uint8_t)((num+den-1)/den))
+#define MMAX(a,b)      ((((int32_t)(a))>((int32_t)(b)))?(a):(b))
+#define MCOUNT(a)      (sizeof(a)/sizeof(*a))
+
+typedef enum ALGOS_enum {
+  eRCVN = 0,
+  eWDQS,
+  eWDQx,
+  eRDQS,
+  eVREF,
+  eWCMD,
+  eWCTL,
+  eWCLK,
+  eMAX_ALGOS,
+} ALGOs_t;
+
+
+// Prototypes:
+void set_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
+void set_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
+void set_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
+void set_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
+void set_wcmd(uint8_t channel, uint32_t pi_count);
+void set_wclk(uint8_t channel, uint8_t grp, uint32_t pi_count);
+void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count);
+void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting);
+uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+uint32_t get_wcmd(uint8_t channel);
+uint32_t get_wclk(uint8_t channel, uint8_t group);
+uint32_t get_wctl(uint8_t channel, uint8_t rank);
+uint32_t get_vref(uint8_t channel, uint8_t byte_lane);
+
+void clear_pointers(void);
+void enable_cache(void);
+void disable_cache(void);
+void find_rising_edge(MRCParams_t *mrc_params, uint32_t delay[], uint8_t channel, uint8_t rank, bool rcvn);
+uint32_t sample_dqs(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank, bool rcvn);
+uint32_t get_addr(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank);
+uint32_t byte_lane_mask(MRCParams_t *mrc_params);
+
+uint64_t read_tsc(void);
+uint32_t get_tsc_freq(void);
+void delay_n(uint32_t nanoseconds);
+void delay_u(uint32_t microseconds);
+void delay_m(uint32_t milliseconds);
+void delay_s(uint32_t seconds);
+
+void post_code(uint8_t major, uint8_t minor);
+void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+void print_timings(MRCParams_t *mrc_params);
+
+void enable_scrambling(MRCParams_t *mrc_params);
+void store_timings(MRCParams_t *mrc_params);
+void restore_timings(MRCParams_t *mrc_params);
+void default_timings(MRCParams_t *mrc_params);
+
+#ifndef SIM
+//
+// Map memset() and memcpy() to BaseMemoryLib functions
+//
+#include <Library/BaseMemoryLib.h>
+#define memset(d,c,n) ((c) == 0) ? ZeroMem ((d), (n)) : SetMem ((d), (n), (c))
+#define memcpy(d,s,n) CopyMem ((d), (s), (n))
+#endif
+
+#endif // _MEMINIT_UTILS_H_
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h
new file mode 100644
index 0000000000..b96d06908e
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h
@@ -0,0 +1,77 @@
+/** @file
+Common definitions and compilation switches for MRC
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __MEMORY_OPTIONS_H
+#define __MEMORY_OPTIONS_H
+
+#include "core_types.h"
+
+// MRC COMPILE TIME SWITCHES:
+// ==========================
+
+
+
+//#define MRC_SV              // enable some validation opitons
+
+#if defined (SIM) || defined(EMU)
+#define QUICKSIM              // reduce execution time using shorter rd/wr sequences
+#endif
+
+#define CLT                   // required for Quark project
+
+
+
+//#define BACKUP_RCVN           // enable STATIC timing settings for RCVN (BACKUP_MODE)
+//#define BACKUP_WDQS           // enable STATIC timing settings for WDQS (BACKUP_MODE)
+//#define BACKUP_RDQS           // enable STATIC timing settings for RDQS (BACKUP_MODE)
+//#define BACKUP_WDQ            // enable STATIC timing settings for WDQ (BACKUP_MODE)
+
+
+
+//#define BACKUP_COMPS          // enable *COMP overrides (BACKUP_MODE)
+//#define RX_EYE_CHECK          // enable the RD_TRAIN eye check
+#define HMC_TEST              // enable Host to Memory Clock Alignment
+#define R2R_SHARING           // enable multi-rank support via rank2rank sharing
+
+#define FORCE_16BIT_DDRIO     // disable signals not used in 16bit mode of DDRIO
+
+
+
+//
+// Debug support
+//
+
+#ifdef NDEBUG
+#define DPF        if(0) dpf
+#else
+#define DPF        dpf
+#endif
+
+void dpf( uint32_t mask, char_t *bla, ...);
+
+
+uint8_t mgetc(void);
+uint8_t mgetch(void);
+
+
+// Debug print type
+#define D_ERROR      0x0001
+#define D_INFO       0x0002
+#define D_REGRD      0x0004
+#define D_REGWR      0x0008
+#define D_FCALL      0x0010
+#define D_TRN        0x0020
+#define D_TIME       0x0040
+
+#define ENTERFN()     DPF(D_FCALL, "<%s>\n", __FUNCTION__)
+#define LEAVEFN()     DPF(D_FCALL, "</%s>\n", __FUNCTION__)
+#define REPORTFN()    DPF(D_FCALL, "<%s/>\n", __FUNCTION__)
+
+extern uint32_t DpfPrintMask;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c
new file mode 100644
index 0000000000..f9b0e7050d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c
@@ -0,0 +1,40 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ ************************************************************************/
+#include "mrc.h"
+#include "memory_options.h"
+
+#include "meminit.h"
+#include "meminit_utils.h"
+#include "prememinit.h"
+#include "io.h"
+
+// Base address for UART registers
+extern uint32_t UartMmioBase;
+
+//
+// Memory Reference Code entry point when executing from BIOS
+//
+void Mrc( MRCParams_t *mrc_params)
+{
+  // configure uart base address assuming code relocated to eSRAM
+  UartMmioBase = mrc_params->uart_mmio_base;
+
+  ENTERFN();
+
+  DPF(D_INFO, "MRC Version %04X %s %s\n", MRC_VERSION, __DATE__, __TIME__);
+
+  // this will set up the data structures used by MemInit()
+  PreMemInit(mrc_params);
+
+  // this will initialize system memory
+  MemInit(mrc_params);
+
+  LEAVEFN();
+  return;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h
new file mode 100644
index 0000000000..dfcfe58a9d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h
@@ -0,0 +1,160 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ ************************************************************************/
+#ifndef _MRC_H_
+#define _MRC_H_
+
+#include "core_types.h"
+
+// define the MRC Version
+#define MRC_VERSION 0x0112
+
+
+// architectural definitions
+#define NUM_CHANNELS   1 // number of channels
+#define NUM_RANKS      2 // number of ranks per channel
+#define NUM_BYTE_LANES 4 // number of byte lanes per channel
+
+// software limitations
+#define MAX_CHANNELS   1
+#define MAX_RANKS      2
+#define MAX_BYTE_LANES 4
+
+// only to mock MrcWrapper
+#define MAX_SOCKETS    1
+#define MAX_SIDES      1
+#define MAX_ROWS       (MAX_SIDES * MAX_SOCKETS)
+// end
+
+
+// Specify DRAM of nenory channel width
+enum {
+  x8,   // DRAM width
+  x16,  // DRAM width & Channel Width
+  x32   // Channel Width
+};
+
+// Specify DRAM speed
+enum {
+  DDRFREQ_800,
+  DDRFREQ_1066
+};
+
+// Specify DRAM type
+enum {
+  DDR3,
+  DDR3L
+};
+
+// Delay configuration for individual signals
+// Vref setting
+// Scrambler seed
+typedef struct MrcTimings_s
+{
+  uint32_t rcvn[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
+  uint32_t rdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
+  uint32_t wdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
+  uint32_t wdq [NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
+  uint32_t vref[NUM_CHANNELS][NUM_BYTE_LANES];
+  uint32_t wctl[NUM_CHANNELS][NUM_RANKS];
+  uint32_t wcmd[NUM_CHANNELS];
+
+  uint32_t scrambler_seed;
+  uint8_t  ddr_speed;            // need to save for the case of frequency change
+} MrcTimings_t;
+
+
+// DENSITY: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
+// tCL is DRAM CAS Latency in clocks.
+// All other timings are in picoseconds.
+// Refer to JEDEC spec (or DRAM datasheet) when changing these values.
+typedef struct DRAMParams_s {
+  uint8_t  DENSITY;
+  uint8_t  tCL;   // CAS latency in clocks
+  uint32_t tRAS;  // ACT to PRE command period
+  uint32_t tWTR;  // Delay from start of internal write transaction to internal read command
+  uint32_t tRRD;  // ACT to ACT command period (JESD79 specific to page size 1K/2K)
+  uint32_t tFAW;  // Four activate window (JESD79 specific to page size 1K/2K)
+} DRAMParams_t;
+
+
+// Boot mode defined as bit mask (1<<n)
+#define bmCold     1    // full training
+#define bmFast     2    // restore timing parameters
+#define bmS3       4    // resume from S3
+#define bmWarm     8
+#define bmUnknown  0
+
+
+// MRC execution status
+#define MRC_SUCCESS     0      // initialization ok
+#define MRC_E_MEMTEST   1      // memtest failed
+
+
+//
+// Input/output/context parameters for Memory Reference Code
+//
+typedef struct MRCParams_s
+{
+  //
+  // Global settings
+  //
+
+  uint32_t boot_mode;           // bmCold, bmFast, bmWarm, bmS3
+  uint32_t uart_mmio_base;      // pcie serial port base address (force 0 to disable debug)
+
+  uint8_t  dram_width;          // x8, x16
+  uint8_t  ddr_speed;           // DDRFREQ_800, DDRFREQ_1066
+  uint8_t  ddr_type;            // DDR3, DDR3L
+  uint8_t  ecc_enables;         // 0, 1 (memory size reduced to 7/8)
+  uint8_t  scrambling_enables;  // 0, 1
+  uint32_t rank_enables;        // 1, 3 (1'st rank has to be populated if 2'nd rank present)
+  uint32_t channel_enables;     // 1 only
+  uint32_t channel_width;       // x16 only
+  uint32_t address_mode;        // 0, 1, 2 (mode 2 forced if ecc enabled)
+
+  // memConfig_t begin
+  uint8_t refresh_rate;         // REFRESH_RATE       : 1=1.95us, 2=3.9us, 3=7.8us, others=RESERVED
+  uint8_t sr_temp_range;        // SR_TEMP_RANGE      : 0=normal, 1=extended, others=RESERVED
+  uint8_t ron_value;            // RON_VALUE          : 0=34ohm, 1=40ohm, others=RESERVED (select MRS1.DIC driver impedance control)
+  uint8_t rtt_nom_value;        // RTT_NOM_VALUE      : 0=40ohm, 1=60ohm, 2=120ohm, others=RESERVED
+  uint8_t rd_odt_value;         // RD_ODT_VALUE       : 0=off, 1=60ohm, 2=120ohm, 3=180ohm, others=RESERVED
+  // memConfig_t end
+
+  DRAMParams_t params;
+
+  //
+  // Internally used
+  //
+
+  uint32_t board_id;            // internally used for board layout (use x8 or x16 memory)
+  uint32_t hte_setup : 1;       // when set hte reconfiguration requested
+  uint32_t menu_after_mrc : 1;
+  uint32_t power_down_disable :1;
+  uint32_t tune_rcvn :1;
+
+  uint32_t channel_size[NUM_CHANNELS];
+  uint32_t column_bits[NUM_CHANNELS];
+  uint32_t row_bits[NUM_CHANNELS];
+
+  uint32_t mrs1;                // register content saved during training
+
+  //
+  // Output
+  //
+
+  uint32_t status;              // initialization result (non zero specifies error code)
+  uint32_t mem_size;            // total memory size in bytes (excludes ECC banks)
+
+  MrcTimings_t timings;         // training results (also used on input)
+
+} MRCParams_t;
+
+// Alternative type name for consistent naming convention
+#define MRC_PARAMS    MRCParams_t
+
+#endif // _MRC_H_
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c
new file mode 100644
index 0000000000..7d0c14119d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c
@@ -0,0 +1,186 @@
+/** @file
+The interface layer for memory controller access.
+It is supporting both real hardware platform and simulation environment.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "mrc.h"
+#include "memory_options.h"
+#include "meminit_utils.h"
+#include "io.h"
+
+#ifdef SIM
+
+void SimMmio32Write (
+    uint32_t be,
+    uint32_t address,
+    uint32_t data );
+
+void SimMmio32Read (
+    uint32_t be,
+    uint32_t address,
+    uint32_t *data );
+
+void SimDelayClk (
+    uint32_t x2clk );
+
+// This is a simple delay function.
+// It takes "nanoseconds" as a parameter.
+void delay_n(uint32_t nanoseconds)
+{
+  SimDelayClk( 800*nanoseconds/1000);
+}
+#endif
+
+/****
+ *
+ ***/
+uint32_t Rd32(
+    uint32_t unit,
+    uint32_t addr)
+{
+  uint32_t data;
+
+  switch (unit)
+  {
+  case MEM:
+    case MMIO:
+#ifdef SIM
+    SimMmio32Read( 1, addr, &data);
+#else
+    data = *PTR32(addr);
+#endif
+    break;
+
+  case MCU:
+    case HOST_BRIDGE:
+    case MEMORY_MANAGER:
+    case HTE:
+    // Handle case addr bigger than 8bit
+    pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
+    addr &= 0x00FF;
+
+    pciwrite32(0, 0, 0, SB_PACKET_REG,
+        SB_COMMAND(SB_REG_READ_OPCODE, unit, addr));
+    data = pciread32(0, 0, 0, SB_DATA_REG);
+    break;
+
+  case DDRPHY:
+    // Handle case addr bigger than 8bit
+    pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
+    addr &= 0x00FF;
+
+    pciwrite32(0, 0, 0, SB_PACKET_REG,
+        SB_COMMAND(SB_DDRIO_REG_READ_OPCODE, unit, addr));
+    data = pciread32(0, 0, 0, SB_DATA_REG);
+    break;
+
+  default:
+    DEAD_LOOP()
+    ;
+  }
+
+  if (unit < MEM)
+    DPF(D_REGRD, "RD32 %03X %08X %08X\n", unit, addr, data);
+
+  return data;
+}
+
+/****
+ *
+ ***/
+void Wr32(
+    uint32_t unit,
+    uint32_t addr,
+    uint32_t data)
+{
+  if (unit < MEM)
+    DPF(D_REGWR, "WR32 %03X %08X %08X\n", unit, addr, data);
+
+  switch (unit)
+  {
+  case MEM:
+    case MMIO:
+#ifdef SIM
+    SimMmio32Write( 1, addr, data);
+#else
+    *PTR32(addr) = data;
+#endif
+    break;
+
+  case MCU:
+    case HOST_BRIDGE:
+    case MEMORY_MANAGER:
+    case HTE:
+    // Handle case addr bigger than 8bit
+    pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
+    addr &= 0x00FF;
+
+    pciwrite32(0, 0, 0, SB_DATA_REG, data);
+    pciwrite32(0, 0, 0, SB_PACKET_REG,
+        SB_COMMAND(SB_REG_WRITE_OPCODE, unit, addr));
+    break;
+
+  case DDRPHY:
+    // Handle case addr bigger than 8bit
+    pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
+    addr &= 0x00FF;
+
+    pciwrite32(0, 0, 0, SB_DATA_REG, data);
+    pciwrite32(0, 0, 0, SB_PACKET_REG,
+        SB_COMMAND(SB_DDRIO_REG_WRITE_OPCODE, unit, addr));
+    break;
+
+  case DCMD:
+    pciwrite32(0, 0, 0, SB_HADR_REG, 0);
+    pciwrite32(0, 0, 0, SB_DATA_REG, data);
+    pciwrite32(0, 0, 0, SB_PACKET_REG,
+        SB_COMMAND(SB_DRAM_CMND_OPCODE, MCU, 0));
+    break;
+
+  default:
+    DEAD_LOOP()
+    ;
+  }
+}
+
+/****
+ *
+ ***/
+void WrMask32(
+    uint32_t unit,
+    uint32_t addr,
+    uint32_t data,
+    uint32_t mask)
+{
+  Wr32(unit, addr, ((Rd32(unit, addr) & ~mask) | (data & mask)));
+}
+
+/****
+ *
+ ***/
+void pciwrite32(
+    uint32_t bus,
+    uint32_t dev,
+    uint32_t fn,
+    uint32_t reg,
+    uint32_t data)
+{
+  Wr32(MMIO, PCIADDR(bus,dev,fn,reg), data);
+}
+
+/****
+ *
+ ***/
+uint32_t pciread32(
+    uint32_t bus,
+    uint32_t dev,
+    uint32_t fn,
+    uint32_t reg)
+{
+  return Rd32(MMIO, PCIADDR(bus,dev,fn,reg));
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c
new file mode 100644
index 0000000000..ebc03efa05
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c
@@ -0,0 +1,187 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ ************************************************************************/
+
+#include "mrc.h"
+#include "memory_options.h"
+
+#include "meminit_utils.h"
+#include "prememinit.h"
+#include "io.h"
+
+// Read character from serial console
+uint8_t mgetc(void);
+
+extern uint32_t DpfPrintMask;
+
+// Adjust configuration parameters before initialisation
+// sequence.
+void PreMemInit(
+    MRCParams_t *mrc_params)
+{
+  const DRAMParams_t *dram_params;
+
+  uint8_t dram_width;
+  uint32_t dram_cfg_index;
+  uint32_t channel_i;
+
+  ENTERFN();
+
+#ifdef MRC_SV
+  {
+    uint8_t ch;
+
+    myloop:
+
+    DPF(D_INFO, "- c - continue\n");
+    DPF(D_INFO, "- f - boot mode [%d]\n", mrc_params->boot_mode);
+    DPF(D_INFO, "- r - rank enable [%d]\n", mrc_params->rank_enables);
+    DPF(D_INFO, "- e - ecc switch [%d]\n", mrc_params->ecc_enables);
+    DPF(D_INFO, "- b - scrambling switch [%d]\n", mrc_params->scrambling_enables);
+    DPF(D_INFO, "- a - adr mode [%d]\n", mrc_params->address_mode);
+    DPF(D_INFO, "- m - menu after mrc [%d]\n", mrc_params->menu_after_mrc);
+    DPF(D_INFO, "- t - tune to rcvn [%d]\n", mrc_params->tune_rcvn);
+    DPF(D_INFO, "- o - odt switch [%d]\n", mrc_params->rd_odt_value);
+    DPF(D_INFO, "- d - dram density [%d]\n", mrc_params->params.DENSITY);
+    DPF(D_INFO, "- p - power down disable [%d]\n", mrc_params->power_down_disable);
+    DPF(D_INFO, "- l - log switch 0x%x\n", DpfPrintMask);
+    ch = mgetc();
+
+    switch (ch)
+    {
+    case 'f':
+      mrc_params->boot_mode >>= 1;
+      if(mrc_params->boot_mode == bmUnknown)
+      {
+         mrc_params->boot_mode = bmWarm;
+      }
+      DPF(D_INFO, "Boot mode %d\n", mrc_params->boot_mode);
+      break;
+
+    case 'p':
+      mrc_params->power_down_disable ^= 1;
+      DPF(D_INFO, "Power down disable %d\n", mrc_params->power_down_disable);
+      break;
+
+    case 'r':
+      mrc_params->rank_enables ^= 2;
+      DPF(D_INFO, "Rank enable %d\n", mrc_params->rank_enables);
+      break;
+
+    case 'e':
+      mrc_params->ecc_enables ^= 1;
+      DPF(D_INFO, "Ecc enable %d\n", mrc_params->ecc_enables);
+      break;
+
+    case 'b':
+      mrc_params->scrambling_enables ^= 1;
+      DPF(D_INFO, "Scrambler enable %d\n", mrc_params->scrambling_enables);
+      break;
+
+    case 'a':
+      mrc_params->address_mode = (mrc_params->address_mode + 1) % 3;
+      DPF(D_INFO, "Adr mode %d\n", mrc_params->address_mode);
+      break;
+
+    case 'm':
+       mrc_params->menu_after_mrc ^= 1;
+      DPF(D_INFO, "Menu after mrc %d\n", mrc_params->menu_after_mrc);
+      break;
+
+    case 't':
+      mrc_params->tune_rcvn ^= 1;
+      DPF(D_INFO, "Tune to rcvn %d\n", mrc_params->tune_rcvn);
+      break;
+
+    case 'o':
+      mrc_params->rd_odt_value = (mrc_params->rd_odt_value + 1) % 4;
+      DPF(D_INFO, "Rd_odt_value %d\n", mrc_params->rd_odt_value);
+      break;
+
+    case 'd':
+      mrc_params->params.DENSITY = (mrc_params->params.DENSITY + 1) % 4;
+      DPF(D_INFO, "Dram density %d\n", mrc_params->params.DENSITY);
+      break;
+
+    case 'l':
+      DpfPrintMask ^= 0x30;
+      DPF(D_INFO, "Log mask %x\n", DpfPrintMask);
+      break;
+
+    default:
+      break;
+    }
+
+    if (ch != 'c')
+      goto myloop;
+
+  }
+#endif
+
+  // initially expect success
+  mrc_params->status = MRC_SUCCESS;
+
+  // todo!!! Setup board layout (must be reviewed as is selecting static timings)
+  // 0 == R0 (DDR3 x16), 1 == R1 (DDR3 x16), 2 == DV (DDR3 x8), 3 == SV (DDR3 x8)
+  if (mrc_params->dram_width == x8)
+  {
+    mrc_params->board_id = 2;  // select x8 layout
+  }
+  else
+  {
+    mrc_params->board_id = 0;  // select x16 layout
+  }
+
+  // initially no memory
+  mrc_params->mem_size = 0;
+  channel_i = 0;
+
+  // begin of channel settings
+  dram_width = mrc_params->dram_width;
+  dram_params = &mrc_params->params;
+  dram_cfg_index = 0;
+
+  // Determine Column & Row Bits:
+  // Column:
+  // 11 for 8Gbx8, else 10
+  mrc_params->column_bits[channel_i] = ((dram_params[dram_cfg_index].DENSITY == 4) && (dram_width == x8)) ? (11) : (10);
+
+  // Row:
+  // 512Mbx16=12 512Mbx8=13
+  //   1Gbx16=13   1Gbx8=14
+  //   2Gbx16=14   2Gbx8=15
+  //   4Gbx16=15   4Gbx8=16
+  //   8Gbx16=16   8Gbx8=16
+  mrc_params->row_bits[channel_i] = 12 + (dram_params[dram_cfg_index].DENSITY)
+      + (((dram_params[dram_cfg_index].DENSITY < 4) && (dram_width == x8)) ? (1) : (0));
+
+  // Determine Per Channel Memory Size:
+  // (For 2 RANKs, multiply by 2)
+  // (For 16 bit data bus, divide by 2)
+  // DENSITY  WIDTH   MEM_AVAILABLE
+  // 512Mb    x16     0x008000000 ( 128MB)
+  // 512Mb    x8      0x010000000 ( 256MB)
+  // 1Gb      x16     0x010000000 ( 256MB)
+  // 1Gb      x8      0x020000000 ( 512MB)
+  // 2Gb      x16     0x020000000 ( 512MB)
+  // 2Gb      x8      0x040000000 (1024MB)
+  // 4Gb      x16     0x040000000 (1024MB)
+  // 4Gb      x8      0x080000000 (2048MB)
+  mrc_params->channel_size[channel_i] = (1 << dram_params[dram_cfg_index].DENSITY);
+  mrc_params->channel_size[channel_i] *= ((dram_width == x8) ? (2) : (1));
+  mrc_params->channel_size[channel_i] *= (mrc_params->rank_enables == 0x3) ? (2) : (1);
+  mrc_params->channel_size[channel_i] *= (mrc_params->channel_width == x16) ? (1) : (2);
+
+  // Determine memory size (convert number of 64MB/512Mb units)
+  mrc_params->mem_size += mrc_params->channel_size[channel_i] << 26;
+
+  // end of channel settings
+
+  LEAVEFN();
+  return;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h
new file mode 100644
index 0000000000..13853fdaa2
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h
@@ -0,0 +1,15 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ ************************************************************************/
+#ifndef __PREMEMINIT_H_
+#define __PREMEMINIT_H_
+
+// Function prototypes
+void PreMemInit(MRCParams_t *mrc_params);
+
+
+#endif // _PREMEMINIT_H_
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h
new file mode 100644
index 0000000000..20bea9277a
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h
@@ -0,0 +1,49 @@
+/** @file
+Common header file shared by all source files.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __COMMON_HEADER_H_
+#define __COMMON_HEADER_H_
+
+//
+// The package level header files this module uses
+//
+#include <PiDxe.h>
+#include <IntelQNCDxe.h>
+
+//
+// The protocols, PPI and GUID definitions for this module
+//
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/LegacyRegion2.h>
+#include <Protocol/SmbusHc.h>
+#include <Protocol/QncS3Support.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/IoLib.h>
+#include <Library/SmbusLib.h>
+#include <Library/S3IoLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/IntelQNCLib.h>
+#include <Library/QNCAccessLib.h>
+#include <AcpiCpuData.h>
+
+extern EFI_HANDLE gQNCInitImageHandle;
+extern QNC_DEVICE_ENABLES mQNCDeviceEnables;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c
new file mode 100644
index 0000000000..2731bfe136
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c
@@ -0,0 +1,612 @@
+/** @file
+Implementation for SMBus DXE driver entry point and SMBus Host
+Controller protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "CommonHeader.h"
+
+#include "DxeQNCSmbus.h"
+
+//
+// Interface defintion of SMBUS Host Controller Protocol.
+//
+EFI_SMBUS_HC_PROTOCOL mSmbusHc = {
+  SmbusExecute,
+  SmbusArpDevice,
+  SmbusGetArpMap,
+  SmbusNotify
+};
+
+//
+// Handle to install SMBus Host Controller protocol.
+//
+EFI_HANDLE                   mSmbusHcHandle = NULL;
+UINT8                        mDeviceMapEntries = 0;
+EFI_SMBUS_DEVICE_MAP         mDeviceMap[MAX_SMBUS_DEVICES];
+UINT8                        mPlatformNumRsvd = 0;
+UINT8                        *mPlatformAddrRsvd = NULL;
+
+//
+// These addresses are reserved by the SMBus 2.0 specification
+//
+UINT8    mReservedAddress[SMBUS_NUM_RESERVED] = {
+  0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x18, 0x50, 0x6E, 0xC2,
+  0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE
+};
+
+
+/**
+  Gets Io port base address of Smbus Host Controller.
+
+  This internal function depends on a feature flag named PcdIchSmbusFixedIoPortBaseAddress
+  to retrieve Smbus Io port base. If that feature flag is true, it will get Smbus Io port base
+  address from a preset Pcd entry named PcdIchSmbusIoPortBaseAddress; otherwise, it will always
+  read Pci configuration space to get that value in each Smbus bus transaction.
+
+  @return The Io port base address of Smbus host controller.
+
+**/
+UINTN
+GetSmbusIoPortBaseAddress (
+  VOID
+  )
+{
+  UINTN     IoPortBaseAddress;
+
+  if (FeaturePcdGet (PcdSmbaIoBaseAddressFixed)) {
+    IoPortBaseAddress = (UINTN) PcdGet16 (PcdSmbaIoBaseAddress);
+  } else {
+    IoPortBaseAddress = (UINTN) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) & B_QNC_LPC_SMBUS_BASE_MASK;
+  }
+
+  //
+  // Make sure that the IO port base address has been properly set.
+  //
+  ASSERT (IoPortBaseAddress != 0);
+
+  return IoPortBaseAddress;
+}
+
+
+VOID
+InitializeInternal (
+  )
+{
+  UINTN     IoPortBaseAddress;
+
+  IoPortBaseAddress = GetSmbusIoPortBaseAddress ();
+
+  //
+  // Step1: Enable QNC SMBUS I/O space.
+  //
+  LpcPciCfg32Or(R_QNC_LPC_SMBUS_BASE, B_QNC_LPC_SMBUS_BASE_EN);
+
+  //
+  // Step2: Clear Status Register before anyone uses the interfaces.
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);
+
+  //
+  // Step3: Program the correct smbus clock
+  //
+  IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCLK, V_QNC_SMBUS_HCLK_100KHZ);
+}
+
+
+
+
+BOOLEAN
+IsAddressAvailable (
+  IN      EFI_SMBUS_DEVICE_ADDRESS  SlaveAddress
+  )
+{
+  UINT8         Index;
+
+  //
+  // See if we have already assigned this address to a device
+  //
+  for (Index = 0; Index < mDeviceMapEntries; Index++) {
+    if (SlaveAddress.SmbusDeviceAddress ==
+         mDeviceMap[Index].SmbusDeviceAddress.SmbusDeviceAddress) {
+      return FALSE;
+    }
+  }
+
+  //
+  // See if this address is claimed by a platform non-ARP-capable device
+  //
+  for (Index = 0; Index < mPlatformNumRsvd; Index++) {
+    if ((SlaveAddress.SmbusDeviceAddress << 1) == mPlatformAddrRsvd[Index]) {
+      return FALSE;
+    }
+  }
+
+  //
+  // See if this is a reserved address
+  //
+  for (Index = 0; Index < SMBUS_NUM_RESERVED; Index++) {
+    if (SlaveAddress.SmbusDeviceAddress == (UINTN) mReservedAddress[Index]) {
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+
+EFI_STATUS
+GetNextAvailableAddress (
+  IN EFI_SMBUS_DEVICE_ADDRESS  *SlaveAddress
+  )
+{
+  for (SlaveAddress->SmbusDeviceAddress = 0x03;
+    SlaveAddress->SmbusDeviceAddress < 0x7F;
+    SlaveAddress->SmbusDeviceAddress++
+    ) {
+    if (IsAddressAvailable (*SlaveAddress)) {
+      return EFI_SUCCESS;
+    }
+  }
+
+  return EFI_OUT_OF_RESOURCES;
+}
+
+EFI_STATUS
+SmbusPrepareToArp (
+  )
+{
+  EFI_SMBUS_DEVICE_ADDRESS  SlaveAddress;
+  EFI_STATUS                Status;
+  UINTN                     Length;
+  UINT8                     Buffer;
+
+  SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;
+  Length = 1;
+  Buffer = SMBUS_DATA_PREPARE_TO_ARP;
+
+  Status = Execute (
+             SlaveAddress,
+             0,
+             EfiSmbusSendByte,
+             TRUE,
+             &Length,
+             &Buffer
+             );
+  return Status;
+}
+
+EFI_STATUS
+SmbusGetUdidGeneral (
+  IN OUT  EFI_SMBUS_DEVICE_MAP  *DeviceMap
+  )
+{
+  EFI_SMBUS_DEVICE_ADDRESS      SlaveAddress;
+  EFI_STATUS                    Status;
+  UINTN                         Length;
+  UINT8                         Buffer[SMBUS_GET_UDID_LENGTH];
+
+  SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;
+  Length = SMBUS_GET_UDID_LENGTH;
+
+  Status = Execute (
+             SlaveAddress,
+             SMBUS_DATA_GET_UDID_GENERAL,
+             EfiSmbusReadBlock,
+             TRUE,
+             &Length,
+             Buffer
+             );
+
+  if (!EFI_ERROR(Status)) {
+    if (Length == SMBUS_GET_UDID_LENGTH) {
+      DeviceMap->SmbusDeviceUdid.DeviceCapabilities = Buffer[0];
+      DeviceMap->SmbusDeviceUdid.VendorRevision = Buffer[1];
+      DeviceMap->SmbusDeviceUdid.VendorId = (UINT16)((Buffer[2] << 8) + Buffer[3]);
+      DeviceMap->SmbusDeviceUdid.DeviceId = (UINT16)((Buffer[4] << 8) + Buffer[5]);
+      DeviceMap->SmbusDeviceUdid.Interface = (UINT16)((Buffer[6] << 8) + Buffer[7]);
+      DeviceMap->SmbusDeviceUdid.SubsystemVendorId = (UINT16)((Buffer[8] << 8) + Buffer[9]);
+      DeviceMap->SmbusDeviceUdid.SubsystemDeviceId = (UINT16)((Buffer[10] << 8) + Buffer[11]);
+      DeviceMap->SmbusDeviceUdid.VendorSpecificId = (UINT32)((Buffer[12] << 24) + (Buffer[13] << 16) + (Buffer[14] << 8) + Buffer[15]);
+      DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress = (UINT8)(Buffer[16] >> 1);
+    } else {
+      Status = EFI_DEVICE_ERROR;
+    }
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+SmbusAssignAddress (
+  IN OUT  EFI_SMBUS_DEVICE_MAP  *DeviceMap
+  )
+{
+  EFI_SMBUS_DEVICE_ADDRESS      SlaveAddress;
+  EFI_STATUS                    Status;
+  UINTN                         Length;
+  UINT8                         Buffer[SMBUS_GET_UDID_LENGTH];
+
+  Buffer[0] = DeviceMap->SmbusDeviceUdid.DeviceCapabilities;
+  Buffer[1] = DeviceMap->SmbusDeviceUdid.VendorRevision;
+  Buffer[2] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorId >> 8);
+  Buffer[3] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorId);
+  Buffer[4] = (UINT8)(DeviceMap->SmbusDeviceUdid.DeviceId >> 8);
+  Buffer[5] = (UINT8)(DeviceMap->SmbusDeviceUdid.DeviceId);
+  Buffer[6] = (UINT8)(DeviceMap->SmbusDeviceUdid.Interface >> 8);
+  Buffer[7] = (UINT8)(DeviceMap->SmbusDeviceUdid.Interface);
+  Buffer[8] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemVendorId >> 8);
+  Buffer[9] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemVendorId);
+  Buffer[10] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemDeviceId >> 8);
+  Buffer[11] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemDeviceId);
+  Buffer[12] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 24);
+  Buffer[13] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 16);
+  Buffer[14] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 8);
+  Buffer[15] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId);
+  Buffer[16] = (UINT8)(DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress << 1);
+
+  SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;
+  Length = SMBUS_GET_UDID_LENGTH;
+
+  Status = Execute (
+             SlaveAddress,
+             SMBUS_DATA_ASSIGN_ADDRESS,
+             EfiSmbusWriteBlock,
+             TRUE,
+             &Length,
+             Buffer
+             );
+  return Status;
+}
+
+
+EFI_STATUS
+SmbusFullArp (
+  )
+{
+  EFI_STATUS              Status;
+  EFI_SMBUS_DEVICE_MAP    *CurrentDeviceMap;
+
+  Status = SmbusPrepareToArp ();
+  if (EFI_ERROR(Status)) {
+    if (Status == EFI_DEVICE_ERROR) {
+      //
+      //  ARP is complete
+      //
+      return EFI_SUCCESS;
+    } else {
+      return Status;
+    }
+  }
+
+  //
+  //  Main loop to ARP all ARP-capable devices
+  //
+  do {
+    CurrentDeviceMap = &mDeviceMap[mDeviceMapEntries];
+    Status = SmbusGetUdidGeneral (CurrentDeviceMap);
+    if (EFI_ERROR(Status)) {
+      break;
+    }
+
+    if (CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress == (0xFF >> 1)) {
+      //
+      // If address is unassigned, assign it
+      //
+      Status = GetNextAvailableAddress (
+                 &CurrentDeviceMap->SmbusDeviceAddress
+                 );
+      if (EFI_ERROR(Status)) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+    } else if (((CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities) & 0xC0) != 0) {
+      //
+      // if address is not fixed, check if the current address is available
+      //
+      if (!IsAddressAvailable (
+             CurrentDeviceMap->SmbusDeviceAddress
+             )) {
+        //
+        // if currently assigned address is already used, get a new one
+        //
+        Status = GetNextAvailableAddress (
+                   &CurrentDeviceMap->SmbusDeviceAddress
+                   );
+        if (EFI_ERROR(Status)) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+      }
+    }
+
+    Status = SmbusAssignAddress (CurrentDeviceMap);
+    if (EFI_ERROR(Status)) {
+      //
+      // If there was a device error, just continue on and try again.
+      // Other errors should be reported.
+      //
+      if (Status != EFI_DEVICE_ERROR) {
+        return Status;
+      }
+    } else {
+      //
+      // If there was no error, the address was assigned and we must update our
+      // records.
+      //
+      mDeviceMapEntries++;
+    }
+
+  } while (mDeviceMapEntries < MAX_SMBUS_DEVICES);
+
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+SmbusDirectedArp (
+  IN      EFI_SMBUS_UDID            *SmbusUdid,
+  IN OUT  EFI_SMBUS_DEVICE_ADDRESS  *SlaveAddress
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_SMBUS_DEVICE_MAP              *CurrentDeviceMap;
+
+  if (mDeviceMapEntries >= MAX_SMBUS_DEVICES) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  CurrentDeviceMap = &mDeviceMap[mDeviceMapEntries];
+
+  //
+  // Find an available address to assign
+  //
+  Status = GetNextAvailableAddress (
+             &CurrentDeviceMap->SmbusDeviceAddress
+             );
+  if (EFI_ERROR(Status)) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities  = SmbusUdid->DeviceCapabilities;
+  CurrentDeviceMap->SmbusDeviceUdid.DeviceId            = SmbusUdid->DeviceId;
+  CurrentDeviceMap->SmbusDeviceUdid.Interface           = SmbusUdid->Interface;
+  CurrentDeviceMap->SmbusDeviceUdid.SubsystemDeviceId   = SmbusUdid->SubsystemDeviceId;
+  CurrentDeviceMap->SmbusDeviceUdid.SubsystemVendorId   = SmbusUdid->SubsystemVendorId;
+  CurrentDeviceMap->SmbusDeviceUdid.VendorId            = SmbusUdid->VendorId;
+  CurrentDeviceMap->SmbusDeviceUdid.VendorRevision      = SmbusUdid->VendorRevision;
+  CurrentDeviceMap->SmbusDeviceUdid.VendorSpecificId    = SmbusUdid->VendorSpecificId;
+
+  Status = SmbusAssignAddress (CurrentDeviceMap);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  mDeviceMapEntries++;
+  SlaveAddress->SmbusDeviceAddress = CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress;
+
+  return EFI_SUCCESS;
+}
+
+
+
+/**
+  Executes an SMBus operation to an SMBus controller. Returns when either the command has been
+  executed or an error is encountered in doing the operation.
+
+  The Execute() function provides a standard way to execute an operation as defined in the System
+  Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus
+  slave devices accept this transaction or that this function returns with error.
+
+  @param  This                    A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
+  @param  SlaveAddress            The SMBus slave address of the device with which to communicate.
+  @param  Command                 This command is transmitted by the SMBus host controller to the
+                                  SMBus slave device and the interpretation is SMBus slave device
+                                  specific. It can mean the offset to a list of functions inside an
+                                  SMBus slave device. Not all operations or slave devices support
+                                  this command's registers.
+  @param  Operation               Signifies which particular SMBus hardware protocol instance that
+                                  it will use to execute the SMBus transactions. This SMBus
+                                  hardware protocol is defined by the SMBus Specification and is
+                                  not related to EFI.
+  @param  PecCheck                Defines if Packet Error Code (PEC) checking is required for this
+                                  operation.
+  @param  Length                  Signifies the number of bytes that this operation will do. The
+                                  maximum number of bytes can be revision specific and operation
+                                  specific. This field will contain the actual number of bytes that
+                                  are executed for this operation. Not all operations require this
+                                  argument.
+  @param  Buffer                  Contains the value of data to execute to the SMBus slave device.
+                                  Not all operations require this argument. The length of this
+                                  buffer is identified by Length.
+
+  @retval EFI_SUCCESS             The last data that was returned from the access matched the poll
+                                  exit criteria.
+  @retval EFI_CRC_ERROR           Checksum is not correct (PEC is incorrect).
+  @retval EFI_TIMEOUT             Timeout expired before the operation was completed. Timeout is
+                                  determined by the SMBus host controller device.
+  @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR        The request was not completed because a failure that was
+                                  reflected in the Host Status Register bit. Device errors are a
+                                  result of a transaction collision, illegal command field,
+                                  unclaimed cycle (host initiated), or bus errors (collisions).
+  @retval EFI_INVALID_PARAMETER   Operation is not defined in EFI_SMBUS_OPERATION.
+  @retval EFI_INVALID_PARAMETER   Length/Buffer is NULL for operations except for EfiSmbusQuickRead
+                                  and EfiSmbusQuickWrite. Length is outside the range of valid
+                                  values.
+  @retval EFI_UNSUPPORTED         The SMBus operation or PEC is not supported.
+  @retval EFI_BUFFER_TOO_SMALL    Buffer is not sufficient for this operation.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbusExecute (
+  IN CONST  EFI_SMBUS_HC_PROTOCOL     *This,
+  IN CONST  EFI_SMBUS_DEVICE_ADDRESS  SlaveAddress,
+  IN CONST  EFI_SMBUS_DEVICE_COMMAND  Command,
+  IN CONST  EFI_SMBUS_OPERATION       Operation,
+  IN CONST  BOOLEAN                   PecCheck,
+  IN OUT    UINTN                     *Length,
+  IN OUT    VOID                      *Buffer
+  )
+{
+  InitializeInternal ();
+  return Execute (
+           SlaveAddress,
+           Command,
+           Operation,
+           PecCheck,
+           Length,
+           Buffer
+           );
+}
+
+/**
+  Sets the SMBus slave device addresses for the device with a given unique ID or enumerates the
+  entire bus.
+
+  The ArpDevice() function provides a standard way for a device driver to enumerate the entire
+  SMBus or specific devices on the bus.
+
+  @param  This                    A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
+  @param  ArpAll                  A Boolean expression that indicates if the host drivers need to
+                                  enumerate all the devices or enumerate only the device that is
+                                  identified by SmbusUdid. If ArpAll is TRUE, SmbusUdid and
+                                  SlaveAddress are optional. If ArpAll is FALSE, ArpDevice will
+                                  enumerate SmbusUdid and the address will be at SlaveAddress.
+  @param  SmbusUdid               The Unique Device Identifier (UDID) that is associated with this
+                                  device.
+  @param  SlaveAddress            The SMBus slave address that is associated with an SMBus UDID.
+
+  @retval EFI_SUCCESS             The last data that was returned from the access matched the poll
+                                  exit criteria.
+  @retval EFI_CRC_ERROR           Checksum is not correct (PEC is incorrect).
+  @retval EFI_TIMEOUT             Timeout expired before the operation was completed. Timeout is
+                                  determined by the SMBus host controller device.
+  @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR        The request was not completed because a failure that was
+                                  reflected in the Host Status Register bit. Device errors are a
+                                  result of a transaction collision, illegal command field,
+                                  unclaimed cycle (host initiated), or bus errors (collisions).
+  @retval EFI_UNSUPPORTED         The corresponding SMBus operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbusArpDevice (
+  IN CONST  EFI_SMBUS_HC_PROTOCOL     *This,
+  IN        BOOLEAN                   ArpAll,
+  IN        EFI_SMBUS_UDID            *SmbusUdid,   OPTIONAL
+  IN OUT    EFI_SMBUS_DEVICE_ADDRESS  *SlaveAddress OPTIONAL
+  )
+{
+    InitializeInternal ();
+
+    if (ArpAll) {
+    return SmbusFullArp ();
+  } else {
+    if ((SmbusUdid == NULL) || (SlaveAddress == NULL)) {
+      return EFI_INVALID_PARAMETER;
+    }
+    return SmbusDirectedArp ((EFI_SMBUS_UDID *)SmbusUdid, SlaveAddress);
+  }
+}
+
+/**
+  Returns a pointer to the Address Resolution Protocol (ARP) map that contains the ID/address pair
+  of the slave devices that were enumerated by the SMBus host controller driver.
+
+  The GetArpMap() function returns the mapping of all the SMBus devices that were enumerated by the
+  SMBus host driver.
+
+  @param  This                    A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
+  @param  Length                  Size of the buffer that contains the SMBus device map.
+  @param  SmbusDeviceMap          The pointer to the device map as enumerated by the SMBus
+                                  controller driver.
+
+  @retval EFI_SUCCESS             The SMBus returned the current device map.
+  @retval EFI_UNSUPPORTED         The corresponding operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbusGetArpMap (
+  IN CONST  EFI_SMBUS_HC_PROTOCOL   *This,
+  IN OUT    UINTN                   *Length,
+  IN OUT    EFI_SMBUS_DEVICE_MAP    **SmbusDeviceMap
+  )
+{
+  *Length = mDeviceMapEntries;
+  *SmbusDeviceMap = mDeviceMap;
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Allows a device driver to register for a callback when the bus driver detects a state that it
+  needs to propagate to other drivers that are registered for a callback.
+
+  The Notify() function registers all the callback functions to allow the bus driver to call these
+  functions when the SlaveAddress/Data pair happens.
+  If NotifyFunction is NULL, then ASSERT ().
+
+  @param  This                    A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
+  @param  SlaveAddress            The SMBUS hardware address to which the SMBUS device is
+                                  preassigned or allocated.
+  @param  Data                    Data of the SMBus host notify command that the caller wants to be
+                                  called.
+  @param  NotifyFunction          The function to call when the bus driver detects the SlaveAddress
+                                  and Data pair.
+
+  @retval EFI_SUCCESS             NotifyFunction was registered.
+  @retval EFI_UNSUPPORTED         The corresponding operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbusNotify (
+  IN CONST  EFI_SMBUS_HC_PROTOCOL     *This,
+  IN CONST  EFI_SMBUS_DEVICE_ADDRESS  SlaveAddress,
+  IN CONST  UINTN                     Data,
+  IN CONST  EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Entry point to the DXE Driver that produces the SMBus Host Controller Protocol.
+
+  @param  ImageHandle      ImageHandle of the loaded driver.
+  @param  SystemTable      Pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS      The entry point of SMBus DXE driver is executed successfully.
+  @retval !EFI_SUCESS      Some error occurs in the entry point of SMBus DXE driver.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeQNCSmbus (
+  IN EFI_HANDLE            ImageHandle,
+  IN EFI_SYSTEM_TABLE      *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+
+  mPlatformNumRsvd = (UINT8)PcdGet32 (PcdPlatformSmbusAddrNum);
+  mPlatformAddrRsvd = (UINT8 *)(UINTN) PcdGet64 (PcdPlatformSmbusAddrTable);
+
+  //
+  // Install SMBus Host Controller protocol interface.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mSmbusHcHandle,
+                  &gEfiSmbusHcProtocolGuid,
+                  &mSmbusHc,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h
new file mode 100644
index 0000000000..6a302ce838
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h
@@ -0,0 +1,205 @@
+/** @file
+Header file for the defintions used in SMBus DXE driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _DXE_QNC_SMBUS_H_
+#define _DXE_QNC_SMBUS_H_
+#include "CommonHeader.h"
+
+#include "QNCSmbus.h"
+
+#define MAX_SMBUS_DEVICES   107     // Max number of SMBus devices (7 bit
+                                    //   address yields 128 combinations but 21
+                                    //   of those are reserved)
+
+#define MICROSECOND     10
+#define MILLISECOND     (1000 * MICROSECOND)
+#define ONESECOND       (1000 * MILLISECOND)
+
+#define STALL_TIME          1000000 // 1,000,000 microseconds = 1 second
+#define BUS_TRIES           3       // How many times to retry on Bus Errors
+#define SMBUS_NUM_RESERVED  21      // Number of device addresses that are
+                                    //   reserved by the SMBus spec.
+#define SMBUS_ADDRESS_ARP   0xC2 >> 1
+#define   SMBUS_DATA_PREPARE_TO_ARP   0x01
+#define   SMBUS_DATA_RESET_DEVICE     0x02
+#define   SMBUS_DATA_GET_UDID_GENERAL 0x03
+#define   SMBUS_DATA_ASSIGN_ADDRESS   0x04
+#define SMBUS_GET_UDID_LENGTH 17    // 16 byte UDID + 1 byte address
+
+/**
+  Executes an SMBus operation to an SMBus controller. Returns when either the command has been
+  executed or an error is encountered in doing the operation.
+
+  The Execute() function provides a standard way to execute an operation as defined in the System
+  Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus
+  slave devices accept this transaction or that this function returns with error.
+
+  @param  This                    A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
+  @param  SlaveAddress            The SMBus slave address of the device with which to communicate.
+  @param  Command                 This command is transmitted by the SMBus host controller to the
+                                  SMBus slave device and the interpretation is SMBus slave device
+                                  specific. It can mean the offset to a list of functions inside an
+                                  SMBus slave device. Not all operations or slave devices support
+                                  this command's registers.
+  @param  Operation               Signifies which particular SMBus hardware protocol instance that
+                                  it will use to execute the SMBus transactions. This SMBus
+                                  hardware protocol is defined by the SMBus Specification and is
+                                  not related to EFI.
+  @param  PecCheck                Defines if Packet Error Code (PEC) checking is required for this
+                                  operation.
+  @param  Length                  Signifies the number of bytes that this operation will do. The
+                                  maximum number of bytes can be revision specific and operation
+                                  specific. This field will contain the actual number of bytes that
+                                  are executed for this operation. Not all operations require this
+                                  argument.
+  @param  Buffer                  Contains the value of data to execute to the SMBus slave device.
+                                  Not all operations require this argument. The length of this
+                                  buffer is identified by Length.
+
+  @retval EFI_SUCCESS             The last data that was returned from the access matched the poll
+                                  exit criteria.
+  @retval EFI_CRC_ERROR           Checksum is not correct (PEC is incorrect).
+  @retval EFI_TIMEOUT             Timeout expired before the operation was completed. Timeout is
+                                  determined by the SMBus host controller device.
+  @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR        The request was not completed because a failure that was
+                                  reflected in the Host Status Register bit. Device errors are a
+                                  result of a transaction collision, illegal command field,
+                                  unclaimed cycle (host initiated), or bus errors (collisions).
+  @retval EFI_INVALID_PARAMETER   Operation is not defined in EFI_SMBUS_OPERATION.
+  @retval EFI_INVALID_PARAMETER   Length/Buffer is NULL for operations except for EfiSmbusQuickRead
+                                  and EfiSmbusQuickWrite. Length is outside the range of valid
+                                  values.
+  @retval EFI_UNSUPPORTED         The SMBus operation or PEC is not supported.
+  @retval EFI_BUFFER_TOO_SMALL    Buffer is not sufficient for this operation.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbusExecute (
+  IN CONST  EFI_SMBUS_HC_PROTOCOL     *This,
+  IN CONST  EFI_SMBUS_DEVICE_ADDRESS  SlaveAddress,
+  IN CONST  EFI_SMBUS_DEVICE_COMMAND  Command,
+  IN CONST  EFI_SMBUS_OPERATION       Operation,
+  IN CONST  BOOLEAN                   PecCheck,
+  IN OUT    UINTN                     *Length,
+  IN OUT    VOID                      *Buffer
+  );
+
+/**
+  Sets the SMBus slave device addresses for the device with a given unique ID or enumerates the
+  entire bus.
+
+  The ArpDevice() function provides a standard way for a device driver to enumerate the entire
+  SMBus or specific devices on the bus.
+
+  @param  This                    A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
+  @param  ArpAll                  A Boolean expression that indicates if the host drivers need to
+                                  enumerate all the devices or enumerate only the device that is
+                                  identified by SmbusUdid. If ArpAll is TRUE, SmbusUdid and
+                                  SlaveAddress are optional. If ArpAll is FALSE, ArpDevice will
+                                  enumerate SmbusUdid and the address will be at SlaveAddress.
+  @param  SmbusUdid               The Unique Device Identifier (UDID) that is associated with this
+                                  device.
+  @param  SlaveAddress            The SMBus slave address that is associated with an SMBus UDID.
+
+  @retval EFI_SUCCESS             The last data that was returned from the access matched the poll
+                                  exit criteria.
+  @retval EFI_CRC_ERROR           Checksum is not correct (PEC is incorrect).
+  @retval EFI_TIMEOUT             Timeout expired before the operation was completed. Timeout is
+                                  determined by the SMBus host controller device.
+  @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR        The request was not completed because a failure that was
+                                  reflected in the Host Status Register bit. Device errors are a
+                                  result of a transaction collision, illegal command field,
+                                  unclaimed cycle (host initiated), or bus errors (collisions).
+  @retval EFI_UNSUPPORTED         The corresponding operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbusArpDevice (
+  IN CONST  EFI_SMBUS_HC_PROTOCOL     *This,
+  IN        BOOLEAN                   ArpAll,
+  IN        EFI_SMBUS_UDID            *SmbusUdid,   OPTIONAL
+  IN OUT    EFI_SMBUS_DEVICE_ADDRESS  *SlaveAddress OPTIONAL
+  );
+
+/**
+  Returns a pointer to the Address Resolution Protocol (ARP) map that contains the ID/address pair
+  of the slave devices that were enumerated by the SMBus host controller driver.
+
+  The GetArpMap() function returns the mapping of all the SMBus devices that were enumerated by the
+  SMBus host driver.
+
+  @param  This                    A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
+  @param  Length                  Size of the buffer that contains the SMBus device map.
+  @param  SmbusDeviceMap          The pointer to the device map as enumerated by the SMBus
+                                  controller driver.
+
+  @retval EFI_SUCCESS             The SMBus returned the current device map.
+  @retval EFI_UNSUPPORTED         The corresponding operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbusGetArpMap (
+  IN CONST  EFI_SMBUS_HC_PROTOCOL   *This,
+  IN OUT    UINTN                   *Length,
+  IN OUT    EFI_SMBUS_DEVICE_MAP    **SmbusDeviceMap
+  );
+
+/**
+  Allows a device driver to register for a callback when the bus driver detects a state that it
+  needs to propagate to other drivers that are registered for a callback.
+
+  The Notify() function registers all the callback functions to allow the bus driver to call these
+  functions when the SlaveAddress/Data pair happens.
+  If NotifyFunction is NULL, then ASSERT ().
+
+  @param  This                    A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
+  @param  SlaveAddress            The SMBUS hardware address to which the SMBUS device is
+                                  preassigned or allocated.
+  @param  Data                    Data of the SMBus host notify command that the caller wants to be
+                                  called.
+  @param  NotifyFunction          The function to call when the bus driver detects the SlaveAddress
+                                  and Data pair.
+
+  @retval EFI_SUCCESS             NotifyFunction was registered.
+  @retval EFI_UNSUPPORTED         The corresponding operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmbusNotify (
+  IN CONST  EFI_SMBUS_HC_PROTOCOL     *This,
+  IN CONST  EFI_SMBUS_DEVICE_ADDRESS  SlaveAddress,
+  IN CONST  UINTN                     Data,
+  IN CONST  EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction
+  );
+
+/**
+  Entry point to the DXE Driver that produces the SMBus Host Controller Protocol.
+
+  @param  ImageHandle      ImageHandle of the loaded driver.
+  @param  SystemTable      Pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS      The entry point of SMBus DXE driver is executed successfully.
+  @retval !EFI_SUCESS      Some error occurs in the entry point of SMBus DXE driver.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeQNCSmbus (
+  IN EFI_HANDLE            ImageHandle,
+  IN EFI_SYSTEM_TABLE      *SystemTable
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c
new file mode 100644
index 0000000000..db9c6f29e5
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c
@@ -0,0 +1,237 @@
+/** @file
+QNC Legacy Region Driver
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CommonHeader.h"
+#include "LegacyRegion.h"
+
+//
+// Handle used to install the Legacy Region Protocol
+//
+EFI_HANDLE  mLegacyRegion2Handle = NULL;
+
+//
+// Instance of the Legacy Region Protocol to install into the handle database
+//
+EFI_LEGACY_REGION2_PROTOCOL  mLegacyRegion2 = {
+  LegacyRegion2Decode,
+  LegacyRegion2Lock,
+  LegacyRegion2BootLock,
+  LegacyRegion2Unlock,
+  LegacyRegionGetInfo
+};
+
+
+/**
+  Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
+
+  If the On parameter evaluates to TRUE, this function enables memory reads in the address range
+  Start to (Start + Length - 1).
+  If the On parameter evaluates to FALSE, this function disables memory reads in the address range
+  Start to (Start + Length - 1).
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  Start[in]             The beginning of the physical address of the region whose attributes
+                                should be modified.
+  @param  Length[in]            The number of bytes of memory whose attributes should be modified.
+                                The actual number of bytes modified may be greater than the number
+                                specified.
+  @param  Granularity[out]      The number of bytes in the last region affected. This may be less
+                                than the total number of bytes affected if the starting address
+                                was not aligned to a region's starting address or if the length
+                                was greater than the number of bytes in the first region.
+  @param  On[in]                Decode / Non-Decode flag.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Decode (
+  IN  EFI_LEGACY_REGION2_PROTOCOL  *This,
+  IN  UINT32                       Start,
+  IN  UINT32                       Length,
+  OUT UINT32                       *Granularity,
+  IN  BOOLEAN                      *On
+  )
+{
+  return QNCLegacyRegionManipulation (Start, Length, On, NULL, Granularity);
+}
+
+
+/**
+  Modify the hardware to disallow memory attribute changes in a region.
+
+  This function makes the attributes of a region read only. Once a region is boot-locked with this
+  function, the read and write attributes of that region cannot be changed until a power cycle has
+  reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  Start[in]             The beginning of the physical address of the region whose
+                                attributes should be modified.
+  @param  Length[in]            The number of bytes of memory whose attributes should be modified.
+                                The actual number of bytes modified may be greater than the number
+                                specified.
+  @param  Granularity[out]      The number of bytes in the last region affected. This may be less
+                                than the total number of bytes affected if the starting address was
+                                not aligned to a region's starting address or if the length was
+                                greater than the number of bytes in the first region.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+  @retval EFI_UNSUPPORTED       The chipset does not support locking the configuration registers in
+                                a way that will not affect memory regions outside the legacy memory
+                                region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2BootLock (
+  IN  EFI_LEGACY_REGION2_PROTOCOL         *This,
+  IN  UINT32                              Start,
+  IN  UINT32                              Length,
+  OUT UINT32                              *Granularity
+  )
+{
+  if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_UNSUPPORTED;
+}
+
+
+/**
+  Modify the hardware to disallow memory writes in a region.
+
+  This function changes the attributes of a memory range to not allow writes.
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  Start[in]             The beginning of the physical address of the region whose
+                                attributes should be modified.
+  @param  Length[in]            The number of bytes of memory whose attributes should be modified.
+                                The actual number of bytes modified may be greater than the number
+                                specified.
+  @param  Granularity[out]      The number of bytes in the last region affected. This may be less
+                                than the total number of bytes affected if the starting address was
+                                not aligned to a region's starting address or if the length was
+                                greater than the number of bytes in the first region.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Lock (
+  IN  EFI_LEGACY_REGION2_PROTOCOL *This,
+  IN  UINT32                      Start,
+  IN  UINT32                      Length,
+  OUT UINT32                      *Granularity
+  )
+{
+  BOOLEAN  WriteEnable;
+
+  WriteEnable = FALSE;
+  return QNCLegacyRegionManipulation (Start, Length, NULL, &WriteEnable, Granularity);
+}
+
+
+/**
+  Modify the hardware to allow memory writes in a region.
+
+  This function changes the attributes of a memory range to allow writes.
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  Start[in]             The beginning of the physical address of the region whose
+                                attributes should be modified.
+  @param  Length[in]            The number of bytes of memory whose attributes should be modified.
+                                The actual number of bytes modified may be greater than the number
+                                specified.
+  @param  Granularity[out]      The number of bytes in the last region affected. This may be less
+                                than the total number of bytes affected if the starting address was
+                                not aligned to a region's starting address or if the length was
+                                greater than the number of bytes in the first region.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Unlock (
+  IN  EFI_LEGACY_REGION2_PROTOCOL  *This,
+  IN  UINT32                       Start,
+  IN  UINT32                       Length,
+  OUT UINT32                       *Granularity
+  )
+{
+  BOOLEAN  WriteEnable;
+
+  WriteEnable = TRUE;
+  return QNCLegacyRegionManipulation (Start, Length, NULL, &WriteEnable, Granularity);
+}
+
+/**
+  Get region information for the attributes of the Legacy Region.
+
+  This function is used to discover the granularity of the attributes for the memory in the legacy
+  region. Each attribute may have a different granularity and the granularity may not be the same
+  for all memory ranges in the legacy region.
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  DescriptorCount[out]  The number of region descriptor entries returned in the Descriptor
+                                buffer.
+  @param  Descriptor[out]       A pointer to a pointer used to return a buffer where the legacy
+                                region information is deposited. This buffer will contain a list of
+                                DescriptorCount number of region descriptors.  This function will
+                                provide the memory for the buffer.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegionGetInfo (
+  IN  EFI_LEGACY_REGION2_PROTOCOL   *This,
+  OUT UINT32                        *DescriptorCount,
+  OUT EFI_LEGACY_REGION_DESCRIPTOR  **Descriptor
+  )
+{
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Entry point to the DXE Driver that produces the Legacy Region Protocol.
+
+  @retval  EFI_SUCCESS One or more of the drivers returned a success code.
+  @retval  !EFI_SUCESS The return status from the last driver entry point in the list.
+
+**/
+EFI_STATUS
+LegacyRegionInit (
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Install the Legacy Region Protocol on a new handle
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mLegacyRegion2Handle,
+                  &gEfiLegacyRegion2ProtocolGuid, &mLegacyRegion2,
+                  NULL
+                  );
+
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h
new file mode 100644
index 0000000000..8afe23f02f
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h
@@ -0,0 +1,198 @@
+/** @file
+The header file legacy region initialization in QNC DXE component.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _LEGACY_REGION_H_
+#define _LEGACY_REGION_H_
+#include "CommonHeader.h"
+
+#include <IndustryStandard/Pci.h>
+
+#define LEGACY_REGION_INSTANCE_SIGNATURE   SIGNATURE_32('R','E','G','N')
+
+typedef struct {
+  UINT32                          Signature;
+
+  EFI_HANDLE                      Handle;
+  EFI_LEGACY_REGION2_PROTOCOL     LegacyRegion2;
+  EFI_HANDLE                      ImageHandle;
+
+  //
+  // Protocol for PAM register access
+  //
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *PciRootBridgeIo;
+} LEGACY_REGION_INSTANCE;
+
+#define LEGACY_REGION_INSTANCE_FROM_THIS(this) \
+  CR(this, LEGACY_REGION_INSTANCE, LegacyRegion2, LEGACY_REGION_INSTANCE_SIGNATURE)
+
+
+EFI_STATUS
+LegacyRegionManipluateRegion (
+  IN  LEGACY_REGION_INSTANCE    *Private
+  );
+
+EFI_STATUS
+LegacyRegionInit (
+  VOID
+  );
+
+/**
+  Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
+
+  If the On parameter evaluates to TRUE, this function enables memory reads in the address range
+  Start to (Start + Length - 1).
+  If the On parameter evaluates to FALSE, this function disables memory reads in the address range
+  Start to (Start + Length - 1).
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  Start[in]             The beginning of the physical address of the region whose attributes
+                                should be modified.
+  @param  Length[in]            The number of bytes of memory whose attributes should be modified.
+                                The actual number of bytes modified may be greater than the number
+                                specified.
+  @param  Granularity[out]      The number of bytes in the last region affected. This may be less
+                                than the total number of bytes affected if the starting address
+                                was not aligned to a region's starting address or if the length
+                                was greater than the number of bytes in the first region.
+  @param  On[in]                Decode / Non-Decode flag.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Decode (
+  IN  EFI_LEGACY_REGION2_PROTOCOL  *This,
+  IN  UINT32                       Start,
+  IN  UINT32                       Length,
+  OUT UINT32                       *Granularity,
+  IN  BOOLEAN                      *On
+  );
+
+/**
+  Modify the hardware to disallow memory writes in a region.
+
+  This function changes the attributes of a memory range to not allow writes.
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  Start[in]             The beginning of the physical address of the region whose
+                                attributes should be modified.
+  @param  Length[in]            The number of bytes of memory whose attributes should be modified.
+                                The actual number of bytes modified may be greater than the number
+                                specified.
+  @param  Granularity[out]      The number of bytes in the last region affected. This may be less
+                                than the total number of bytes affected if the starting address was
+                                not aligned to a region's starting address or if the length was
+                                greater than the number of bytes in the first region.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Lock (
+  IN  EFI_LEGACY_REGION2_PROTOCOL *This,
+  IN  UINT32                      Start,
+  IN  UINT32                      Length,
+  OUT UINT32                      *Granularity
+  );
+
+/**
+  Modify the hardware to disallow memory attribute changes in a region.
+
+  This function makes the attributes of a region read only. Once a region is boot-locked with this
+  function, the read and write attributes of that region cannot be changed until a power cycle has
+  reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  Start[in]             The beginning of the physical address of the region whose
+                                attributes should be modified.
+  @param  Length[in]            The number of bytes of memory whose attributes should be modified.
+                                The actual number of bytes modified may be greater than the number
+                                specified.
+  @param  Granularity[out]      The number of bytes in the last region affected. This may be less
+                                than the total number of bytes affected if the starting address was
+                                not aligned to a region's starting address or if the length was
+                                greater than the number of bytes in the first region.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+  @retval EFI_UNSUPPORTED       The chipset does not support locking the configuration registers in
+                                a way that will not affect memory regions outside the legacy memory
+                                region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2BootLock (
+  IN EFI_LEGACY_REGION2_PROTOCOL          *This,
+  IN  UINT32                              Start,
+  IN  UINT32                              Length,
+  OUT UINT32                              *Granularity
+  );
+
+/**
+  Modify the hardware to allow memory writes in a region.
+
+  This function changes the attributes of a memory range to allow writes.
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  Start[in]             The beginning of the physical address of the region whose
+                                attributes should be modified.
+  @param  Length[in]            The number of bytes of memory whose attributes should be modified.
+                                The actual number of bytes modified may be greater than the number
+                                specified.
+  @param  Granularity[out]      The number of bytes in the last region affected. This may be less
+                                than the total number of bytes affected if the starting address was
+                                not aligned to a region's starting address or if the length was
+                                greater than the number of bytes in the first region.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegion2Unlock (
+  IN  EFI_LEGACY_REGION2_PROTOCOL  *This,
+  IN  UINT32                       Start,
+  IN  UINT32                       Length,
+  OUT UINT32                       *Granularity
+  );
+
+/**
+  Get region information for the attributes of the Legacy Region.
+
+  This function is used to discover the granularity of the attributes for the memory in the legacy
+  region. Each attribute may have a different granularity and the granularity may not be the same
+  for all memory ranges in the legacy region.
+
+  @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
+  @param  DescriptorCount[out]  The number of region descriptor entries returned in the Descriptor
+                                buffer.
+  @param  Descriptor[out]       A pointer to a pointer used to return a buffer where the legacy
+                                region information is deposited. This buffer will contain a list of
+                                DescriptorCount number of region descriptors.  This function will
+                                provide the memory for the buffer.
+
+  @retval EFI_SUCCESS           The region's attributes were successfully modified.
+  @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegionGetInfo (
+  IN  EFI_LEGACY_REGION2_PROTOCOL   *This,
+  OUT UINT32                        *DescriptorCount,
+  OUT EFI_LEGACY_REGION_DESCRIPTOR  **Descriptor
+  );
+
+#endif //_QNC_LEGACY_REGION_H_
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c
new file mode 100644
index 0000000000..b0751a6362
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c
@@ -0,0 +1,518 @@
+/** @file
+QuarkNcSocId module initialization module
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "CommonHeader.h"
+
+#include "LegacyRegion.h"
+#include "DxeQNCSmbus.h"
+
+#include "QNCInit.h"
+
+//
+// Definitions
+//
+#define QNC_RESERVED_ITEM_IO         0
+#define QNC_RESERVED_ITEM_MEMORYIO   1
+#define DXE_DEVICE_DISABLED 0
+#define DXE_DEVICE_ENABLED 1
+
+typedef struct _QNC_SPACE_TABLE_ITEM {
+   UINTN                   IoOrMemory;
+   UINTN                   Type;
+   EFI_PHYSICAL_ADDRESS    BaseAddress;
+   UINT64                  Length;
+   UINTN                   Alignment;
+   BOOLEAN                 RuntimeOrNot;
+} QNC_SPACE_TABLE_ITEM;
+
+typedef struct {
+  ACPI_CPU_DATA       AcpuCpuData;
+  MTRR_SETTINGS       MtrrTable;
+  IA32_DESCRIPTOR     GdtrProfile;
+  IA32_DESCRIPTOR     IdtrProfile;
+  CPU_REGISTER_TABLE  RegisterTable;
+  CPU_REGISTER_TABLE  PreSmmInitRegisterTable;
+} ACPI_CPU_DATA_EX;
+
+//
+// Spaces to be reserved in GCD
+// Expand it to add more
+//
+const QNC_SPACE_TABLE_ITEM  mQNCReservedSpaceTable[] = {
+  {
+    QNC_RESERVED_ITEM_MEMORYIO,
+    EfiGcdMemoryTypeMemoryMappedIo,
+    FixedPcdGet64 (PcdIoApicBaseAddress),
+    FixedPcdGet64 (PcdIoApicSize),
+    0,
+    FALSE
+  },
+  {
+    QNC_RESERVED_ITEM_MEMORYIO,
+    EfiGcdMemoryTypeMemoryMappedIo,
+    FixedPcdGet64 (PcdHpetBaseAddress),
+    FixedPcdGet64 (PcdHpetSize),
+    0,
+    FALSE
+  }
+};
+
+//
+// Global variable for ImageHandle of QNCInit driver
+//
+EFI_HANDLE gQNCInitImageHandle;
+QNC_DEVICE_ENABLES    mQNCDeviceEnables;
+
+
+VOID
+QNCInitializeResource (
+  VOID
+  );
+
+EFI_STATUS
+InitializeQNCPolicy (
+  VOID
+  );
+
+/**
+  Allocate EfiACPIMemoryNVS below 4G memory address.
+
+  This function allocates EfiACPIMemoryNVS below 4G memory address.
+
+  @param Size   Size of memory to allocate.
+
+  @return       Allocated address for output.
+
+**/
+VOID *
+AllocateAcpiNvsMemoryBelow4G (
+  IN UINTN  Size
+  )
+{
+  UINTN                 Pages;
+  EFI_PHYSICAL_ADDRESS  Address;
+  EFI_STATUS            Status;
+  VOID*                 Buffer;
+
+  Pages = EFI_SIZE_TO_PAGES (Size);
+  Address = 0xffffffff;
+
+  Status  = gBS->AllocatePages (
+                   AllocateMaxAddress,
+                   EfiACPIMemoryNVS,
+                   Pages,
+                   &Address
+                   );
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+
+  Buffer = (VOID *) (UINTN) Address;
+  ZeroMem (Buffer, Size);
+
+  return Buffer;
+}
+
+/**
+  Prepare ACPI NVS memory below 4G memory for use of S3 resume.
+
+  This function allocates ACPI NVS memory below 4G memory for use of S3 resume,
+  and saves data into the memory region.
+
+**/
+VOID
+SaveCpuS3Data (
+  VOID
+  )
+{
+  EFI_STATUS        Status;
+  ACPI_CPU_DATA_EX  *AcpiCpuDataEx;
+  ACPI_CPU_DATA     *AcpiCpuData;
+  UINTN             GdtSize;
+  UINTN             IdtSize;
+  VOID              *Gdt;
+  VOID              *Idt;
+
+  //
+  // Allocate ACPI NVS memory below 4G memory for use of S3 resume.
+  //
+  AcpiCpuDataEx = AllocateAcpiNvsMemoryBelow4G (sizeof (ACPI_CPU_DATA_EX));
+  AcpiCpuData = &AcpiCpuDataEx->AcpuCpuData;
+
+  //
+  //
+  //
+  AcpiCpuData->NumberOfCpus              = 1;
+  AcpiCpuData->StackSize                 = PcdGet32 (PcdCpuApStackSize);
+  AcpiCpuData->ApMachineCheckHandlerBase = 0;
+  AcpiCpuData->ApMachineCheckHandlerSize = 0;
+  AcpiCpuData->GdtrProfile               = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->GdtrProfile;
+  AcpiCpuData->IdtrProfile               = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->IdtrProfile;
+  AcpiCpuData->MtrrTable                 = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->MtrrTable;
+  AcpiCpuData->RegisterTable             = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->RegisterTable;
+  AcpiCpuData->PreSmmInitRegisterTable   = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->PreSmmInitRegisterTable;
+
+  //
+  // Allocate stack space for all CPUs
+  //
+  AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateAcpiNvsMemoryBelow4G (AcpiCpuData->NumberOfCpus * AcpiCpuData->StackSize);
+
+  //
+  // Get MTRR settings from currently executing CPU
+  //
+  MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);
+
+  //
+  // Get the BSP's data of GDT and IDT
+  //
+  AsmReadGdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->GdtrProfile);
+  AsmReadIdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->IdtrProfile);
+
+  //
+  // Allocate GDT and IDT in ACPI NVS and copy in current GDT and IDT contents
+  //
+  GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;
+  IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;
+  Gdt = AllocateAcpiNvsMemoryBelow4G (GdtSize + IdtSize);
+  Idt = (VOID *)((UINTN)Gdt + GdtSize);
+  CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);
+  CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);
+  AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;
+  AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;
+
+  //
+  // No RegisterTable entries
+  //
+  AcpiCpuDataEx->RegisterTable.TableLength = 0;
+
+  //
+  // No PreSmmInitRegisterTable entries
+  //
+  AcpiCpuDataEx->PreSmmInitRegisterTable.TableLength = 0;
+
+  //
+  // Set the base address of CPU S3 data to PcdCpuS3DataAddress
+  //
+  Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+   The entry function for QNCInit driver.
+
+   This function just call initialization function for PciHostBridge,
+   LegacyRegion and QNCSmmAccess module.
+
+   @param ImageHandle   The driver image handle for GmchInit driver
+   @param SystemTable   The pointer to System Table
+
+   @retval EFI_SUCCESS  Success to initialize every module for GMCH driver.
+   @return EFI_STATUS   The status of initialization work.
+
+**/
+EFI_STATUS
+EFIAPI
+QNCInit (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  S3BootScriptSaveInformationAsciiString (
+    "QNCInitDxeEntryBegin"
+    );
+
+  gQNCInitImageHandle = ImageHandle;
+
+  mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);
+
+
+  //
+  // Initialize PCIE root ports
+  //
+  Status = QncInitRootPorts ();
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "QNC Root Port initialization is failed!\n"));
+    return Status;
+  }
+
+  Status = LegacyRegionInit ();
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "QNC LegacyRegion initialization is failed!\n"));
+    return Status;
+  }
+
+
+  Status = InitializeQNCPolicy ();
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "QNC Policy initialization is failed!\n"));
+    return Status;
+  }
+
+  Status = InitializeQNCSmbus (ImageHandle,SystemTable);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "QNC Smbus driver is failed!\n"));
+    return Status;
+  }
+
+  QNCInitializeResource ();
+
+  SaveCpuS3Data ();
+
+  S3BootScriptSaveInformationAsciiString (
+    "QNCInitDxeEntryEnd"
+    );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Reserve I/O or memory space in GCD
+
+  @param  IoOrMemory    Switch of I/O or memory.
+  @param  GcdType       Type of the space.
+  @param  BaseAddress   Base address of the space.
+  @param  Length        Length of the space.
+  @param  Alignment     Align with 2^Alignment
+  @param  RuntimeOrNot  For runtime usage or not
+  @param  ImageHandle   Handle for the image of this driver.
+
+  @retval EFI_SUCCESS   Reserve successful
+**/
+EFI_STATUS
+QNCReserveSpaceInGcd(
+  IN UINTN                 IoOrMemory,
+  IN UINTN                 GcdType,
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN UINTN                 Alignment,
+  IN BOOLEAN               RuntimeOrNot,
+  IN EFI_HANDLE            ImageHandle
+  )
+{
+  EFI_STATUS               Status;
+
+  if (IoOrMemory == QNC_RESERVED_ITEM_MEMORYIO) {
+    Status = gDS->AddMemorySpace (
+                    GcdType,
+                    BaseAddress,
+                    Length,
+                    EFI_MEMORY_UC
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        EFI_D_ERROR,
+        "Failed to add memory space :0x%x 0x%x\n",
+        BaseAddress,
+        Length
+        ));
+    }
+    ASSERT_EFI_ERROR (Status);
+    Status = gDS->AllocateMemorySpace (
+                    EfiGcdAllocateAddress,
+                    GcdType,
+                    Alignment,
+                    Length,
+                    &BaseAddress,
+                    ImageHandle,
+                    NULL
+                    );
+    ASSERT_EFI_ERROR (Status);
+    if (RuntimeOrNot) {
+      Status = gDS->SetMemorySpaceAttributes (
+                      BaseAddress,
+                      Length,
+                      EFI_MEMORY_RUNTIME | EFI_MEMORY_UC
+                     );
+      ASSERT_EFI_ERROR (Status);
+    }
+  } else {
+    Status = gDS->AddIoSpace (
+                    GcdType,
+                    BaseAddress,
+                    Length
+                    );
+    ASSERT_EFI_ERROR (Status);
+    Status = gDS->AllocateIoSpace (
+                    EfiGcdAllocateAddress,
+                    GcdType,
+                    Alignment,
+                    Length,
+                    &BaseAddress,
+                    ImageHandle,
+                    NULL
+                    );
+    ASSERT_EFI_ERROR (Status);
+  }
+  return Status;
+}
+
+
+/**
+  Initialize the memory and io resource which belong to QNC.
+  1) Report and allocate all BAR's memory to GCD.
+  2) Report PCI memory and I/O space to GCD.
+  3) Set memory attribute for <1M memory space.
+**/
+VOID
+QNCInitializeResource (
+  )
+{
+  EFI_PHYSICAL_ADDRESS            BaseAddress;
+  EFI_STATUS                      Status;
+  UINT64                          ExtraRegionLength;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+  UINTN                           Index;
+
+  // Report TSEG range
+  // This range maybe has been reportted in PEI phase via Resource Hob.
+  //
+  QNCGetTSEGMemoryRange (&BaseAddress, &ExtraRegionLength);
+  if (ExtraRegionLength != 0) {
+    Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &Descriptor);
+    if (Status == EFI_NOT_FOUND) {
+      Status = gDS->AddMemorySpace (
+                      EfiGcdMemoryTypeReserved,
+                      BaseAddress,
+                      ExtraRegionLength,
+                      EFI_MEMORY_UC
+                      );
+    }
+  }
+
+  //
+  // < 1M resource setting. The memory ranges <1M has been added into GCD via
+  // resource hob produced by PEI phase. Here will set memory attribute of these
+  // ranges for DXE phase.
+  //
+
+  //
+  // Dos Area (0 ~ 0x9FFFFh)
+  //
+  Status = gDS->GetMemorySpaceDescriptor (0, &Descriptor);
+  DEBUG ((
+    EFI_D_INFO,
+    "DOS Area Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n",
+    Descriptor.BaseAddress,
+    Descriptor.Length,
+    Descriptor.Attributes
+    ));
+  ASSERT_EFI_ERROR (Status);
+  Status = gDS->SetMemorySpaceAttributes(
+                  0,
+                  0xA0000,
+                  EFI_MEMORY_WB
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Default SMRAM UnCachable until SMBASE relocated.
+  //
+  Status = gDS->SetMemorySpaceAttributes(
+                  0x30000,
+                  0x10000,
+                  EFI_MEMORY_UC
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Default SMM ABSEG area. (0xA0000 ~ 0xBFFFF)
+  //
+  Status = gDS->GetMemorySpaceDescriptor (0xA0000, &Descriptor);
+  DEBUG ((
+    EFI_D_INFO,
+    "ABSEG Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n",
+    Descriptor.BaseAddress,
+    Descriptor.Length,
+    Descriptor.Attributes
+    ));
+  ASSERT_EFI_ERROR (Status);
+  Status = gDS->SetMemorySpaceAttributes(
+                  0xA0000,
+                  0x20000,
+                  EFI_MEMORY_UC
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Expansion BIOS area.
+  //
+  Status = gDS->GetMemorySpaceDescriptor (0xC0000, &Descriptor);
+  DEBUG ((
+    EFI_D_INFO,
+    "Memory base = 0x%x, length = 0x%x, attribute = 0x%x\n",
+    Descriptor.BaseAddress,
+    Descriptor.Length,
+    Descriptor.Attributes
+    ));
+  ASSERT_EFI_ERROR (Status);
+  Status = gDS->SetMemorySpaceAttributes(
+                  0xC0000,
+                  0x30000,
+                  EFI_MEMORY_UC
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Report other IO resources from mQNCReservedSpaceTable in GCD
+  //
+  for (Index = 0; Index < sizeof (mQNCReservedSpaceTable) / sizeof (QNC_SPACE_TABLE_ITEM); Index++) {
+    Status = QNCReserveSpaceInGcd (
+               mQNCReservedSpaceTable[Index].IoOrMemory,
+               mQNCReservedSpaceTable[Index].Type,
+               mQNCReservedSpaceTable[Index].BaseAddress,
+               mQNCReservedSpaceTable[Index].Length,
+               mQNCReservedSpaceTable[Index].Alignment,
+               mQNCReservedSpaceTable[Index].RuntimeOrNot,
+               gQNCInitImageHandle
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  //
+  // Report unused PCIe config space as reserved.
+  //
+  if (PcdGet64 (PcdPciExpressSize) < SIZE_256MB) {
+    Status = QNCReserveSpaceInGcd (
+               QNC_RESERVED_ITEM_MEMORYIO,
+               EfiGcdMemoryTypeMemoryMappedIo,
+               (PcdGet64(PcdPciExpressBaseAddress) + PcdGet64(PcdPciExpressSize)),
+               (SIZE_256MB - PcdGet64(PcdPciExpressSize)),
+               0,
+               FALSE,
+               gQNCInitImageHandle
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+}
+
+/**
+  Use the platform PCD to initialize devices in the QNC
+
+  @param  ImageHandle   Handle for the image of this driver.
+  @retval EFI_SUCCESS   Initialize successful
+**/
+EFI_STATUS
+InitializeQNCPolicy (
+  )
+{
+  UINT32       PciD31F0RegBase;  // LPC
+
+  PciD31F0RegBase = PciDeviceMmBase (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC);
+
+  //
+  // Disable for smbus
+  //
+  if (mQNCDeviceEnables.Bits.Smbus == DXE_DEVICE_DISABLED) {
+    S3MmioAnd32 (PciD31F0RegBase + R_QNC_LPC_SMBUS_BASE, (~B_QNC_LPC_SMBUS_BASE_EN));
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h
new file mode 100644
index 0000000000..c5d1ffad40
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h
@@ -0,0 +1,49 @@
+/** @file
+Header file for QNC Initialization Driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+#ifndef _QNC_INITIALIZATION_DRIVER_H_
+#define _QNC_INITIALIZATION_DRIVER_H_
+
+EFI_STATUS
+QncInitRootPorts (
+  )
+/*++
+
+Routine Description:
+
+  Perform Initialization of the Downstream Root Ports.
+
+Arguments:
+
+Returns:
+
+  EFI_STATUS
+
+--*/
+;
+
+EFI_STATUS
+SetInitRootPortDownstreamS3Item (
+  )
+/*++
+
+Routine Description:
+
+  Set an Init Root Port Downstream devices S3 dispatch item, this function may assert if any error happend
+
+Arguments:
+
+Returns:
+
+  EFI_SUCCESS             The function completed successfully
+
+--*/
+;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf
new file mode 100644
index 0000000000..b250602cf4
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf
@@ -0,0 +1,92 @@
+## @file
+# Component description file for QNCInit driver.
+#
+# QNCInit driver implement QuarkNcSocId related drivers, includes:
+# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver.
+#
+# This driver mainly do full initialization for the QNC chipet includes:
+# 1. Initialize the PCI Express device.
+# 2. Initialize the PciHostBridge, and allocate the I/O and memory space from GCD service.
+# 3. Initialize the SmmAccess module and install EFI_SMM_ACCESS_PROTOCOL
+# 4. Initialize the LegacyRegion module, install EFI_LEGACY_REGION_PROTOCOL and set below 1M
+#    memory attribute from MTRR.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = QNCInitDxe
+  FILE_GUID                      = 74D3B506-EE9C-47ed-B749-41261401DA78
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = QNCInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  LegacyRegion.h
+  LegacyRegion.c
+  DxeQNCSmbus.c
+  DxeQNCSmbus.h
+  QNCSmbusExec.c
+  QNCSmbus.h
+  QNCInit.c
+  QNCInit.h
+  CommonHeader.h
+  QNCRootPorts.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  BaseLib
+  UefiBootServicesTableLib
+  DxeServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+  MtrrLib
+  IoLib
+  SmbusLib
+  S3IoLib
+  S3BootScriptLib
+  IntelQNCLib
+  QNCAccessLib
+
+[Protocols]
+  gEfiLegacyRegion2ProtocolGuid                 # PROTOCOL ALWAYS_PRODUCED
+  gEfiSmbusHcProtocolGuid                       # PROTOCOL ALWAYS_PRODUCED
+  gEfiQncS3SupportProtocolGuid                  # PROTOCOL ALWAYS_CONSUMED
+
+[FeaturePcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed
+
+[FixedPcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicSize
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetSize
+
+[Pcd]
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize                           ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress|0x0|UINT64|0x60000010   ## PRODUCES
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress                     ## CONSUMES
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciExpressSize                      ## CONSUMES
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrNum
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrTable
+
+[Depex]
+  gEfiPlatformPolicyProtocolGuid AND gEfiQncS3SupportProtocolGuid
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c
new file mode 100644
index 0000000000..7c3f18efc7
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c
@@ -0,0 +1,76 @@
+/** @file
+PciHostBridge driver module, part of QNC module.
+
+Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "CommonHeader.h"
+#include "QNCInit.h"
+
+UINT32  mS3ParameterRootPortDownstream = 0;
+EFI_QNC_S3_DISPATCH_ITEM  mS3DispatchItem = {
+    QncS3ItemTypeInitPcieRootPortDownstream,
+    &mS3ParameterRootPortDownstream
+  };
+
+EFI_STATUS
+QncInitRootPorts (
+  )
+/*++
+
+Routine Description:
+
+  Perform Initialization of the Downstream Root Ports
+
+Arguments:
+
+Returns:
+
+  EFI_SUCCESS             The function completed successfully
+
+--*/
+{
+  EFI_STATUS                   Status;
+  EFI_QNC_S3_SUPPORT_PROTOCOL  *QncS3Support;
+  VOID                         *Context;
+  VOID                         *S3DispatchEntryPoint;
+
+  Status = PciExpressInit ();
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Get the QNC S3 Support Protocol
+  //
+  Status = gBS->LocateProtocol (
+                  &gEfiQncS3SupportProtocolGuid,
+                  NULL,
+                  (VOID **) &QncS3Support
+                  );
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the QNC S3 Support Protocol
+  //
+  Status = QncS3Support->SetDispatchItem (
+                          QncS3Support,
+                          &mS3DispatchItem,
+                          &S3DispatchEntryPoint,
+                          &Context
+                          );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Save the script dispatch item in the Boot Script
+  //
+  Status = S3BootScriptSaveDispatch2 (S3DispatchEntryPoint, Context);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h
new file mode 100644
index 0000000000..fbd1859dea
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h
@@ -0,0 +1,80 @@
+/** @file
+Common definitons for SMBus PEIM/DXE driver. Smbus PEI and DXE
+modules share the same version of this file.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _QNC_SMBUS_H_
+#define _QNC_SMBUS_H_
+
+#include "CommonHeader.h"
+
+//
+// Minimum and maximum length for SMBus bus block protocols defined in SMBus spec 2.0.
+//
+#define MIN_SMBUS_BLOCK_LEN               1
+#define MAX_SMBUS_BLOCK_LEN               32
+#define ADD_LENGTH(SmbusAddress, Length)  ((SmbusAddress) + SMBUS_LIB_ADDRESS (0, 0, (Length), FALSE))
+
+/**
+  Executes an SMBus operation to an SMBus controller. Returns when either the command has been
+  executed or an error is encountered in doing the operation.
+
+  The internal worker function provides a standard way to execute an operation as defined in the
+  System Management Bus (SMBus) Specification. The resulting transaction will be either that the
+  SMBus slave devices accept this transaction or that this function returns with error.
+
+  @param  SlaveAddress            The SMBus slave address of the device with which to communicate.
+  @param  Command                 This command is transmitted by the SMBus host controller to the
+                                  SMBus slave device and the interpretation is SMBus slave device
+                                  specific. It can mean the offset to a list of functions inside an
+                                  SMBus slave device. Not all operations or slave devices support
+                                  this command's registers.
+  @param  Operation               Signifies which particular SMBus hardware protocol instance that
+                                  it will use to execute the SMBus transactions. This SMBus
+                                  hardware protocol is defined by the SMBus Specification and is
+                                  not related to EFI.
+  @param  PecCheck                Defines if Packet Error Code (PEC) checking is required for this
+                                  operation.
+  @param  Length                  Signifies the number of bytes that this operation will do. The
+                                  maximum number of bytes can be revision specific and operation
+                                  specific. This field will contain the actual number of bytes that
+                                  are executed for this operation. Not all operations require this
+                                  argument.
+  @param  Buffer                  Contains the value of data to execute to the SMBus slave device.
+                                  Not all operations require this argument. The length of this
+                                  buffer is identified by Length.
+
+  @retval EFI_SUCCESS             The last data that was returned from the access matched the poll
+                                  exit criteria.
+  @retval EFI_CRC_ERROR           Checksum is not correct (PEC is incorrect).
+  @retval EFI_TIMEOUT             Timeout expired before the operation was completed. Timeout is
+                                  determined by the SMBus host controller device.
+  @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR        The request was not completed because a failure that was
+                                  reflected in the Host Status Register bit. Device errors are a
+                                  result of a transaction collision, illegal command field,
+                                  unclaimed cycle (host initiated), or bus errors (collisions).
+  @retval EFI_INVALID_PARAMETER   Operation is not defined in EFI_SMBUS_OPERATION.
+  @retval EFI_INVALID_PARAMETER   Length/Buffer is NULL for operations except for EfiSmbusQuickRead
+                                  and EfiSmbusQuickWrite. Length is outside the range of valid
+                                  values.
+  @retval EFI_UNSUPPORTED         The SMBus operation or PEC is not supported.
+  @retval EFI_BUFFER_TOO_SMALL    Buffer is not sufficient for this operation.
+
+**/
+EFI_STATUS
+Execute (
+  IN     EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
+  IN     EFI_SMBUS_DEVICE_COMMAND Command,
+  IN     EFI_SMBUS_OPERATION      Operation,
+  IN     BOOLEAN                  PecCheck,
+  IN OUT UINTN                    *Length,
+  IN OUT VOID                     *Buffer
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c
new file mode 100644
index 0000000000..dbd3566496
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c
@@ -0,0 +1,246 @@
+/** @file
+Common code to implement SMBus bus protocols. Smbus PEI and DXE modules
+share the same version of this file.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "CommonHeader.h"
+
+#include "QNCSmbus.h"
+
+/**
+  Checks the parameter of SmbusExecute().
+
+  This function checks the input parameters of SmbusExecute().  If the input parameters are valid
+  for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain
+  error code based on the input SMBus bus protocol.
+
+  @param  SlaveAddress            The SMBus slave address of the device with which to communicate.
+  @param  Command                 This command is transmitted by the SMBus host controller to the
+                                  SMBus slave device and the interpretation is SMBus slave device
+                                  specific. It can mean the offset to a list of functions inside an
+                                  SMBus slave device. Not all operations or slave devices support
+                                  this command's registers.
+  @param  Operation               Signifies which particular SMBus hardware protocol instance that
+                                  it will use to execute the SMBus transactions. This SMBus
+                                  hardware protocol is defined by the SMBus Specification and is
+                                  not related to EFI.
+  @param  PecCheck                Defines if Packet Error Code (PEC) checking is required for this
+                                  operation.
+  @param  Length                  Signifies the number of bytes that this operation will do. The
+                                  maximum number of bytes can be revision specific and operation
+                                  specific. This field will contain the actual number of bytes that
+                                  are executed for this operation. Not all operations require this
+                                  argument.
+  @param  Buffer                  Contains the value of data to execute to the SMBus slave device.
+                                  Not all operations require this argument. The length of this
+                                  buffer is identified by Length.
+
+  @retval EFI_SUCCESS             All the parameters are valid for the corresponding SMBus bus
+                                  protocol.
+  @retval EFI_INVALID_PARAMETER   Operation is not defined in EFI_SMBUS_OPERATION.
+  @retval EFI_INVALID_PARAMETER   Length/Buffer is NULL for operations except for EfiSmbusQuickRead
+                                  and EfiSmbusQuickWrite. Length is outside the range of valid
+                                  values.
+  @retval EFI_UNSUPPORTED         The SMBus operation or PEC is not supported.
+  @retval EFI_BUFFER_TOO_SMALL    Buffer is not sufficient for this operation.
+
+**/
+EFI_STATUS
+QncSmbusExecCheckParameters (
+  IN     EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
+  IN     EFI_SMBUS_DEVICE_COMMAND Command,
+  IN     EFI_SMBUS_OPERATION      Operation,
+  IN     BOOLEAN                  PecCheck,
+  IN OUT UINTN                    *Length,
+  IN OUT VOID                     *Buffer
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       RequiredLen;
+
+  //
+  // Set default value to be 2:
+  // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall.
+  //
+  RequiredLen = 2;
+  Status      = EFI_SUCCESS;
+  switch (Operation) {
+  case EfiSmbusQuickRead:
+  case EfiSmbusQuickWrite:
+    if (PecCheck || Command != 0) {
+      return EFI_UNSUPPORTED;
+    }
+    break;
+  case EfiSmbusReceiveByte:
+  case EfiSmbusSendByte:
+    if (Command != 0) {
+      return EFI_UNSUPPORTED;
+    }
+    //
+    // Cascade to check length parameter.
+    //
+  case EfiSmbusReadByte:
+  case EfiSmbusWriteByte:
+    RequiredLen = 1;
+    //
+    // Cascade to check length parameter.
+    //
+  case EfiSmbusReadWord:
+  case EfiSmbusWriteWord:
+  case EfiSmbusProcessCall:
+    if (Buffer == NULL || Length == NULL) {
+      return EFI_INVALID_PARAMETER;
+    } else if (*Length < RequiredLen) {
+      Status = EFI_BUFFER_TOO_SMALL;
+    }
+    *Length = RequiredLen;
+    break;
+  case EfiSmbusReadBlock:
+  case EfiSmbusWriteBlock:
+    if ((Buffer == NULL) ||
+        (Length == NULL) ||
+        (*Length < MIN_SMBUS_BLOCK_LEN) ||
+        (*Length > MAX_SMBUS_BLOCK_LEN)) {
+      return EFI_INVALID_PARAMETER;
+    }
+    break;
+  case EfiSmbusBWBRProcessCall:
+    return EFI_UNSUPPORTED;
+  default:
+    return EFI_INVALID_PARAMETER;
+  }
+  return Status;
+}
+
+/**
+  Executes an SMBus operation to an SMBus controller. Returns when either the command has been
+  executed or an error is encountered in doing the operation.
+
+  The internal worker function provides a standard way to execute an operation as defined in the
+  System Management Bus (SMBus) Specification. The resulting transaction will be either that the
+  SMBus slave devices accept this transaction or that this function returns with error.
+
+  @param  SlaveAddress            The SMBus slave address of the device with which to communicate.
+  @param  Command                 This command is transmitted by the SMBus host controller to the
+                                  SMBus slave device and the interpretation is SMBus slave device
+                                  specific. It can mean the offset to a list of functions inside an
+                                  SMBus slave device. Not all operations or slave devices support
+                                  this command's registers.
+  @param  Operation               Signifies which particular SMBus hardware protocol instance that
+                                  it will use to execute the SMBus transactions. This SMBus
+                                  hardware protocol is defined by the SMBus Specification and is
+                                  not related to EFI.
+  @param  PecCheck                Defines if Packet Error Code (PEC) checking is required for this
+                                  operation.
+  @param  Length                  Signifies the number of bytes that this operation will do. The
+                                  maximum number of bytes can be revision specific and operation
+                                  specific. This field will contain the actual number of bytes that
+                                  are executed for this operation. Not all operations require this
+                                  argument.
+  @param  Buffer                  Contains the value of data to execute to the SMBus slave device.
+                                  Not all operations require this argument. The length of this
+                                  buffer is identified by Length.
+
+  @retval EFI_SUCCESS             The last data that was returned from the access matched the poll
+                                  exit criteria.
+  @retval EFI_CRC_ERROR           Checksum is not correct (PEC is incorrect).
+  @retval EFI_TIMEOUT             Timeout expired before the operation was completed. Timeout is
+                                  determined by the SMBus host controller device.
+  @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR        The request was not completed because a failure that was
+                                  reflected in the Host Status Register bit. Device errors are a
+                                  result of a transaction collision, illegal command field,
+                                  unclaimed cycle (host initiated), or bus errors (collisions).
+  @retval EFI_INVALID_PARAMETER   Operation is not defined in EFI_SMBUS_OPERATION.
+  @retval EFI_INVALID_PARAMETER   Length/Buffer is NULL for operations except for EfiSmbusQuickRead
+                                  and EfiSmbusQuickWrite. Length is outside the range of valid
+                                  values.
+  @retval EFI_UNSUPPORTED         The SMBus operation or PEC is not supported.
+  @retval EFI_BUFFER_TOO_SMALL    Buffer is not sufficient for this operation.
+
+**/
+EFI_STATUS
+Execute (
+  IN     EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
+  IN     EFI_SMBUS_DEVICE_COMMAND Command,
+  IN     EFI_SMBUS_OPERATION      Operation,
+  IN     BOOLEAN                  PecCheck,
+  IN OUT UINTN                    *Length,
+  IN OUT VOID                     *Buffer
+  )
+{
+  EFI_STATUS                      Status;
+  UINTN                           SmbusAddress;
+  UINTN                           WorkBufferLen;
+  UINT8                           WorkBuffer[MAX_SMBUS_BLOCK_LEN];
+
+  Status = QncSmbusExecCheckParameters (
+             SlaveAddress,
+             Command,
+             Operation,
+             PecCheck,
+             Length,
+             Buffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SmbusAddress = SMBUS_LIB_ADDRESS (SlaveAddress.SmbusDeviceAddress, Command, *Length, PecCheck);
+
+  switch (Operation) {
+  case EfiSmbusQuickRead:
+    SmBusQuickRead (SmbusAddress, &Status);
+    break;
+  case EfiSmbusQuickWrite:
+    SmBusQuickWrite (SmbusAddress, &Status);
+    break;
+  case EfiSmbusReceiveByte:
+    *(UINT8 *) Buffer = SmBusReceiveByte (SmbusAddress, &Status);
+    break;
+  case EfiSmbusSendByte:
+    SmBusSendByte (SmbusAddress, *(UINT8 *) Buffer, &Status);
+    break;
+  case EfiSmbusReadByte:
+    *(UINT8 *) Buffer = SmBusReadDataByte (SmbusAddress, &Status);
+    break;
+  case EfiSmbusWriteByte:
+    SmBusWriteDataByte (SmbusAddress, *(UINT8 *) Buffer, &Status);
+    break;
+  case EfiSmbusReadWord:
+    *(UINT16 *) Buffer = SmBusReadDataWord (SmbusAddress, &Status);
+    break;
+  case EfiSmbusWriteWord:
+    SmBusWriteDataWord (SmbusAddress, *(UINT16 *) Buffer, &Status);
+    break;
+  case EfiSmbusProcessCall:
+    *(UINT16 *) Buffer = SmBusProcessCall (SmbusAddress, *(UINT16 *) Buffer, &Status);
+    break;
+  case EfiSmbusReadBlock:
+    WorkBufferLen = SmBusReadBlock (SmbusAddress, WorkBuffer, &Status);
+    if (!EFI_ERROR (Status)) {
+      //
+      // Read block transaction is complete successfully, and then
+      // check whether the output buffer is large enough.
+      //
+      if (*Length >= WorkBufferLen) {
+        CopyMem (Buffer, WorkBuffer, WorkBufferLen);
+      } else {
+        Status = EFI_BUFFER_TOO_SMALL;
+      }
+      *Length = WorkBufferLen;
+    }
+    break;
+  case EfiSmbusWriteBlock:
+    SmBusWriteBlock (ADD_LENGTH (SmbusAddress, *Length), Buffer, &Status);
+    break;
+  default:
+    break;
+  }
+
+  return Status;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c
new file mode 100644
index 0000000000..a4617ccca2
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c
@@ -0,0 +1,417 @@
+/** @file
+This is the driver that implements the QNC S3 Support protocol
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "QncS3Support.h"
+
+//
+// Global Variables
+//
+EFI_QNC_S3_SUPPORT_PROTOCOL mQncS3SupportProtocol;
+QNC_S3_PARAMETER_HEADER     *mS3Parameter;
+UINT32                      mQncS3ImageEntryPoint;
+VOID                        *mQncS3ImageAddress;
+UINTN                       mQncS3ImageSize;
+
+extern EFI_GUID gQncS3CodeInLockBoxGuid;
+extern EFI_GUID gQncS3ContextInLockBoxGuid;
+
+/**
+
+    Create a buffer that is used to store context information for use with
+    dispatch functions.
+
+    @retval EFI_SUCCESS - Buffer allocated and initialized.
+
+**/
+EFI_STATUS
+CreateContextBuffer (
+  VOID
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PHYSICAL_ADDRESS  Address;
+  UINT32                ContextStoreSize;
+
+  ContextStoreSize = EFI_PAGE_SIZE;
+
+  //
+  // Allcoate <4G EfiReservedMemory
+  //
+  Address = 0xFFFFFFFF;
+  Status = gBS->AllocatePages (AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (ContextStoreSize), &Address);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  mS3Parameter  = (QNC_S3_PARAMETER_HEADER *) (UINTN) Address;
+
+  //
+  // Determine the maximum number of context entries that can be stored in this
+  // table.
+  //
+  mS3Parameter->MaxContexts = ((ContextStoreSize - sizeof(QNC_S3_PARAMETER_HEADER)) / sizeof(EFI_DISPATCH_CONTEXT_UNION)) + 1;
+  mS3Parameter->StorePosition = 0;
+
+  return Status;
+}
+
+//
+// Functions
+//
+EFI_STATUS
+EFIAPI
+QncS3SupportEntryPoint (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+/*++
+
+  Routine Description:
+
+    QNC S3 support driver entry point
+
+  Arguments:
+
+    ImageHandle     - Handle for the image of this driver
+    SystemTable     - Pointer to the EFI System Table
+
+  Returns:
+
+    EFI_STATUS
+
+--*/
+{
+  EFI_STATUS  Status;
+  VOID        *TmpPtr;
+  EFI_EVENT   Event;
+
+  //
+  // If the protocol is found execution is happening in ACPI NVS memory.  If it
+  // is not found copy the driver into ACPI NVS memory and pass control to it.
+  //
+  Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &TmpPtr);
+
+  //
+  // Load the QNC S3 image
+  //
+  if (EFI_ERROR (Status)) {
+    Status = LoadQncS3Image (SystemTable);
+    ASSERT_EFI_ERROR (Status);
+
+  } else {
+    DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - Begin\n"));
+    //
+    // Allocate and initialize context buffer.
+    //
+    Status = CreateContextBuffer ();
+
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    //
+    // Install the QNC S3 Support protocol
+    //
+    mQncS3SupportProtocol.SetDispatchItem = QncS3SetDispatchItem;
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &ImageHandle,
+                    &gEfiQncS3SupportProtocolGuid,
+                    &mQncS3SupportProtocol,
+                    NULL
+                    );
+
+    mQncS3ImageAddress = (VOID *)(UINTN)PcdGet64(PcdQncS3CodeInLockBoxAddress);
+    mQncS3ImageSize    = (UINTN)PcdGet64(PcdQncS3CodeInLockBoxSize);
+    DEBUG ((DEBUG_INFO, "QncS3SupportEntry Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));
+    DEBUG ((DEBUG_INFO, "QncS3SupportEntry Contex = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));
+    ASSERT (mQncS3ImageAddress != 0);
+
+    //
+    // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
+    //
+    Status = gBS->CreateEventEx (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    QncS3BootEvent,
+                    NULL,
+                    &gEfiEndOfDxeEventGroupGuid,
+                    &Event
+                    );
+    ASSERT_EFI_ERROR (Status);
+
+    DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - End\n"));
+  }
+
+
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+QncS3SetDispatchItem (
+  IN     EFI_QNC_S3_SUPPORT_PROTOCOL   *This,
+  IN     EFI_QNC_S3_DISPATCH_ITEM      *DispatchItem,
+  OUT  VOID                            **S3DispatchEntryPoint,
+  OUT  VOID                            **Context
+  )
+/*++
+
+Routine Description:
+
+  Set an item to be dispatched at S3 resume time. At the same time, the entry point
+  of the QNC S3 support image is returned to be used in subsequent boot script save
+  call
+
+Arguments:
+
+  This                    - Pointer to the protocol instance.
+  DispatchItem            - The item to be dispatched.
+  S3DispatchEntryPoint    - The entry point of the QNC S3 support image.
+
+Returns:
+
+  EFI_STATUS              - Successfully completed.
+  EFI_OUT_OF_RESOURCES    - Out of resources.
+
+--*/
+{
+
+  DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() Start\n"));
+
+  //
+  // Set default values.
+  //
+  *S3DispatchEntryPoint = NULL;
+  *Context = NULL;
+
+  //
+  // Determine if this entry will fit.
+  //
+  if (mS3Parameter->StorePosition >= mS3Parameter->MaxContexts) {
+    DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem exceeds max length - 0x%08x\n", (UINTN)mS3Parameter->MaxContexts));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  //
+  // Calculate the size required;
+  // ** Always round up to be 8 byte aligned
+  //
+  switch (DispatchItem->Type) {
+    case QncS3ItemTypeInitPcieRootPortDownstream:
+      *S3DispatchEntryPoint = (VOID*) (UINTN)QncS3InitPcieRootPortDownstream;
+      *Context = &mS3Parameter->Contexts[mS3Parameter->StorePosition];
+       CopyMem (&mS3Parameter->Contexts[mS3Parameter->StorePosition], DispatchItem->Parameter, sizeof(UINT32));
+      DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream @ 0x%08x - context  0x%08x\n", (UINTN)*S3DispatchEntryPoint, (UINTN)*Context));
+       break;
+
+    default:
+      return EFI_UNSUPPORTED;
+
+  }
+
+  mS3Parameter->StorePosition ++;
+  DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() End\n"));
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LoadQncS3Image (
+  IN  EFI_SYSTEM_TABLE   *SystemTable
+  )
+/*++
+
+Routine Description:
+
+  Load the QNC S3 Image into Efi Reserved Memory below 4G.
+
+Arguments:
+
+  ImageEntryPoint     the ImageEntryPoint after success loading
+
+Returns:
+
+  EFI_STATUS
+
+--*/
+{
+  EFI_STATUS                                    Status;
+  UINT8                                         *Buffer;
+  UINTN                                         BufferSize;
+  VOID                                          *FfsBuffer;
+  PE_COFF_LOADER_IMAGE_CONTEXT                  ImageContext;
+  EFI_HANDLE                                    NewImageHandle;
+
+  //
+  // Install NULL protocol on module file handle to indicate that the entry point
+  // has been called for the first time.
+  //
+  NewImageHandle = NULL;
+  Status = gBS->InstallProtocolInterface (
+    &NewImageHandle,
+    &gEfiCallerIdGuid,
+    EFI_NATIVE_INTERFACE,
+    NULL
+    );
+
+
+  //
+  // Find this module so it can be loaded again.
+  //
+  Status = GetSectionFromAnyFv  (
+             &gEfiCallerIdGuid,
+             EFI_SECTION_PE32,
+             0,
+             (VOID**) &Buffer,
+             &BufferSize
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+
+  //
+  // Get information about the image being loaded.
+  //
+  ImageContext.Handle = Buffer;
+  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+  //
+  // Get information about the image being loaded
+  //
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->AllocatePool (
+                EfiReservedMemoryType,
+                BufferSize + ImageContext.SectionAlignment,
+                &FfsBuffer
+                );
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for no enough space! \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  mQncS3ImageAddress = FfsBuffer;
+  mQncS3ImageSize    = BufferSize + ImageContext.SectionAlignment;
+  Status = PcdSet64S (PcdQncS3CodeInLockBoxAddress, (UINT64)(UINTN)mQncS3ImageAddress);
+  ASSERT_EFI_ERROR (Status);
+  Status = PcdSet64S (PcdQncS3CodeInLockBoxSize, (UINT64)mQncS3ImageSize);
+  ASSERT_EFI_ERROR (Status);
+  //
+  // Align buffer on section boundary
+  //
+  ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
+  if (ImageContext.SectionAlignment != 0) {
+    ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+    ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
+  }
+
+  //
+  // Load the image to our new buffer
+  //
+  Status = PeCoffLoaderLoadImage (&ImageContext);
+  if (EFI_ERROR (Status)) {
+    gBS->FreePool (FfsBuffer);
+    DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderLoadImage failure! \n"));
+    return Status;
+  }
+
+  //
+  // Relocate the image in our new buffer
+  //
+  Status = PeCoffLoaderRelocateImage (&ImageContext);
+  if (EFI_ERROR (Status)) {
+    PeCoffLoaderUnloadImage (&ImageContext);
+    gBS->FreePool (FfsBuffer);
+    DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderRelocateImage failure! \n"));
+    return Status;
+  }
+
+  //
+  // Invalidate instruction cache and pass control to the image.  This will perform
+  // the initialization of the module and publish the supporting protocols.
+  //
+  InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+  Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);
+  if (EFI_ERROR (Status)) {
+    gBS->FreePool (FfsBuffer);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+QncS3InitPcieRootPortDownstream (
+  IN EFI_HANDLE ImageHandle,
+  IN VOID       *Context
+  )
+/*++
+
+  Routine Description:
+    Perform Init Root Port Downstream devices on S3 resume
+
+  Arguments:
+    Parameter         Parameters passed in from DXE
+
+  Returns:
+    EFI_STATUS
+
+--*/
+{
+  EFI_STATUS  Status;
+
+  DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() Begin\n"));
+
+  //
+  // Initialize the device behind the root port.
+  //
+  Status = PciExpressInit ();
+
+  //
+  // Not checking the error status here - downstream device not present does not
+  // mean an error of this root port. Our return status of EFI_SUCCESS means this
+  // port is enabled and outer function depends on this return status to do
+  // subsequent initializations.
+  //
+
+  if (Status != EFI_SUCCESS){
+    DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() failed\n"));
+  }
+
+  DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() End\n"));
+  return Status;
+}
+
+VOID
+EFIAPI
+QncS3BootEvent (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // These 2 boxes will be restored by RestoreAllLockBoxInPlace in S3Resume automatically
+  //
+  DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));
+  SaveLockBox(&gQncS3CodeInLockBoxGuid, mQncS3ImageAddress, mQncS3ImageSize);
+  Status = SetLockBoxAttributes (&gQncS3CodeInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+  ASSERT_EFI_ERROR (Status);
+
+  DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Context = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));
+  SaveLockBox(&gQncS3ContextInLockBoxGuid, (VOID *)mS3Parameter, EFI_PAGE_SIZE);
+  Status = SetLockBoxAttributes (&gQncS3ContextInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+  ASSERT_EFI_ERROR (Status);
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h
new file mode 100644
index 0000000000..a126e38b7f
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h
@@ -0,0 +1,117 @@
+/** @file
+Header file for QNC S3 Support driver
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _QNC_S3_SUPPORT_H_
+#define _QNC_S3_SUPPORT_H_
+
+//
+// External include files do NOT need to be explicitly specified in real EDKII
+// environment
+//
+//
+// Driver Consumed Protocol Prototypes
+//
+#include <Protocol/FirmwareVolume2.h>
+#include <Library/UefiLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+//
+// Driver Produced Protocol Prototypes
+//
+#include <Protocol/LoadedImage.h>
+#include <Protocol/QncS3Support.h>
+
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/IntelQNCLib.h>
+//
+// Define the header of the context region.
+//
+typedef struct {
+  UINT32                      MaxContexts;
+  UINT32                      StorePosition;
+  EFI_DISPATCH_CONTEXT_UNION  Contexts[1];
+} QNC_S3_PARAMETER_HEADER;
+//
+// Function prototypes
+//
+EFI_STATUS
+EFIAPI
+QncS3SetDispatchItem (
+  IN     EFI_QNC_S3_SUPPORT_PROTOCOL   *This,
+  IN     EFI_QNC_S3_DISPATCH_ITEM      *DispatchItem,
+  OUT    VOID                          **S3DispatchEntryPoint,
+  OUT    VOID                          **Context
+  )
+/*++
+
+Routine Description:
+
+  Set an item to be dispatched at S3 resume time. At the same time, the entry point
+  of the QNC S3 support image is returned to be used in subsequent boot script save
+  call
+
+Arguments:
+
+  This                    - Pointer to the protocol instance.
+  DispatchItem            - The item to be dispatched.
+  S3DispatchEntryPoint    - The entry point of the QNC S3 support image.
+
+Returns:
+
+  EFI_STATUS              - Successfully completed.
+  EFI_OUT_OF_RESOURCES    - Out of resources.
+
+--*/
+;
+
+EFI_STATUS
+LoadQncS3Image (
+  IN  EFI_SYSTEM_TABLE   *SystemTable
+  )
+/*++
+
+Routine Description:
+
+  Load the QNC S3 Image into Efi Reserved Memory below 4G.
+
+Arguments:
+
+  ImageEntryPoint     the ImageEntryPoint after success loading
+
+Returns:
+
+  EFI_STATUS
+
+--*/
+;
+
+EFI_STATUS
+QncS3InitPcieRootPortDownstream (
+  IN EFI_HANDLE ImageHandle,
+  IN VOID       *Context
+  );
+
+VOID
+EFIAPI
+QncS3BootEvent (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  );
+
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf
new file mode 100644
index 0000000000..0e12a2c594
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf
@@ -0,0 +1,64 @@
+## @file
+#    Component description file for Qnc Initialization driver
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = QncS3Support
+  FILE_GUID                      = C7EA9787-CA0A-43b4-B1E5-25EF87391F8D
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = QncS3SupportEntryPoint
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  QncS3Support.h
+  QncS3Support.c
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  IoLib
+  DebugLib
+  DxeServicesLib
+  BaseMemoryLib
+  UefiDriverEntryPoint
+  PeCoffLib
+  LockBoxLib
+  S3BootScriptLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+  CacheMaintenanceLib
+  IntelQNCLib
+
+[Protocols]
+  gEfiQncS3SupportProtocolGuid     ## PRODUCES
+  gEfiLoadPeImageProtocolGuid      ## CONSUMES
+  gEfiFirmwareVolume2ProtocolGuid  ## CONSUMES
+
+[Guids]
+  gQncS3CodeInLockBoxGuid
+  gQncS3ContextInLockBoxGuid
+  gEfiEndOfDxeEventGroupGuid
+
+[Pcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxSize
+
+[Depex]
+  gEfiFirmwareVolume2ProtocolGuid AND
+  gEfiVariableArchProtocolGuid AND
+  gEfiVariableWriteArchProtocolGuid
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf
new file mode 100644
index 0000000000..405e9eb7fd
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf
@@ -0,0 +1,49 @@
+## @file
+# Component description file for SmmAccess module
+#
+# Copyright (c) 2013-2019 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SmmAccess
+  FILE_GUID                      = 274F0C8F-9E57-41d8-9966-29CCD48D31C2
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = SmmAccessDriverEntryPoint
+
+[Sources]
+  SmmAccessDriver.h
+  SmmAccessDriver.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  IntelFrameworkPkg/IntelFrameworkPkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  HobLib
+  DebugLib
+  UefiLib
+  BaseLib
+  BaseMemoryLib
+  S3BootScriptLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  DxeServicesTableLib
+  PcdLib
+  SmmLib
+
+[Protocols]
+  gEfiPciRootBridgeIoProtocolGuid
+  gEfiSmmAccess2ProtocolGuid
+
+[Guids]
+  gEfiSmmPeiSmramMemoryReserveGuid
+
+[Depex]
+  gEfiPciRootBridgeIoProtocolGuid
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c
new file mode 100644
index 0000000000..830f8b83c3
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c
@@ -0,0 +1,405 @@
+/** @file
+This is the driver that publishes the SMM Access Protocol
+instance for the Tylersburg chipset.
+
+Copyright (c) 2013-2019 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SmmAccessDriver.h"
+
+
+
+SMM_ACCESS_PRIVATE_DATA  mSmmAccess;
+
+VOID
+SmmAccessOnBoot (
+  IN EFI_EVENT                          Event,
+  IN VOID                               *Context
+);
+
+EFI_STATUS
+EFIAPI
+SmmAccessDriverEntryPoint (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+/*++
+
+Routine Description:
+
+  Installs an SMM Access Protocol.
+
+Arguments:
+
+  ImageHandle  -  Handle for the image of this driver.
+  SystemTable  -  Pointer to the EFI System Table.
+
+Returns:
+
+  EFI_SUCCESS     -  Protocol successfully started and installed.
+  EFI_UNSUPPORTED -  Protocol can't be started.
+  EFI_NOT_FOUND   -  Protocol not found.
+--*/
+{
+
+  EFI_STATUS                      Status;
+  EFI_EVENT                       BootEvent;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+  UINTN                           Index;
+  EFI_SMRAM_HOB_DESCRIPTOR_BLOCK  *DescriptorBlock;
+  EFI_HOB_GUID_TYPE               *GuidHob;
+
+
+  //
+  // Initialize private data
+  //
+  ZeroMem (&mSmmAccess, sizeof (mSmmAccess));
+
+  Status = gBS->LocateProtocol (
+                  &gEfiPciRootBridgeIoProtocolGuid,
+                  NULL,
+                  (VOID **) &PciRootBridgeIo
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Build SMM related information
+  //
+  mSmmAccess.Signature        = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;
+  mSmmAccess.Handle           = NULL;
+  mSmmAccess.PciRootBridgeIo  = PciRootBridgeIo;
+
+  //
+  // Get Hob list
+  //
+  GuidHob    = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
+  DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
+  ASSERT (DescriptorBlock);
+
+
+  //
+  // Get CPU Max bus number
+  //
+  mSmmAccess.MaxBusNumber         = PCI_BUS_NUMBER_QNC;
+  for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {
+    mSmmAccess.SocketPopulated[Index] = TRUE;
+  }
+
+  //
+  // Use the hob to publish SMRAM capabilities
+  //
+  ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);
+  for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {
+    mSmmAccess.SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;
+    mSmmAccess.SmramDesc[Index].CpuStart      = DescriptorBlock->Descriptor[Index].CpuStart;
+    mSmmAccess.SmramDesc[Index].PhysicalSize  = DescriptorBlock->Descriptor[Index].PhysicalSize;
+    mSmmAccess.SmramDesc[Index].RegionState   = DescriptorBlock->Descriptor[Index].RegionState;
+    DEBUG ((EFI_D_INFO, "SM RAM index[%d] startaddr:%08X Size :%08X\n", Index, mSmmAccess.SmramDesc[Index].CpuStart,
+      mSmmAccess.SmramDesc[Index].PhysicalSize));
+  }
+
+  mSmmAccess.NumberRegions              = Index;
+  mSmmAccess.SmmAccess.Open             = Open;
+  mSmmAccess.SmmAccess.Close            = Close;
+  mSmmAccess.SmmAccess.Lock             = Lock;
+  mSmmAccess.SmmAccess.GetCapabilities  = GetCapabilities;
+  mSmmAccess.SmmAccess.LockState        = FALSE;
+  mSmmAccess.SmmAccess.OpenState        = FALSE;
+  mSmmAccess.SMMRegionState             = EFI_SMRAM_CLOSED;
+
+  //
+  // Install our protocol interfaces on the device's handle
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                &mSmmAccess.Handle,
+                &gEfiSmmAccess2ProtocolGuid,
+                &mSmmAccess.SmmAccess,
+                NULL
+                );
+  ASSERT_EFI_ERROR (Status);
+
+  DEBUG ((EFI_D_INFO, "SMM  Base: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalStart)));
+  DEBUG ((EFI_D_INFO, "SMM  Size: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize)));
+
+  mSmmAccess.TsegSize = (UINT8)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize);
+  //
+  // T Seg setting done in QPI RC
+  //
+
+  //
+  // Prior ReadyToBoot, lock CSEG
+  //
+  Status = EfiCreateEventReadyToBootEx(
+           TPL_NOTIFY,
+           SmmAccessOnBoot,
+           NULL,
+           &BootEvent );
+  ASSERT (!EFI_ERROR (Status));
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Open (
+  IN EFI_SMM_ACCESS2_PROTOCOL    *This
+  )
+/*++
+
+Routine Description:
+
+  This routine accepts a request to "open" a region of SMRAM.  The
+  region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
+  The use of "open" means that the memory is visible from all boot-service
+  and SMM agents.
+
+Arguments:
+
+  This             -  Pointer to the SMM Access Interface.
+  DescriptorIndex  -  Region of SMRAM to Open.
+
+Returns:
+
+  EFI_SUCCESS            -  The region was successfully opened.
+  EFI_DEVICE_ERROR       -  The region could not be opened because locked by
+                            chipset.
+  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
+
+--*/
+{
+  SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+
+  SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+  if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {
+    DEBUG ((EFI_D_ERROR, "Cannot open a locked SMRAM region\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Open TSEG
+  //
+  if (!QNCOpenSmramRegion ()) {
+    mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
+    return EFI_DEVICE_ERROR;
+  }
+
+  mSmmAccess.SMMRegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+  SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EFI_ALLOCATED)));
+  mSmmAccess.SMMRegionState |= EFI_SMRAM_OPEN;
+  SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN);
+  SmmAccess->SmmAccess.OpenState = TRUE;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Close (
+  IN EFI_SMM_ACCESS2_PROTOCOL *This
+  )
+/*++
+
+Routine Description:
+
+  This routine accepts a request to "close" a region of SMRAM.  This is valid for
+  compatible SMRAM region.
+
+Arguments:
+
+  This             -  Pointer to the SMM Access Interface.
+  DescriptorIndex  -  Region of SMRAM to Close.
+
+Returns:
+
+  EFI_SUCCESS            -  The region was successfully closed.
+  EFI_DEVICE_ERROR       -  The region could not be closed because locked by
+                            chipset.
+  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
+
+--*/
+{
+  EFI_STATUS              Status;
+  SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+  BOOLEAN                 OpenState;
+  UINTN                   Index;
+
+  SmmAccess     = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+  if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {
+    //
+    // Cannot close a "locked" region
+    //
+    DEBUG ((EFI_D_WARN, "Cannot close the locked SMRAM Region\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (mSmmAccess.SMMRegionState & EFI_SMRAM_CLOSED) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Reset SMRAM cacheability to UC
+  //
+  for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {
+    DEBUG ((DEBUG_INFO, "SmmAccess->Close: Set to UC Base=%016lx  Size=%016lx\n", SmmAccess->SmramDesc[Index].CpuStart, SmmAccess->SmramDesc[Index].PhysicalSize));
+    Status = gDS->SetMemorySpaceAttributes(
+                    SmmAccess->SmramDesc[Index].CpuStart,
+                    SmmAccess->SmramDesc[Index].PhysicalSize,
+                    EFI_MEMORY_UC
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "SmmAccess: Failed to reset SMRAM window to EFI_MEMORY_UC\n"));
+    }
+  }
+
+  //
+  // Close TSEG
+  //
+  if (!QNCCloseSmramRegion ()) {
+    mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
+    return EFI_DEVICE_ERROR;
+  }
+
+  mSmmAccess.SMMRegionState &= ~EFI_SMRAM_OPEN;
+  SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN));
+  mSmmAccess.SMMRegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+  SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+
+  //
+  // Find out if any regions are still open
+  //
+  OpenState = FALSE;
+  for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {
+    if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {
+      OpenState = TRUE;
+    }
+  }
+
+  SmmAccess->SmmAccess.OpenState = OpenState;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Lock (
+  IN EFI_SMM_ACCESS2_PROTOCOL   *This
+  )
+/*++
+
+Routine Description:
+
+  This routine accepts a request to "lock" SMRAM.  The
+  region could be legacy AB or TSEG near top of physical memory.
+  The use of "lock" means that the memory can no longer be opened
+  to BS state..
+
+Arguments:
+
+  This             -  Pointer to the SMM Access Interface.
+  DescriptorIndex  -  Region of SMRAM to Lock.
+
+Returns:
+
+  EFI_SUCCESS            -  The region was successfully locked.
+  EFI_DEVICE_ERROR       -  The region could not be locked because at least
+                            one range is still open.
+  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
+
+--*/
+{
+  SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+
+  SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+  if (SmmAccess->SmmAccess.OpenState) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
+  SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED);
+  SmmAccess->SmmAccess.LockState                     = TRUE;
+
+  //
+  // Lock TSEG
+  //
+  QNCLockSmramRegion ();
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+GetCapabilities (
+  IN CONST  EFI_SMM_ACCESS2_PROTOCOL *This,
+  IN OUT UINTN                       *SmramMapSize,
+  IN OUT EFI_SMRAM_DESCRIPTOR        *SmramMap
+  )
+/*++
+
+Routine Description:
+
+  This routine services a user request to discover the SMRAM
+  capabilities of this platform.  This will report the possible
+  ranges that are possible for SMRAM access, based upon the
+  memory controller capabilities.
+
+Arguments:
+
+  This          -  Pointer to the SMRAM Access Interface.
+  SmramMapSize  -  Pointer to the variable containing size of the
+                   buffer to contain the description information.
+  SmramMap      -  Buffer containing the data describing the Smram
+                   region descriptors.
+Returns:
+
+  EFI_BUFFER_TOO_SMALL  -  The user did not provide a sufficient buffer.
+  EFI_SUCCESS           -  The user provided a sufficiently-sized buffer.
+
+--*/
+{
+  EFI_STATUS                Status;
+  SMM_ACCESS_PRIVATE_DATA  *SmmAccess;
+  UINTN                     BufferSize;
+
+  SmmAccess           = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+  BufferSize          = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);
+
+  if (*SmramMapSize < BufferSize) {
+    Status = EFI_BUFFER_TOO_SMALL;
+  } else {
+    CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);
+    Status = EFI_SUCCESS;
+  }
+  *SmramMapSize = BufferSize;
+
+  return Status;
+}
+
+VOID
+SmmAccessOnBoot (
+  IN EFI_EVENT                          Event,
+  IN VOID                               *Context
+)
+{
+
+}
+VOID
+SyncRegionState2SmramDesc(
+  IN BOOLEAN  OrAnd,
+  IN UINT64   Value
+  )
+{
+  UINT32 Index;
+
+  for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {
+    if (OrAnd) {
+      mSmmAccess.SmramDesc[Index].RegionState |= Value;
+    } else {
+      mSmmAccess.SmramDesc[Index].RegionState &= Value;
+    }
+  }
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h
new file mode 100644
index 0000000000..aca169d3e2
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h
@@ -0,0 +1,230 @@
+/** @file
+Header file for SMM Access Driver.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2019 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _SMM_ACCESS_DRIVER_H
+#define _SMM_ACCESS_DRIVER_H
+
+#include <PiDxe.h>
+#include <IndustryStandard/Pci.h>
+
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Driver Consumed Protocol Prototypes
+//
+#include <Protocol/PciRootBridgeIo.h>
+
+//
+// Driver Consumed GUID Prototypes
+//
+#include <Guid/SmramMemoryReserve.h>
+
+//
+// Driver produced protocol
+//
+#include <Protocol/SmmAccess2.h>
+
+#include <Library/QNCSmmLib.h>
+#include <QNCAccess.h>
+
+#define MAX_CPU_SOCKET      1
+#define MAX_SMRAM_RANGES    4
+
+//
+// Private data structure
+//
+#define  SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a')
+
+typedef struct {
+  UINTN                            Signature;
+  EFI_HANDLE                       Handle;
+  EFI_SMM_ACCESS2_PROTOCOL          SmmAccess;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo;
+  UINTN                            NumberRegions;
+  EFI_SMRAM_DESCRIPTOR             SmramDesc[MAX_SMRAM_RANGES];
+  UINT8                            TsegSize;
+  UINT8                            MaxBusNumber;
+  UINT8                            SocketPopulated[MAX_CPU_SOCKET];
+  UINT64                           SMMRegionState;
+  UINT8                            ActualNLIioBusNumber;
+} SMM_ACCESS_PRIVATE_DATA;
+
+
+#define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \
+  CR ( \
+  a, \
+  SMM_ACCESS_PRIVATE_DATA, \
+  SmmAccess, \
+  SMM_ACCESS_PRIVATE_DATA_SIGNATURE \
+  )
+
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+EFI_STATUS
+EFIAPI
+SmmAccessDriverEntryPoint (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+/*++
+
+Routine Description:
+
+  This is the standard EFI driver point that detects
+  whether there is an proper chipset in the system
+  and if so, installs an SMM Access Protocol.
+
+Arguments:
+
+  ImageHandle  -  Handle for the image of this driver.
+  SystemTable  -  Pointer to the EFI System Table.
+
+Returns:
+
+  EFI_SUCCESS      -  Protocol successfully started and installed.
+  EFI_UNSUPPORTED  -  Protocol can't be started.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+Open (
+  IN EFI_SMM_ACCESS2_PROTOCOL *This
+  )
+/*++
+
+Routine Description:
+
+  This routine accepts a request to "open" a region of SMRAM.  The
+  region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
+  The use of "open" means that the memory is visible from all boot-service
+  and SMM agents.
+
+Arguments:
+
+  This             -  Pointer to the SMM Access Interface.
+  DescriptorIndex  -  Region of SMRAM to Open.
+
+Returns:
+
+  EFI_SUCCESS            -  The region was successfully opened.
+  EFI_DEVICE_ERROR       -  The region could not be opened because locked by
+                            chipset.
+  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+Close (
+  IN EFI_SMM_ACCESS2_PROTOCOL *This
+  )
+/*++
+
+Routine Description:
+
+  This routine accepts a request to "close" a region of SMRAM.  This is valid for
+  compatible SMRAM region.
+
+Arguments:
+
+  This             -  Pointer to the SMM Access Interface.
+  DescriptorIndex  -  Region of SMRAM to Close.
+
+Returns:
+
+  EFI_SUCCESS            -  The region was successfully closed.
+  EFI_DEVICE_ERROR       -  The region could not be closed because locked by
+                            chipset.
+  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+Lock (
+  IN EFI_SMM_ACCESS2_PROTOCOL *This
+  )
+/*++
+
+Routine Description:
+
+  This routine accepts a request to "lock" SMRAM.  The
+  region could be legacy AB or TSEG near top of physical memory.
+  The use of "lock" means that the memory can no longer be opened
+  to BS state..
+
+Arguments:
+
+  This             -  Pointer to the SMM Access Interface.
+  DescriptorIndex  -  Region of SMRAM to Lock.
+
+Returns:
+
+  EFI_SUCCESS            -  The region was successfully locked.
+  EFI_DEVICE_ERROR       -  The region could not be locked because at least
+                            one range is still open.
+  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+GetCapabilities (
+  IN CONST EFI_SMM_ACCESS2_PROTOCOL     *This,
+  IN OUT UINTN                   *SmramMapSize,
+  IN OUT EFI_SMRAM_DESCRIPTOR    *SmramMap
+  )
+/*++
+
+Routine Description:
+
+  This routine services a user request to discover the SMRAM
+  capabilities of this platform.  This will report the possible
+  ranges that are possible for SMRAM access, based upon the
+  memory controller capabilities.
+
+Arguments:
+
+  This          -  Pointer to the SMRAM Access Interface.
+  SmramMapSize  -  Pointer to the variable containing size of the
+                   buffer to contain the description information.
+  SmramMap      -  Buffer containing the data describing the Smram
+                   region descriptors.
+
+Returns:
+
+  EFI_BUFFER_TOO_SMALL  -  The user did not provide a sufficient buffer.
+  EFI_SUCCESS           -  The user provided a sufficiently-sized buffer.
+
+--*/
+;
+VOID
+SyncRegionState2SmramDesc(
+  IN BOOLEAN  OrAnd,
+  IN UINT64    Value
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
new file mode 100644
index 0000000000..a3e992848f
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
@@ -0,0 +1,358 @@
+/** @file
+This module produces the SMM COntrol2 Protocol for QNC
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/SmmControl2.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <IntelQNCDxe.h>
+#include <Library/QNCAccessLib.h>
+#include <Uefi/UefiBaseType.h>
+
+#define EFI_INTERNAL_POINTER  0x00000004
+
+extern EFI_GUID gEfiEventVirtualAddressChangeGuid;
+
+/**
+  Generates an SMI using the parameters passed in.
+
+  @param  This                A pointer to an instance of
+                              EFI_SMM_CONTROL2_PROTOCOL
+  @param  ArgumentBuffer      The argument buffer
+  @param  ArgumentBufferSize  The size of the argument buffer
+  @param  Periodic            TRUE to indicate a periodical SMI
+  @param  ActivationInterval  Interval of the periodical SMI
+
+  @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
+  @return Return value from SmmTrigger().
+
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL     *This,
+  IN OUT  UINT8                          *CommandPort       OPTIONAL,
+  IN OUT  UINT8                          *DataPort          OPTIONAL,
+  IN      BOOLEAN                        Periodic           OPTIONAL,
+  IN      EFI_SMM_PERIOD                 ActivationInterval OPTIONAL
+                  );
+
+/**
+  Clears an SMI.
+
+  @param  This      Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL
+  @param  Periodic  TRUE to indicate a periodical SMI
+
+  @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+  IN CONST     EFI_SMM_CONTROL2_PROTOCOL  *This,
+  IN      BOOLEAN                         Periodic OPTIONAL
+  );
+
+///
+/// Handle for the SMM Control2 Protocol
+///
+EFI_HANDLE  mSmmControl2Handle = NULL;
+
+///
+/// SMM COntrol2 Protocol instance
+///
+EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {
+  Activate,
+  Deactivate,
+  0
+};
+
+VOID
+EFIAPI
+SmmControlVirtualddressChangeEvent (
+  IN EFI_EVENT                  Event,
+  IN VOID                       *Context
+  )
+/*++
+
+Routine Description:
+
+  Fixup internal data pointers so that the services can be called in virtual mode.
+
+Arguments:
+
+  Event                         The event registered.
+  Context                       Event context.
+
+Returns:
+
+  None.
+
+--*/
+{
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Trigger));
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Clear));
+}
+
+/**
+  Clear SMI related chipset status and re-enable SMI by setting the EOS bit.
+
+  @retval EFI_SUCCESS The requested operation has been carried out successfully
+  @retval EFI_DEVICE_ERROR  The EOS bit could not be set.
+
+**/
+EFI_STATUS
+SmmClear (
+  VOID
+  )
+{
+  UINT16                       GPE0BLK_Base;
+
+  //
+  // Get GPE0BLK_Base
+  //
+  GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+  //
+  // Clear the Power Button Override Status Bit, it gates EOS from being set.
+  // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.
+  //
+
+  //
+  // Clear the APM SMI Status Bit
+  //
+  IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
+
+  //
+  // Set the EOS Bit
+  //
+  IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Generates an SMI using the parameters passed in.
+
+  @param  This                A pointer to an instance of
+                              EFI_SMM_CONTROL_PROTOCOL
+  @param  ArgumentBuffer      The argument buffer
+  @param  ArgumentBufferSize  The size of the argument buffer
+  @param  Periodic            TRUE to indicate a periodical SMI
+  @param  ActivationInterval  Interval of the periodical SMI
+
+  @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
+  @retval EFI_SUCCESS            SMI generated
+
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL     *This,
+  IN OUT  UINT8                          *CommandPort       OPTIONAL,
+  IN OUT  UINT8                          *DataPort          OPTIONAL,
+  IN      BOOLEAN                        Periodic           OPTIONAL,
+  IN      EFI_SMM_PERIOD                 ActivationInterval OPTIONAL
+  )
+{
+  UINT16        GPE0BLK_Base;
+  UINT32        NewValue;
+
+  //
+  // Get GPE0BLK_Base
+  //
+  GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+  if (Periodic) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Clear any pending the APM SMI
+  //
+  if (EFI_ERROR (SmmClear())) {
+    return EFI_DEVICE_ERROR;
+    }
+
+  //
+  // Enable the APMC SMI
+  //
+  IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);
+
+  //
+  // Enable SMI globally
+  //
+  NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+  NewValue |= SMI_EN;
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+
+  //
+  // Set APMC_STS
+  //
+  if (DataPort == NULL) {
+    IoWrite8 (PcdGet16 (PcdSmmDataPort), 0xFF);
+  } else {
+    IoWrite8 (PcdGet16 (PcdSmmDataPort), *DataPort);
+  }
+
+  //
+  // Generate the APMC SMI
+  //
+  if (CommandPort == NULL) {
+    IoWrite8 (PcdGet16 (PcdSmmActivationPort), 0xFF);
+  } else {
+    IoWrite8 (PcdGet16 (PcdSmmActivationPort), *CommandPort);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Clears an SMI.
+
+  @param  This      Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL
+  @param  Periodic  TRUE to indicate a periodical SMI
+
+  @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL     *This,
+  IN      BOOLEAN                   Periodic
+  )
+{
+  if (Periodic) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return SmmClear();
+}
+
+/**
+  This is the constructor for the SMM Control protocol.
+
+  This function installs EFI_SMM_CONTROL2_PROTOCOL.
+
+  @param  ImageHandle Handle for the image of this driver
+  @param  SystemTable Pointer to the EFI System Table
+
+  @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
+  @return The status returned from InstallProtocolInterface().
+
+--*/
+EFI_STATUS
+SmmControl2Init (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   Event;
+  UINT16      PM1BLK_Base;
+  UINT16      GPE0BLK_Base;
+  BOOLEAN     SciEn;
+  UINT32      NewValue;
+
+  //
+  // Get PM1BLK_Base & GPE0BLK_Base
+  //
+  PM1BLK_Base  = PcdGet16 (PcdPm1blkIoBaseAddress);
+  GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+  //
+  // Install our protocol interfaces on the device's handle
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mSmmControl2Handle,
+                  &gEfiSmmControl2ProtocolGuid,  &mSmmControl2,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Determine whether an ACPI OS is present (via the SCI_EN bit)
+  //
+  SciEn = (BOOLEAN)((IoRead16 (PM1BLK_Base + R_QNC_PM1BLK_PM1C) & B_QNC_PM1BLK_PM1C_SCIEN) != 0);
+  if (!SciEn) {
+    //
+    // Clear any SMIs that double as SCIs (when SCI_EN==0)
+    //
+    IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1S), B_QNC_PM1BLK_PM1S_ALL);
+    IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1E), 0x00000000);
+    IoWrite32 ((PM1BLK_Base + R_QNC_PM1BLK_PM1C),  0x00000000);
+    IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0S), B_QNC_GPE0BLK_GPE0S_ALL);
+    IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0E), 0x00000000);
+  }
+
+  //
+  // Clear and disable all SMIs that are unaffected by SCI_EN
+  // Set EOS
+  //
+  IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), 0x00000000);
+  IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), (B_QNC_GPE0BLK_SMIS_EOS + B_QNC_GPE0BLK_SMIS_ALL));
+
+  //
+  // Enable SMI globally
+  //
+  NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+  NewValue |= SMI_EN;
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+  //
+  // Make sure to write this register last -- EOS re-enables SMIs for the QNC
+  //
+  IoAndThenOr32 (
+    GPE0BLK_Base + R_QNC_GPE0BLK_SMIE,
+    (UINT32)(~B_QNC_GPE0BLK_SMIE_ALL),
+    B_QNC_GPE0BLK_SMIE_APM
+    );
+
+  //
+  // Make sure EOS bit cleared
+  //
+  DEBUG_CODE_BEGIN ();
+  if (IoRead32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS) & B_QNC_GPE0BLK_SMIS_EOS) {
+    DEBUG ((
+      EFI_D_ERROR,
+      "******************************************************************************\n"
+      "BIG ERROR: SmmControl constructor couldn't properly initialize the ACPI table.\n"
+      "           SmmControl->Clear will probably hang.                              \n"
+      "              NOTE: SCI_EN = %d                                               \n"
+      "******************************************************************************\n",
+      SciEn
+      ));
+
+    //
+    // If we want the system to stop, then keep the ASSERT(FALSE).
+    // Otherwise, comment it out.
+    //
+    ASSERT (FALSE);
+  }
+  DEBUG_CODE_END ();
+
+  Status = gBS->CreateEventEx (
+                EVT_NOTIFY_SIGNAL,
+                TPL_NOTIFY,
+                SmmControlVirtualddressChangeEvent,
+                NULL,
+                &gEfiEventVirtualAddressChangeGuid,
+                &Event
+                );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf
new file mode 100644
index 0000000000..1367f0a1f4
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf
@@ -0,0 +1,55 @@
+## @file
+# QNC SmmControl driver to install EFI_SMM_CONTROL_PROTOCOL.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SmmControlDxe
+  FILE_GUID                      = A03A9429-C570-4ef9-9E00-C7A673976E5F
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = SmmControl2Init
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  SmmControlDriver.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+  PcdLib
+  IoLib
+  PciLib
+  QNCAccessLib
+
+[Protocols]
+  gEfiSmmControl2ProtocolGuid             # PROTOCOL ALWAYS_PRODUCED
+
+[Pcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid
+
+[Depex]
+  TRUE
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h
new file mode 100644
index 0000000000..c8bead8081
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h
@@ -0,0 +1,45 @@
+/** @file
+Common header file shared by all source files.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __COMMON_HEADER_H_
+#define __COMMON_HEADER_H_
+
+
+
+#include <PiSmm.h>
+#include <IntelQNCDxe.h>
+
+#include <Protocol/SmmUsbDispatch2.h>
+#include <Protocol/SmmPeriodicTimerDispatch2.h>
+#include <Protocol/SmmIchnDispatch2.h>
+#include <Protocol/SmmPowerButtonDispatch2.h>
+#include <Protocol/SmmGpiDispatch2.h>
+#include <Protocol/SmmSxDispatch2.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/SmmIoTrapDispatch2.h>
+#include <Protocol/SmmCpu.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/S3IoLib.h>
+#include <Library/QNCAccessLib.h>
+
+#include <Uefi/UefiBaseType.h>
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c
new file mode 100644
index 0000000000..98c9c0690c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c
@@ -0,0 +1,32 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC = {
+  QNC_SMM_NO_FLAGS,
+  {
+    {
+      {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_GPIO
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_GPIO
+  }
+  }
+};
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
new file mode 100644
index 0000000000..5d01c9ef3d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
@@ -0,0 +1,549 @@
+/** @file
+
+This driver is responsible for the registration of child drivers
+and the abstraction of the QNC SMI sources.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+//
+// Help handle porting bit shifts to IA-64.
+//
+#define BIT_ZERO 0x00000001
+
+
+VOID
+QNCSmmPublishDispatchProtocols(
+  VOID
+  )
+{
+  UINTN      Index;
+  EFI_STATUS Status;
+
+  //
+  // Install protocol interfaces.
+  //
+  for (Index = 0; Index < NUM_PROTOCOLS; Index++) {
+    Status = gSmst->SmmInstallProtocolInterface (
+                 &mPrivateData.InstallMultProtHandle,
+                      mPrivateData.Protocols[Index].Guid,
+                      EFI_NATIVE_INTERFACE,
+                      &mPrivateData.Protocols[Index].Protocols.Generic
+                 );
+
+  ASSERT_EFI_ERROR (Status);
+}
+}
+
+EFI_STATUS
+QNCSmmInitHardware(
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Initialize bits that aren't necessarily related to an SMI source.
+
+Dependencies:
+
+  gSmst - SMM System Table; contains an entry for SMM CPU IO
+
+Returns:
+
+  EFI_SUCCESS.  Asserts, otherwise.
+
+--*/
+{
+  EFI_STATUS Status;
+
+  //
+  // Clear all SMIs
+  //
+  QNCSmmClearSmi();
+
+  Status = QNCSmmEnableGlobalSmiBit ();
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Be *really* sure to clear all SMIs
+  //
+  QNCSmmClearSmi ();
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+QNCSmmEnableGlobalSmiBit (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Enables the QNC to generate SMIs. Note that no SMIs will be generated
+  if no SMI sources are enabled. Conversely, no enabled SMI source will
+  generate SMIs if SMIs are not globally enabled. This is the main
+  switchbox for SMI generation.
+
+Arguments:
+
+  None
+
+Returns:
+
+  EFI_SUCCESS.
+  Asserts, otherwise.
+
+--*/
+{
+  UINT32        NewValue;
+
+  //
+  // Enable SMI globally
+  //
+  NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+  NewValue |= SMI_EN;
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+QNCSmmClearSmi(
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Clears the SMI after all SMI source have been processed.
+  Note that this function will not work correctly (as it is
+  written) unless all SMI sources have been processed.
+  A revision of this function could manually clear all SMI
+  status bits to guarantee success.
+
+Returns:
+
+  EFI_SUCCESS.
+  Asserts, otherwise.
+
+--*/
+{
+  BOOLEAN EosSet;
+  BOOLEAN SciEn;
+
+  UINT32 Pm1Cnt = 0;
+  UINT16 Pm1Sts = 0;
+  UINT32 Gpe0Sts = 0;
+  UINT32 SmiSts  = 0;
+
+  //
+  // Determine whether an ACPI OS is present (via the SCI_EN bit)
+  //
+  Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+  SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
+
+  if (SciEn == FALSE) {
+
+    //
+    // Clear any SMIs that double as SCIs (when SCI_EN==0)
+    //
+    Pm1Sts = (B_QNC_PM1BLK_PM1S_WAKE | B_QNC_PM1BLK_PM1S_PCIEWSTS | B_QNC_PM1BLK_PM1S_RTC | B_QNC_PM1BLK_PM1S_GLOB | B_QNC_PM1BLK_PM1S_TO);
+
+    Gpe0Sts = B_QNC_GPE0BLK_GPE0S_ALL;
+
+    IoOr16((PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S), Pm1Sts);
+    IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S), Gpe0Sts);
+  }
+
+  //
+  // Clear all SMIs that are unaffected by SCI_EN
+  //
+  SmiSts = IoRead32((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
+  SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;
+  IoWrite32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), SmiSts);
+
+  //
+  // Try to clear the EOS bit. ASSERT on an error
+  //
+  EosSet = QNCSmmSetAndCheckEos();
+  ASSERT (EosSet);
+
+  return EFI_SUCCESS;
+}
+
+BOOLEAN
+QNCSmmSetAndCheckEos(
+  VOID
+  )
+{
+  //
+  // Reset the QNC to generate subsequent SMIs
+  //
+  IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
+    return TRUE;
+}
+
+BOOLEAN
+QNCSmmGetSciEn(
+  )
+{
+  BOOLEAN SciEn;
+  UINT32 Pm1Cnt;
+
+  //
+  // Determine whether an ACPI OS is present (via the SCI_EN bit)
+  //
+  Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+
+  SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
+
+  return SciEn;
+}
+
+//
+// These may or may not need to change w/ the QNC version; they're highly IA-32 dependent, though.
+//
+
+BOOLEAN
+ReadBitDesc (
+  CONST QNC_SMM_BIT_DESC  *BitDesc
+  )
+{
+  UINT64           Register;
+  UINT32           PciBus;
+  UINT32           PciDev;
+  UINT32           PciFun;
+  UINT32           PciReg;
+  BOOLEAN          BitWasOne;
+
+  ASSERT (BitDesc != NULL );
+  ASSERT (!IS_BIT_DESC_NULL( *BitDesc ) );
+
+  Register  = 0;
+  BitWasOne = FALSE;
+
+  switch (BitDesc->Reg.Type) {
+
+  case ACPI_ADDR_TYPE:
+    //
+    // Double check that we correctly read in the acpi base address
+    //
+    ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1) );
+
+    switch (BitDesc->SizeInBytes) {
+
+    case 0:
+      //
+      // Chances are that this field didn't get initialized.
+      // Check your assignments to bit descriptions.
+      //
+      ASSERT (FALSE );
+      break;
+
+      case 1:
+      Register = (UINT64) IoRead8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
+        break;
+
+      case 2:
+      Register = (UINT64) IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
+        break;
+
+      case 4:
+      Register = (UINT64) IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
+        break;
+
+      default:
+        //
+        // Unsupported or invalid register size
+        //
+        ASSERT (FALSE );
+        break;
+      };
+
+    if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
+        BitWasOne = TRUE;
+      } else {
+        BitWasOne = FALSE;
+      }
+    break;
+
+  case GPE_ADDR_TYPE:
+      //
+    // Double check that we correctly read in the gpe base address
+      //
+    ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1) );
+
+    switch (BitDesc->SizeInBytes) {
+
+    case 0:
+      //
+      // Chances are that this field didn't get initialized.
+      // Check your assignments to bit descriptions.
+      //
+      ASSERT (FALSE );
+      break;
+
+    case 1:
+      Register = (UINT64) IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
+      break;
+
+    case 2:
+      Register = (UINT64) IoRead16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
+      break;
+
+    case 4:
+      Register = (UINT64) IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
+      break;
+
+    default:
+      //
+      // Unsupported or invalid register size
+      //
+      ASSERT (FALSE );
+      break;
+    };
+
+    if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
+        BitWasOne = TRUE;
+      } else {
+        BitWasOne = FALSE;
+      }
+    break;
+
+  case MEMORY_MAPPED_IO_ADDRESS_TYPE:
+    //
+    // Read the register, and it with the bit to read
+    //
+
+    //
+    // This code does not support reads greater then 64 bits
+    //
+    ASSERT (BitDesc->SizeInBytes <= 8);
+    CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
+    Register &= LShiftU64 (BIT0, BitDesc->Bit);
+    if (Register) {
+      BitWasOne = TRUE;
+    } else {
+      BitWasOne = FALSE;
+    }
+    break;
+
+  case PCI_ADDR_TYPE:
+    PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
+    PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
+    PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
+    PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
+    switch (BitDesc->SizeInBytes) {
+
+    case 0:
+      //
+      // Chances are that this field didn't get initialized.
+      // Check your assignments to bit descriptions.
+      ASSERT (FALSE );
+      break;
+
+    case 1:
+      Register = (UINT64) PciRead8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
+      break;
+
+    case 2:
+      Register = (UINT64) PciRead16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
+      break;
+
+    case 4:
+      Register = (UINT64) PciRead32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
+      break;
+
+    default:
+      //
+      // Unsupported or invalid register size
+      //
+      ASSERT (FALSE );
+      break;
+    };
+
+    if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
+        BitWasOne = TRUE;
+    } else {
+      BitWasOne = FALSE;
+    }
+    break;
+
+  default:
+    //
+    // This address type is not yet implemented
+    //
+    ASSERT (FALSE );
+    break;
+  };
+
+  return BitWasOne;
+}
+
+VOID
+WriteBitDesc (
+  CONST QNC_SMM_BIT_DESC   *BitDesc,
+  CONST BOOLEAN           ValueToWrite
+  )
+{
+  UINT64           Register;
+  UINT64           AndVal;
+  UINT64           OrVal;
+  UINT32           PciBus;
+  UINT32           PciDev;
+  UINT32           PciFun;
+  UINT32           PciReg;
+
+  ASSERT (BitDesc != NULL);
+  ASSERT (!IS_BIT_DESC_NULL(*BitDesc));
+
+  AndVal = ~(BIT_ZERO << (BitDesc->Bit));
+  OrVal  = ((UINT32)ValueToWrite) << (BitDesc->Bit);
+
+  switch (BitDesc->Reg.Type) {
+
+  case ACPI_ADDR_TYPE:
+    //
+    // Double check that we correctly read in the acpi base address
+    //
+    ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1));
+
+    switch (BitDesc->SizeInBytes) {
+
+    case 0:
+      //
+      // Chances are that this field didn't get initialized.
+      // Check your assignments to bit descriptions.
+      //
+      ASSERT (FALSE );
+      break;
+
+    case 1:
+      IoAndThenOr8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT8)AndVal, (UINT8)OrVal);
+      break;
+
+    case 2:
+      IoAndThenOr16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT16)AndVal, (UINT16)OrVal);
+      break;
+
+    case 4:
+      IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT32)AndVal, (UINT32)OrVal);
+      break;
+
+    default:
+      //
+      // Unsupported or invalid register size
+      //
+      ASSERT (FALSE );
+      break;
+    };
+    break;
+
+  case GPE_ADDR_TYPE:
+    //
+    // Double check that we correctly read in the gpe base address
+    //
+    ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1));
+
+    switch (BitDesc->SizeInBytes) {
+
+    case 0:
+      //
+      // Chances are that this field didn't get initialized.
+      // Check your assignments to bit descriptions.
+      //
+      ASSERT (FALSE );
+      break;
+
+    case 1:
+      IoAndThenOr8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT8)AndVal, (UINT8)OrVal);
+      break;
+
+    case 2:
+      IoAndThenOr16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT16)AndVal, (UINT16)OrVal);
+      break;
+
+    case 4:
+      IoAndThenOr32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT32)AndVal, (UINT32)OrVal);
+      break;
+
+    default:
+      //
+      // Unsupported or invalid register size
+      //
+      ASSERT (FALSE );
+      break;
+    };
+      break;
+
+  case MEMORY_MAPPED_IO_ADDRESS_TYPE:
+    //
+    // Read the register, or it with the bit to set, then write it back.
+    //
+
+    //
+    // This code does not support writes greater then 64 bits
+    //
+    ASSERT (BitDesc->SizeInBytes <= 8);
+    CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
+    Register &= AndVal;
+    Register |= OrVal;
+    CopyMem (BitDesc->Reg.Data.Mmio, &Register, BitDesc->SizeInBytes);
+    break;
+
+  case PCI_ADDR_TYPE:
+    PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
+    PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
+    PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
+    PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
+    switch (BitDesc->SizeInBytes) {
+
+    case 0:
+      //
+      // Chances are that this field didn't get initialized -- check your assignments
+      // to bit descriptions.
+      //
+      ASSERT (FALSE );
+      break;
+
+    case 1:
+      PciAndThenOr8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal);
+      break;
+
+    case 2:
+      PciAndThenOr16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal);
+      break;
+
+    case 4:
+      PciAndThenOr32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal);
+      break;
+
+    default:
+      //
+      // Unsupported or invalid register size
+      //
+      ASSERT (FALSE );
+      break;
+    };
+    break;
+
+    default:
+    //
+    // This address type is not yet implemented
+    //
+    ASSERT (FALSE );
+    break;
+  };
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c
new file mode 100644
index 0000000000..b0825bde9d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c
@@ -0,0 +1,424 @@
+/** @file
+File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+typedef enum {
+  PERIODIC_TIMER = 0,
+  NUM_TIMERS
+} SUPPORTED_TIMER;
+
+typedef struct _TIMER_INTERVAL
+{
+  UINT64    Interval;
+  UINT8     AssociatedTimer;
+} TIMER_INTERVAL;
+
+//
+// Time constants, in 100 nano-second units
+//
+#define TIME_64s   640000000 /* 64   s  */
+#define TIME_32s   320000000 /* 32   s  */
+#define TIME_16s   160000000 /* 16   s  */
+#define TIME_8s     80000000 /*  8   s  */
+#define TIME_64ms     640000 /* 64   ms */
+#define TIME_32ms     320000 /* 32   ms */
+#define TIME_16ms     160000 /* 16   ms */
+#define TIME_1_5ms     15000 /*  1.5 ms */
+
+// PMCW (GPE+28h) [2:0] Periodic SMI Rate selection
+// 000 1.5ms
+// 001 16ms
+// 010 32ms
+// 011 64ms
+// 100 8s
+// 101 16s
+// 110 32s
+// 111 64s
+
+typedef enum {
+  INDEX_TIME_1_5ms = 0,
+  INDEX_TIME_16ms,
+  INDEX_TIME_32ms,
+  INDEX_TIME_64ms,
+  INDEX_TIME_8s,
+  INDEX_TIME_16s,
+  INDEX_TIME_32s,
+  INDEX_TIME_64s,
+  INDEX_TIME_MAX
+} TIMER_INTERVAL_INDEX;
+
+TIMER_INTERVAL mSmmPeriodicTimerIntervals[INDEX_TIME_MAX] = {
+  {TIME_1_5ms, PERIODIC_TIMER},
+  {TIME_16ms,  PERIODIC_TIMER},
+  {TIME_32ms,  PERIODIC_TIMER},
+  {TIME_64ms,  PERIODIC_TIMER},
+  { TIME_8s,    PERIODIC_TIMER },
+  {TIME_16s,   PERIODIC_TIMER},
+  {TIME_32s,   PERIODIC_TIMER},
+  {TIME_64s,   PERIODIC_TIMER}
+};
+
+typedef struct _TIMER_INFO {
+  UINTN     NumChildren;      // number of children using this timer
+  UINT64    MinReqInterval;   // minimum interval required by children
+  UINTN     CurrentSetting;   // interval this timer is set at right now (index into interval table)
+} TIMER_INFO;
+
+TIMER_INFO  mTimers[NUM_TIMERS];
+
+QNC_SMM_SOURCE_DESC mTIMER_SOURCE_DESCS[NUM_TIMERS] = {
+  {
+    QNC_SMM_NO_FLAGS,
+    {
+      {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SWT},
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SWT}
+    }
+  }
+};
+
+VOID
+QNCSmmPeriodicTimerProgramTimers(
+  VOID
+  );
+
+
+TIMER_INTERVAL *
+ContextToTimerInterval (
+  IN  QNC_SMM_CONTEXT     *RegisterContext
+  )
+{
+  UINTN loopvar;
+
+  //
+  // Determine which timer this child is using
+  //
+  for (loopvar = 0; loopvar < INDEX_TIME_MAX; loopvar++) {
+    if (((RegisterContext->PeriodicTimer.SmiTickInterval == 0) && (RegisterContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) ||
+        (RegisterContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)
+       ) {
+        return &mSmmPeriodicTimerIntervals[loopvar];
+      }
+  }
+
+  //
+  // If this assertion fires, then either:
+  //    (1) the context contains an invalid interval
+  //    (2) the timer interval table is corrupt
+  //
+  // ASSERT (FALSE);
+
+  return NULL;
+}
+
+EFI_STATUS
+MapPeriodicTimerToSrcDesc (
+  IN  QNC_SMM_CONTEXT             *RegisterContext,
+  OUT QNC_SMM_SOURCE_DESC         *SrcDesc
+  )
+{
+  TIMER_INTERVAL  *TimerInterval;
+
+  //
+  // Figure out which timer the child is requesting and
+  // send back the source description
+  //
+  TimerInterval = ContextToTimerInterval (RegisterContext);
+  if (TimerInterval == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  CopyMem (SrcDesc, &mTIMER_SOURCE_DESCS[TimerInterval->AssociatedTimer], sizeof (QNC_SMM_SOURCE_DESC));;
+
+  //
+  // Program the value of the interval into hardware
+  //
+  QNCSmmPeriodicTimerProgramTimers ();
+
+  return EFI_SUCCESS;
+}
+
+VOID
+PeriodicTimerGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT QNC_SMM_CONTEXT    *HwContext
+  )
+{
+  TIMER_INTERVAL    *TimerInterval;
+
+  ASSERT (Record->ProtocolType == PeriodicTimerType);
+
+  TimerInterval = ContextToTimerInterval (&Record->ChildContext);
+
+  if (TimerInterval != NULL) {
+    //
+    // Ignore the hardware context. It's not required for this protocol.
+    // Instead, just increment the child's context.
+    // Update the elapsed time w/ the data from our tables
+    //
+    Record->CommBuffer.PeriodicTimer.ElapsedTime += TimerInterval->Interval;
+    CopyMem (HwContext, &Record->ChildContext, sizeof (QNC_SMM_CONTEXT));
+  }
+}
+
+BOOLEAN
+PeriodicTimerCmpContext (
+  IN QNC_SMM_CONTEXT     *HwContext,
+  IN QNC_SMM_CONTEXT     *ChildContext
+  )
+{
+  DATABASE_RECORD    *Record;
+
+  Record = DATABASE_RECORD_FROM_CONTEXT (ChildContext);
+
+  if (Record->CommBuffer.PeriodicTimer.ElapsedTime >= ChildContext->PeriodicTimer.Period) {
+    //
+    // This child should be dispatched
+    // The timer will be restarted on the "ClearSource" call.
+    //
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+VOID
+PeriodicTimerGetBuffer (
+  IN  DATABASE_RECORD     * Record
+  )
+{
+  //
+  // CommBuffer has been updated by PeriodicTimerGetContext, so return directly
+  //
+  return;
+}
+
+VOID
+QNCSmmPeriodicTimerProgramTimers (
+  VOID
+  )
+{
+  UINT32            GpePmcwValue;
+  SUPPORTED_TIMER   Timer;
+  DATABASE_RECORD   *RecordInDb;
+  LIST_ENTRY        *LinkInDb;
+  TIMER_INTERVAL    *TimerInterval;
+
+  //
+  // Find the minimum required interval for each timer
+  //
+  for (Timer = (SUPPORTED_TIMER)0; Timer < NUM_TIMERS; Timer++) {
+    mTimers[Timer].MinReqInterval = ~(UINT64)0x0;
+    mTimers[Timer].NumChildren = 0;
+  }
+  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+    if (RecordInDb->ProtocolType == PeriodicTimerType) {
+      //
+      // This child is registerd with the PeriodicTimer protocol
+      //
+      TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);
+
+      if(TimerInterval != NULL) {
+        Timer = (SUPPORTED_TIMER)((TIMER_INTERVAL *) (TimerInterval))->AssociatedTimer;
+
+        ASSERT (Timer >= 0 && Timer < NUM_TIMERS);
+
+        if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) {
+          mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval;
+        }
+        mTimers[Timer].NumChildren++;
+      }
+    }
+    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+  }
+
+  //
+  // Program the hardware
+  //
+  GpePmcwValue = 0;
+  if (mTimers[PERIODIC_TIMER].NumChildren > 0) {
+    switch (mTimers[PERIODIC_TIMER].MinReqInterval) {
+
+    case TIME_64s:
+      GpePmcwValue = INDEX_TIME_64s;
+      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;
+      break;
+
+    case TIME_32s:
+      GpePmcwValue = INDEX_TIME_32s;
+      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;
+      break;
+
+    case TIME_16s:
+      GpePmcwValue = INDEX_TIME_16s;
+      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;
+      break;
+
+    case TIME_8s:
+      GpePmcwValue = INDEX_TIME_8s;
+      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;
+      break;
+
+    case TIME_64ms:
+      GpePmcwValue = INDEX_TIME_64ms;
+      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64ms;
+      break;
+
+    case TIME_32ms:
+      GpePmcwValue = INDEX_TIME_32ms;
+      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32ms;
+      break;
+
+    case TIME_16ms:
+      GpePmcwValue = INDEX_TIME_16ms;
+      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16ms;
+      break;
+
+    case TIME_1_5ms:
+      GpePmcwValue = INDEX_TIME_1_5ms;
+      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_1_5ms;
+      break;
+
+    default:
+      ASSERT (FALSE);
+      break;
+    };
+
+    GpePmcwValue |= B_QNC_GPE0BLK_PMCW_PSE;
+
+    IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMCW), GpePmcwValue);
+
+    //
+    // Restart the timer here, just need to clear the SMI
+    //
+    QNCSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
+  } else {
+    QNCSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
+  }
+}
+
+EFI_STATUS
+QNCSmmPeriodicTimerDispatchGetNextShorterInterval (
+  IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL  *This,
+  IN OUT   UINT64                                    **SmiTickInterval
+  )
+/*++
+
+Routine Description:
+
+  This services returns the next SMI tick period that is supported by the chipset.
+  The order returned is from longest to shortest interval period.
+
+Arguments:
+
+  This              - Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.
+  SmiTickInterval   - Pointer to pointer of the next shorter SMI interval period that is supported by the child.
+
+Returns:
+
+  EFI_SUCCESS              - The service returned successfully.
+  EFI_INVALID_PARAMETER   - The parameter SmiTickInterval is invalid.
+
+--*/
+{
+  TIMER_INTERVAL    *IntervalPointer;
+
+  ASSERT (SmiTickInterval != NULL);
+
+  IntervalPointer = (TIMER_INTERVAL*)*SmiTickInterval;
+
+  if (IntervalPointer == NULL) {
+    //
+    // The first time child requesting an interval
+    //
+    IntervalPointer = &mSmmPeriodicTimerIntervals[0];
+  } else if (IntervalPointer == &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1]) {
+    //
+    // At end of the list
+    //
+    IntervalPointer = NULL;
+  } else {
+    if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) &&
+        (IntervalPointer < &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1])) {
+      //
+      // Get the next interval in the list
+      //
+      IntervalPointer++;
+    } else {
+      //
+      // Input is out of range
+      //
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  if (IntervalPointer != NULL) {
+  *SmiTickInterval = &IntervalPointer->Interval;
+  } else {
+    *SmiTickInterval = NULL;
+  }
+
+  return EFI_SUCCESS;
+}
+
+VOID
+QNCSmmPeriodicTimerClearSource (
+  IN QNC_SMM_SOURCE_DESC     *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  This function is responsible for calculating and enabling any timers that are required
+  to dispatch messages to children. The SrcDesc argument isn't acutally used.
+
+Arguments:
+
+  SrcDesc - Pointer to the QNC_SMM_SOURCE_DESC instance.
+
+Returns:
+
+  None.
+
+--*/
+{
+  DATABASE_RECORD   *RecordInDb;
+  LIST_ENTRY        *LinkInDb;
+
+  QNCSmmPeriodicTimerProgramTimers ();
+
+  //
+  // Reset Elapsed time
+  //
+  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+    if (RecordInDb->ProtocolType == PeriodicTimerType) {
+      //
+      // This child is registerd with the PeriodicTimer protocol and Callback
+      // has been invoked, so reset the ElapsedTime to 0
+      //
+      if (RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime >= RecordInDb->ChildContext.PeriodicTimer.Period) {
+        RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime = 0;
+      }
+    }
+    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+  }
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c
new file mode 100644
index 0000000000..2ce0499975
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c
@@ -0,0 +1,211 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm QNCn dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES] = {
+
+  // QNCnMch (0)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnPme (1)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnRtcAlarm (2)
+  {
+    QNC_SMM_NO_FLAGS,
+    {
+      {{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1E}}, S_QNC_PM1BLK_PM1E, N_QNC_PM1BLK_PM1E_RTC},
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1S}}, S_QNC_PM1BLK_PM1S, N_QNC_PM1BLK_PM1S_RTC}
+    }
+  },
+
+  // QNCnRingIndicate (3)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnAc97Wake (4)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnSerialIrq (5)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnY2KRollover (6)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnTcoTimeout (7)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnOsTco (8)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnNmi (9)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnIntruderDetect (10)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnBiosWp (11)
+  {
+    QNC_SMM_CLEAR_WITH_ZERO,
+    {
+      {
+        {
+          PCI_ADDR_TYPE,
+          {
+            (
+              (PCI_BUS_NUMBER_QNC << 24) |
+              (PCI_DEVICE_NUMBER_QNC_LPC << 16) |
+              (PCI_FUNCTION_NUMBER_QNC_LPC << 8) |
+              R_QNC_LPC_BIOS_CNTL
+            )
+          }
+        },
+        S_QNC_LPC_BIOS_CNTL,
+        N_QNC_LPC_BIOS_CNTL_BLE
+      },
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {
+        {
+          PCI_ADDR_TYPE,
+          {
+            (
+              (PCI_BUS_NUMBER_QNC << 24) |
+              (PCI_DEVICE_NUMBER_QNC_LPC << 16) |
+              (PCI_FUNCTION_NUMBER_QNC_LPC << 8) |
+              R_QNC_LPC_BIOS_CNTL
+            )
+          }
+        },
+        S_QNC_LPC_BIOS_CNTL,
+        N_QNC_LPC_BIOS_CNTL_BIOSWE
+      }
+    }
+  },
+
+  // QNCnMcSmi (12)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnPmeB0 (13)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnThrmSts (14)
+  {
+    QNC_SMM_SCI_EN_DEPENDENT,
+    {
+      {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0E}}, S_QNC_GPE0BLK_GPE0E, N_QNC_GPE0BLK_GPE0E_THRM},
+      NULL_BIT_DESC_INITIALIZER
+    },
+    {
+      {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0S}}, S_QNC_GPE0BLK_GPE0S, N_QNC_GPE0BLK_GPE0S_THRM}
+    }
+  },
+
+  // QNCnSmBus (15)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnIntelUsb2 (16)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnMonSmi7 (17)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnMonSmi6 (18)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnMonSmi5 (19)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnMonSmi4 (20)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap13 (21)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap12 (22)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap11 (23)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap10 (24)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap9 (25)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap8 (26)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap7 (27)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap6 (28)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap5 (29)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap3 (30)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap2 (31)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap1 (32)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnDevTrap0 (33)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnIoTrap3 (34)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnIoTrap2 (35)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnIoTrap1 (36)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnIoTrap0 (37)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnPciExpress (38)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnMonitor (39)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnSpi (40)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnQRT (41)
+  NULL_SOURCE_DESC_INITIALIZER,
+
+  // QNCnGpioUnlock (42)
+  NULL_SOURCE_DESC_INITIALIZER
+};
+
+VOID
+QNCSmmQNCnClearSource(
+  QNC_SMM_SOURCE_DESC   *SrcDesc
+  )
+{
+    QNCSmmClearSource (SrcDesc);
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c
new file mode 100644
index 0000000000..c820df8067
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c
@@ -0,0 +1,90 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm Sw dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+EFI_SMM_CPU_PROTOCOL  *mSmmCpu = NULL;
+
+CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC = {
+  QNC_SMM_NO_FLAGS,
+  {
+    {
+      {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_APM
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_APM
+    }
+  }
+};
+
+VOID
+SwGetContext(
+  IN  DATABASE_RECORD    *Record,
+  OUT QNC_SMM_CONTEXT    *Context
+  )
+{
+  Context->Sw.SwSmiInputValue = IoRead8 (R_APM_CNT);
+}
+
+BOOLEAN
+SwCmpContext (
+  IN QNC_SMM_CONTEXT     *Context1,
+  IN QNC_SMM_CONTEXT     *Context2
+  )
+{
+  return (BOOLEAN)( Context1->Sw.SwSmiInputValue == Context2->Sw.SwSmiInputValue );
+}
+
+VOID
+SwGetBuffer (
+  IN  DATABASE_RECORD     * Record
+  )
+{
+  EFI_STATUS                 Status;
+  UINTN                      Index;
+  UINTN                      CpuIndex;
+  EFI_SMM_SAVE_STATE_IO_INFO IoState;
+
+  //
+  // Locate SMM CPU protocol to retrieve the CPU save state
+  //
+  if (mSmmCpu == NULL) {
+    Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  //
+  // Find the CPU which generated the software SMI
+  //
+  CpuIndex = 0;
+  for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
+    Status = mSmmCpu->ReadSaveState (
+                        mSmmCpu,
+                        sizeof (EFI_SMM_SAVE_STATE_IO_INFO),
+                        EFI_SMM_SAVE_STATE_REGISTER_IO,
+                        Index,
+                        &IoState
+                        );
+    if (!EFI_ERROR (Status) && (IoState.IoPort == R_APM_CNT)) {
+      CpuIndex = Index;
+      break;
+    }
+  }
+
+  Record->CommBuffer.Sw.SwSmiCpuIndex = CpuIndex;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c
new file mode 100644
index 0000000000..6381a2c598
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c
@@ -0,0 +1,147 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm Sx dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC = {
+  QNC_SMM_NO_FLAGS,
+  {
+    {
+      {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SLP
+    },
+    NULL_BIT_DESC_INITIALIZER
+  },
+  {
+    {
+      {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SLP
+    }
+  }
+};
+
+VOID
+SxGetContext(
+  IN  DATABASE_RECORD    *Record,
+  OUT QNC_SMM_CONTEXT    *Context
+  )
+{
+  UINT32        Pm1Cnt;
+
+  Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+
+  //
+  // By design, the context phase will always be ENTRY
+  //
+  Context->Sx.Phase = SxEntry;
+
+  //
+  // Map the PM1_CNT register's SLP_TYP bits to the context type
+  //
+  switch (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) {
+
+  case V_S0:
+    Context->Sx.Type = SxS0;
+    break;
+
+  case V_S3:
+    Context->Sx.Type = SxS3;
+    break;
+
+  case V_S4:
+    Context->Sx.Type = SxS4;
+    break;
+
+  case V_S5:
+    Context->Sx.Type = SxS5;
+    break;
+
+  default:
+    ASSERT (FALSE);
+    break;
+  };
+}
+
+BOOLEAN
+SxCmpContext (
+  IN QNC_SMM_CONTEXT     *Context1,
+  IN QNC_SMM_CONTEXT     *Context2
+  )
+{
+  return (BOOLEAN)(Context1->Sx.Type == Context2->Sx.Type);
+}
+
+VOID
+QNCSmmSxGoToSleep(
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  When we get an SMI that indicates that we are transitioning to a sleep state,
+  we need to actually transition to that state.  We do this by disabling the
+  "SMI on sleep enable" feature, which generates an SMI when the operating system
+  tries to put the system to sleep, and then physically putting the system to sleep.
+
+Returns:
+
+  None.
+
+--*/
+{
+  UINT32        Pm1Cnt;
+
+  //
+  // Flush cache into memory before we go to sleep. It is necessary for S3 sleep
+  // because we may update memory in SMM Sx sleep handlers -- the updates are in cache now
+  //
+  AsmWbinvd();
+
+  //
+  // Disable SMIs
+  //
+  QNCSmmClearSource (&SX_SOURCE_DESC );
+  QNCSmmDisableSource (&SX_SOURCE_DESC);
+
+  //
+  // Clear Sleep Type Enable
+  //
+  IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIE, (UINT16)(~B_QNC_GPE0BLK_SMIE_SLP));
+
+  // clear sleep SMI status
+  IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, (UINT16)(S_QNC_GPE0BLK_SMIS));
+
+  //
+  // Now that SMIs are disabled, write to the SLP_EN bit again to trigger the sleep
+  //
+  Pm1Cnt = IoOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, B_QNC_PM1BLK_PM1C_SLPEN);
+
+  //
+  // The system just went to sleep. If the sleep state was S1, then code execution will resume
+  // here when the system wakes up.
+  //
+  Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+  if ((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == 0) {
+    //
+    // An ACPI OS isn't present, clear the sleep information
+    //
+    Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SLPTP;
+    Pm1Cnt |= V_S0;
+
+    IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Pm1Cnt);
+  }
+
+  QNCSmmClearSource (&SX_SOURCE_DESC);
+  QNCSmmEnableSource (&SX_SOURCE_DESC);
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h
new file mode 100644
index 0000000000..ae3529f679
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h
@@ -0,0 +1,868 @@
+/** @file
+Prototypes and defines for the QNC SMM Dispatcher.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef QNC_SMM_H
+#define QNC_SMM_H
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmRegisters.h"
+
+extern EFI_HANDLE  mQNCSmmDispatcherImageHandle;
+
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SUPPORTED PROTOCOLS
+//
+
+//
+// Define an enumeration for all the supported protocols
+//
+typedef enum {
+  // UsbType,    DELETE:on QuarkNcSocId, there is no usb smi supported
+  SxType,
+  SwType,
+  GpiType,
+  QNCnType,
+  PowerButtonType,
+  PeriodicTimerType,
+  NUM_PROTOCOLS
+} QNC_SMM_PROTOCOL_TYPE;
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SPECIFYING A REGISTER
+// We want a general way of referring to addresses.  For this case, we'll only
+// need addresses in the ACPI table (and the TCO entries within the ACPI table).
+// However, it's interesting to consider what it would take to support other types
+// of addresses.  To address Will's concern, I think it prudent to accommodate it
+// early on in the design.
+//
+// Addresses we need to consider:
+//
+//  Type:                           Required:
+//  I/O                             Yes
+//    ACPI (special case of I/O)    Only if we want to
+//    TCO  (special case of ACPI)   Only if we want to
+//  Memory (or Memory Mapped I/O)   Only if we want to
+//  PCI                             Yes, for BiosWp
+//
+typedef enum {
+  //
+  //  IO_ADDR_TYPE, // unimplemented
+  //
+  ACPI_ADDR_TYPE,
+  GPE_ADDR_TYPE,
+  //
+  //  MEMORY_ADDR_TYPE, // unimplemented
+  //
+  MEMORY_MAPPED_IO_ADDRESS_TYPE,
+  PCI_ADDR_TYPE,
+  NUM_ADDR_TYPES,                     // count of items in this enum
+  QNC_SMM_ADDR_TYPE_NULL        = -1  // sentinel to indicate NULL or to signal end of arrays
+} ADDR_TYPE;
+
+//
+// Assumption: 32-bits -- enum's evaluate to integer
+// Assumption: This code will only run on IA-32.  Justification: IA-64 doesn't have SMIs.
+// We don't have to worry about 64-bit addresses.
+// Typedef the size of addresses in case the numbers I'm using are wrong or in case
+// this changes.  This is a good idea because PCI_ADDR will change, for example, when
+// we add support for PciExpress.
+//
+typedef UINT16 IO_ADDR;
+typedef IO_ADDR ACPI_ADDR;  // can omit
+typedef IO_ADDR GPE_ADDR;  // can omit
+typedef IO_ADDR TCO_ADDR;   // can omit
+typedef VOID *MEM_ADDR;
+typedef MEM_ADDR MEMORY_MAPPED_IO_ADDRESS;
+typedef union {
+  UINT32  Raw;
+  struct {
+    UINT8 Reg;
+    UINT8 Fnc;
+    UINT8 Dev;
+    UINT8 Bus;
+  } Fields;
+} PCI_ADDR;
+
+typedef struct {
+  ADDR_TYPE Type;
+  union {
+    //
+    // used to initialize during declaration/definition
+    //
+    UINTN                     raw;
+
+    //
+    // used to access useful data
+    //
+    IO_ADDR                   io;
+    ACPI_ADDR                 acpi;
+    GPE_ADDR                  gpe;
+    TCO_ADDR                  tco;
+    MEM_ADDR                  mem;
+    MEMORY_MAPPED_IO_ADDRESS  Mmio;
+    PCI_ADDR                  pci;
+
+  } Data;
+
+} QNC_SMM_ADDRESS;
+//
+// Assumption: total size is 64 bits (32 for type and 32 for data) or 8 bytes
+//
+#define EFI_PCI_ADDRESS_PORT  0xcf8
+#define EFI_PCI_DATA_PORT     0xcfc
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SPECIFYING BITS WITHIN A REGISTER
+// Here's a struct that helps us specify a source or enable bit.
+//
+typedef struct {
+  QNC_SMM_ADDRESS Reg;
+  UINT8           SizeInBytes;  // of the register
+  UINT8           Bit;
+} QNC_SMM_BIT_DESC;
+
+//
+// Sometimes, we'll have bit descriptions that are unused.  It'd be great to have a
+// way to easily identify them:
+//
+#define IS_BIT_DESC_NULL(BitDesc)   ((BitDesc).Reg.Type == QNC_SMM_ADDR_TYPE_NULL)  // "returns" true when BitDesc is NULL
+#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = QNC_SMM_ADDR_TYPE_NULL)   // will "return" an integer w/ value of 0
+#define NULL_BIT_DESC_INITIALIZER \
+  { \
+    { \
+      QNC_SMM_ADDR_TYPE_NULL, \
+      { \
+        0 \
+      } \
+    }, \
+    0, 0 \
+  }
+//
+// I'd like a type to specify the callback's Sts & En bits because they'll
+// be commonly used together:
+//
+#define NUM_EN_BITS   2
+#define NUM_STS_BITS  1
+
+//
+// Flags
+//
+typedef UINT8 QNC_SMM_SOURCE_FLAGS;
+
+//
+// Flags required today
+//
+#define QNC_SMM_NO_FLAGS               0
+#define QNC_SMM_SCI_EN_DEPENDENT      (BIT0)
+#define QNC_SMM_CLEAR_WITH_ZERO       (BIT6)
+
+//
+// Flags that might be required tomorrow
+// #define QNC_SMM_CLEAR_WITH_ONE 2 // may need to support bits that clear by writing 0
+// #define QNC_SMM_MULTIBIT_FIELD 3 // may need to support status/enable fields 2 bits wide
+//
+typedef struct {
+  QNC_SMM_SOURCE_FLAGS  Flags;
+  QNC_SMM_BIT_DESC      En[NUM_EN_BITS];
+  QNC_SMM_BIT_DESC      Sts[NUM_STS_BITS];
+} QNC_SMM_SOURCE_DESC;
+//
+// 31 bytes, I think
+//
+#define NULL_SOURCE_DESC_INITIALIZER \
+  { \
+    QNC_SMM_NO_FLAGS, \
+    { \
+      NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \
+    }, \
+    { \
+      NULL_BIT_DESC_INITIALIZER \
+    } \
+  }
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// CHILD CONTEXTS
+// To keep consistent w/ the architecture, we'll need to provide the context
+// to the child when we call its callback function.  After talking with Will,
+// we agreed that we'll need functions to "dig" the context out of the hardware
+// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those
+// contexts to prevent unnecessary dispatches.  I'd like a general type for these
+// "GetContext" functions, so I'll need a union of all the protocol contexts for
+// our internal use:
+//
+typedef union {
+  //
+  // (in no particular order)
+  //
+  EFI_SMM_ICHN_REGISTER_CONTEXT           QNCn;
+  EFI_SMM_SX_REGISTER_CONTEXT             Sx;
+  EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer;
+  EFI_SMM_SW_REGISTER_CONTEXT             Sw;
+  EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT   PowerButton;
+  // EFI_SMM_USB_REGISTER_CONTEXT            Usb; DELETE:on QuarkNcSocId, there is no usb smi supported
+  EFI_SMM_GPI_REGISTER_CONTEXT            Gpi;
+} QNC_SMM_CONTEXT;
+
+typedef union {
+  //
+  // (in no particular order)
+  //
+  EFI_SMM_SW_CONTEXT                      Sw;
+  EFI_SMM_PERIODIC_TIMER_CONTEXT          PeriodicTimer;
+} QNC_SMM_BUFFER;
+
+//
+// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes
+//
+typedef struct _DATABASE_RECORD DATABASE_RECORD;
+
+typedef
+VOID
+(EFIAPI *GET_CONTEXT) (
+  IN  DATABASE_RECORD    * Record,
+  OUT QNC_SMM_CONTEXT    * Context
+  );
+//
+// Assumption: the GET_CONTEXT function will be as small and simple as possible.
+// Assumption: We don't need to pass in an enumeration for the protocol because each
+//    GET_CONTEXT function is written for only one protocol.
+// We also need a function to compare contexts to see if the child should be dispatched
+//
+typedef
+BOOLEAN
+(EFIAPI *CMP_CONTEXT) (
+  IN QNC_SMM_CONTEXT     * Context1,
+  IN QNC_SMM_CONTEXT     * Context2
+  );
+
+/*
+    Returns: True when contexts are equivalent; False otherwise
+*/
+
+//
+// This function is used to get the content of CommBuffer that will be passed
+// to Callback function
+//
+typedef
+VOID
+(EFIAPI *GET_BUFFER) (
+  IN  DATABASE_RECORD     * Record
+  );
+
+//
+// Finally, every protocol will require a "Get Context", "Compare Context"
+// and "Get CommBuffer" call, so we may as well wrap that up in a table, too.
+//
+typedef struct {
+  GET_CONTEXT GetContext;
+  CMP_CONTEXT CmpContext;
+  GET_BUFFER  GetBuffer;
+} CONTEXT_FUNCTIONS;
+
+extern CONTEXT_FUNCTIONS          ContextFunctions[NUM_PROTOCOLS];
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// MAPPING CONTEXT TO BIT DESCRIPTIONS
+// I'd like to have a general approach to mapping contexts to bit descriptions.
+// Sometimes, we'll find that we can use table lookups or CONSTant assignments;
+// other times, we'll find that we'll need to use a function to perform the mapping.
+// If we define a macro to mask that process, we'll never have to change the code.
+// I don't know if this is desirable or not -- if it isn't, then we can get rid
+// of the macros and just use function calls or variable assignments.  Doesn't matter
+// to me.
+// Mapping complex contexts requires a function
+//
+// DELETE:on QuarkNcSocId, there is no usb smi supported
+//EFI_STATUS
+//EFIAPI
+//MapUsbToSrcDesc (
+//  IN  QNC_SMM_CONTEXT                                          *RegisterContext,
+//  OUT QNC_SMM_SOURCE_DESC                                      *SrcDesc
+//  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  RegisterContext - GC_TODO: add argument description
+  SrcDesc         - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+MapPeriodicTimerToSrcDesc (
+  IN  QNC_SMM_CONTEXT                                          *RegisterContext,
+  OUT QNC_SMM_SOURCE_DESC                                     *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  RegisterContext - GC_TODO: add argument description
+  SrcDesc         - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+//
+// Mapping simple contexts can be done by assignment or lookup table
+//
+extern CONST QNC_SMM_SOURCE_DESC  SW_SOURCE_DESC;
+extern CONST QNC_SMM_SOURCE_DESC  SX_SOURCE_DESC;
+
+//
+// With the changes we've made to the protocols, we can now use table
+// lookups for the following protocols:
+//
+extern CONST QNC_SMM_SOURCE_DESC  GPI_SOURCE_DESC;
+
+extern QNC_SMM_SOURCE_DESC        QNCN_SOURCE_DESCS[NUM_ICHN_TYPES];
+
+
+//
+// For QNCx, APMC is UINT8 port, so the MAX SWI Value is 0xFF.
+//
+#define MAXIMUM_SWI_VALUE   0xFF
+
+
+//
+// Open: Need to make sure this kind of type cast will actually work.
+//   May need an intermediate form w/ two VOID* arguments.  I'll figure
+//   that out when I start compiling.
+
+///////////////////////////////////////////////////////////////////////////////
+//
+typedef
+VOID
+(EFIAPI *QNC_SMM_CLEAR_SOURCE) (
+  QNC_SMM_SOURCE_DESC * SrcDesc
+  );
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// "DATABASE" RECORD
+// Linked list data structures
+//
+#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C')
+
+struct _DATABASE_RECORD {
+  UINT32                Signature;
+  LIST_ENTRY            Link;
+
+  BOOLEAN               Processed;
+
+  //
+  // Status and Enable bit description
+  //
+  QNC_SMM_SOURCE_DESC   SrcDesc;
+
+  //
+  // Callback function
+  //
+  EFI_SMM_HANDLER_ENTRY_POINT2      Callback;
+  QNC_SMM_CONTEXT                   ChildContext;
+  VOID                              *CallbackContext;
+  QNC_SMM_BUFFER                    CommBuffer;
+  UINTN                             BufferSize;
+
+  //
+  // Special handling hooks -- init them to NULL if unused/unneeded
+  //
+  QNC_SMM_CLEAR_SOURCE  ClearSource;  // needed for SWSMI timer
+  // Functions required to make callback code general
+  //
+  CONTEXT_FUNCTIONS     ContextFunctions;
+
+  //
+  // The protocol that this record dispatches
+  //
+  QNC_SMM_PROTOCOL_TYPE ProtocolType;
+
+};
+
+#define DATABASE_RECORD_FROM_LINK(_record)  CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE)
+#define DATABASE_RECORD_FROM_CONTEXT(_record)  CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE)
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// HOOKING INTO THE ARCHITECTURE
+//
+typedef
+EFI_STATUS
+(EFIAPI *QNC_SMM_GENERIC_REGISTER) (
+  IN  VOID                                    **This,
+  IN  VOID                                    *DispatchFunction,
+  IN  VOID                                    *RegisterContext,
+  OUT EFI_HANDLE                              * DispatchHandle
+  );
+typedef
+EFI_STATUS
+(EFIAPI *QNC_SMM_GENERIC_UNREGISTER) (
+  IN  VOID                                    **This,
+  IN  EFI_HANDLE                              DispatchHandle
+  );
+
+//
+// Define a memory "stamp" equivalent in size and function to most of the protocols
+//
+typedef struct {
+  QNC_SMM_GENERIC_REGISTER    Register;
+  QNC_SMM_GENERIC_UNREGISTER  Unregister;
+  UINTN                       Extra1;
+  UINTN                       Extra2; // may not need this one
+} QNC_SMM_GENERIC_PROTOCOL;
+
+EFI_STATUS
+QNCSmmCoreRegister (
+  IN  QNC_SMM_GENERIC_PROTOCOL                          *This,
+  IN  EFI_SMM_HANDLER_ENTRY_POINT2                      DispatchFunction,
+  IN  QNC_SMM_CONTEXT                                    *RegisterContext,
+  OUT EFI_HANDLE                                        *DispatchHandle
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  This              - GC_TODO: add argument description
+  DispatchFunction  - GC_TODO: add argument description
+  RegisterContext   - GC_TODO: add argument description
+  DispatchHandle    - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+EFI_STATUS
+QNCSmmCoreUnRegister (
+  IN  QNC_SMM_GENERIC_PROTOCOL                         *This,
+  IN EFI_HANDLE                                        DispatchHandle
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  This            - GC_TODO: add argument description
+  DispatchHandle  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+typedef union {
+  QNC_SMM_GENERIC_PROTOCOL                  Generic;
+
+  // EFI_SMM_USB_DISPATCH2_PROTOCOL             Usb;  DELETE:on QuarkNcSocId, there is no usb smi supported
+  EFI_SMM_SX_DISPATCH2_PROTOCOL              Sx;
+  EFI_SMM_SW_DISPATCH2_PROTOCOL              Sw;
+  EFI_SMM_GPI_DISPATCH2_PROTOCOL             Gpi;
+  EFI_SMM_ICHN_DISPATCH2_PROTOCOL            QNCn;
+  EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL    PowerButton;
+  EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL  PeriodicTimer;
+} QNC_SMM_PROTOCOL;
+
+//
+// Define a structure to help us identify the generic protocol
+//
+#define PROTOCOL_SIGNATURE  SIGNATURE_32 ('P', 'R', 'O', 'T')
+
+typedef struct {
+  UINTN                 Signature;
+
+  QNC_SMM_PROTOCOL_TYPE Type;
+  EFI_GUID              *Guid;
+  QNC_SMM_PROTOCOL      Protocols;
+} QNC_SMM_QUALIFIED_PROTOCOL;
+
+#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \
+  CR (_generic, \
+      QNC_SMM_QUALIFIED_PROTOCOL, \
+      Protocols, \
+      PROTOCOL_SIGNATURE \
+      )
+
+//
+// Create private data for the protocols that we'll publish
+//
+typedef struct {
+  LIST_ENTRY                  CallbackDataBase;
+  EFI_HANDLE                  SmiHandle;
+  EFI_HANDLE                  InstallMultProtHandle;
+  QNC_SMM_QUALIFIED_PROTOCOL  Protocols[NUM_PROTOCOLS];
+} PRIVATE_DATA;
+
+extern PRIVATE_DATA           mPrivateData;
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+//
+VOID
+EFIAPI
+SwGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT QNC_SMM_CONTEXT    *Context
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Record  - GC_TODO: add argument description
+  Context - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+EFIAPI
+SwCmpContext (
+  IN QNC_SMM_CONTEXT     *Context1,
+  IN QNC_SMM_CONTEXT     *Context2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Context1  - GC_TODO: add argument description
+  Context2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+SwGetBuffer (
+  IN  DATABASE_RECORD     * Record
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Record  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+EFIAPI
+SxGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT QNC_SMM_CONTEXT    *Context
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Record  - GC_TODO: add argument description
+  Context - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+EFIAPI
+SxCmpContext (
+  IN QNC_SMM_CONTEXT     *Context1,
+  IN QNC_SMM_CONTEXT     *Context2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Context1  - GC_TODO: add argument description
+  Context2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+EFIAPI
+PeriodicTimerGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT QNC_SMM_CONTEXT    *Context
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Record  - GC_TODO: add argument description
+  Context - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+EFIAPI
+PeriodicTimerCmpContext (
+  IN QNC_SMM_CONTEXT     *Context1,
+  IN QNC_SMM_CONTEXT     *Context2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Context1  - GC_TODO: add argument description
+  Context2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+PeriodicTimerGetBuffer (
+  IN  DATABASE_RECORD     * Record
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Record  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+EFIAPI
+PowerButtonGetContext (
+  IN  DATABASE_RECORD    *Record,
+  OUT QNC_SMM_CONTEXT     *Context
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Record  - GC_TODO: add argument description
+  Context - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+EFIAPI
+PowerButtonCmpContext (
+  IN QNC_SMM_CONTEXT     *Context1,
+  IN QNC_SMM_CONTEXT     *Context2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Context1  - GC_TODO: add argument description
+  Context2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+//
+VOID
+EFIAPI
+QNCSmmPeriodicTimerClearSource (
+  QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+QNCSmmPeriodicTimerDispatchGetNextShorterInterval (
+  IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL    *This,
+  IN OUT UINT64                                         **SmiTickInterval
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  This            - GC_TODO: add argument description
+  SmiTickInterval - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmSxGoToSleep (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  None
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+EFIAPI
+QNCSmmQNCnClearSource (
+  QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c
new file mode 100644
index 0000000000..6e6d48fe02
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c
@@ -0,0 +1,825 @@
+/** @file
+This driver is responsible for the registration of child drivers
+and the abstraction of the QNC SMI sources.
+
+Copyright (c) 2013-2017 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmm.h"
+#include "QNCSmmHelpers.h"
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// MODULE / GLOBAL DATA
+//
+// Module variables used by the both the main dispatcher and the source dispatchers
+// Declared in QNCSmmSources.h
+//
+UINT32                    mPciData;
+UINT32                    mPciAddress;
+
+PRIVATE_DATA              mPrivateData = {  // for the structure
+  {
+    NULL
+  },                                        // CallbackDataBase linked list head
+  NULL,                                     // Handler returned whan calling SmiHandlerRegister
+  NULL,                                     // EFI handle returned when calling InstallMultipleProtocolInterfaces
+  {                                         // protocol arrays
+    // elements within the array
+    //
+    {
+      PROTOCOL_SIGNATURE,
+      SxType,
+      &gEfiSmmSxDispatch2ProtocolGuid,
+      {
+        {
+          (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+          (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister
+        }
+      }
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      SwType,
+      &gEfiSmmSwDispatch2ProtocolGuid,
+      {
+        {
+          (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+          (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,
+          (UINTN) MAXIMUM_SWI_VALUE
+        }
+      }
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      GpiType,
+      &gEfiSmmGpiDispatch2ProtocolGuid,
+      {
+        {
+          (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+          (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,
+          (UINTN) 1
+        }
+      }
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      QNCnType,
+      &gEfiSmmIchnDispatch2ProtocolGuid,
+      {
+        {
+          (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+          (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister
+        }
+      }
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      PowerButtonType,
+      &gEfiSmmPowerButtonDispatch2ProtocolGuid,
+      {
+        {
+          (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+          (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister
+        }
+      }
+    },
+    {
+      PROTOCOL_SIGNATURE,
+      PeriodicTimerType,
+      &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,
+      {
+        {
+          (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+          (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,
+          (UINTN) QNCSmmPeriodicTimerDispatchGetNextShorterInterval
+        }
+      }
+    },
+  }
+};
+
+CONTEXT_FUNCTIONS         mContextFunctions[NUM_PROTOCOLS] = {
+  {
+    SxGetContext,
+    SxCmpContext,
+    NULL
+  },
+  {
+    SwGetContext,
+    SwCmpContext,
+    SwGetBuffer
+  },
+  {
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    PeriodicTimerGetContext,
+    PeriodicTimerCmpContext,
+    PeriodicTimerGetBuffer,
+  },
+};
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// PROTOTYPES
+//
+// Functions use only in this file
+//
+EFI_STATUS
+QNCSmmCoreDispatcher (
+  IN     EFI_HANDLE               DispatchHandle,
+  IN     CONST VOID               *Context,        OPTIONAL
+  IN OUT VOID                     *CommBuffer,     OPTIONAL
+  IN OUT UINTN                    *CommBufferSize  OPTIONAL
+  );
+
+
+UINTN
+DevicePathSize (
+  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath
+  );
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// FUNCTIONS
+//
+// Driver entry point
+//
+EFI_STATUS
+EFIAPI
+InitializeQNCSmmDispatcher (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+/*++
+
+Routine Description:
+
+  Initializes the QNC SMM Dispatcher
+
+Arguments:
+
+  ImageHandle   - Pointer to the loaded image protocol for this driver
+  SystemTable   - Pointer to the EFI System Table
+
+Returns:
+  Status        - EFI_SUCCESS
+
+--*/
+{
+  EFI_STATUS                Status;
+
+  QNCSmmPublishDispatchProtocols ();
+
+  //
+  // Register a callback function to handle subsequent SMIs.  This callback
+  // will be called by SmmCoreDispatcher.
+  //
+  Status = gSmst->SmiHandlerRegister (QNCSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Initialize Callback DataBase
+  //
+  InitializeListHead (&mPrivateData.CallbackDataBase);
+
+  //
+  // Enable SMIs on the QNC now that we have a callback
+  //
+  QNCSmmInitHardware ();
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SaveState (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Save Index registers to avoid corrupting the foreground environment
+
+Arguments:
+  None
+
+Returns:
+  Status - EFI_SUCCESS
+
+--*/
+{
+  mPciAddress = IoRead32 (EFI_PCI_ADDRESS_PORT);
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RestoreState (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Restore Index registers to avoid corrupting the foreground environment
+
+Arguments:
+  None
+
+Returns:
+  Status - EFI_SUCCESS
+
+--*/
+{
+  IoWrite32 (EFI_PCI_ADDRESS_PORT, mPciAddress);
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SmiInputValueDuplicateCheck (
+  UINTN           FedSwSmiInputValue
+  )
+/*++
+
+Routine Description:
+
+  Check the Fed SwSmiInputValue to see if there is a duplicated one in the database
+
+Arguments:
+  None
+
+Returns:
+  Status - EFI_SUCCESS, EFI_INVALID_PARAMETER
+
+--*/
+// GC_TODO:    FedSwSmiInputValue - add argument and description to function comment
+{
+
+  DATABASE_RECORD *RecordInDb;
+  LIST_ENTRY      *LinkInDb;
+
+  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+
+    if (RecordInDb->ProtocolType == SwType) {
+      if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) {
+        return EFI_INVALID_PARAMETER;
+      }
+    }
+
+    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+QNCSmmCoreRegister (
+  IN  QNC_SMM_GENERIC_PROTOCOL                          *This,
+  IN  EFI_SMM_HANDLER_ENTRY_POINT2                      DispatchFunction,
+  IN  QNC_SMM_CONTEXT                                    *RegisterContext,
+  OUT EFI_HANDLE                                        *DispatchHandle
+  )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+// GC_TODO:    This - add argument and description to function comment
+// GC_TODO:    DispatchFunction - add argument and description to function comment
+// GC_TODO:    RegisterContext - add argument and description to function comment
+// GC_TODO:    DispatchHandle - add argument and description to function comment
+// GC_TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
+// GC_TODO:    EFI_INVALID_PARAMETER - add return value to function comment
+// GC_TODO:    EFI_SUCCESS - add return value to function comment
+// GC_TODO:    EFI_INVALID_PARAMETER - add return value to function comment
+{
+  EFI_STATUS                  Status;
+  DATABASE_RECORD             *Record;
+  QNC_SMM_QUALIFIED_PROTOCOL  *Qualified;
+  INTN                        Index;
+
+  //
+  // Check for invalid parameter
+  //
+  if (This == NULL || RegisterContext == NULL || DispatchHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Create database record and add to database
+  //
+  Record = (DATABASE_RECORD *) AllocateZeroPool (sizeof (DATABASE_RECORD));
+  if (Record == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Gather information about the registration request
+  //
+  Record->Callback          = DispatchFunction;
+  Record->CallbackContext   = RegisterContext;
+  CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT));
+
+  Qualified                 = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
+
+  Record->ProtocolType      = Qualified->Type;
+
+  CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions));
+  //
+  // Perform linked list housekeeping
+  //
+  Record->Signature = DATABASE_RECORD_SIGNATURE;
+
+  switch (Qualified->Type) {
+  //
+  // By the end of this switch statement, we'll know the
+  // source description the child is registering for
+  //
+  case SxType:
+    //
+    // Check the validity of Context Type and Phase
+    //
+    if ((Record->ChildContext.Sx.Type < SxS0) ||
+        (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) ||
+        (Record->ChildContext.Sx.Phase < SxEntry) ||
+        (Record->ChildContext.Sx.Phase >= EfiMaximumPhase)
+        ) {
+      goto Error;
+    }
+
+    InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+    CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc));
+    //
+    // use default clear source function
+    //
+    break;
+
+  case SwType:
+    if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {
+      //
+      // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.
+      //
+      Status = EFI_NOT_FOUND;
+      for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {
+        Status = SmiInputValueDuplicateCheck (Index);
+        if (!EFI_ERROR (Status)) {
+          RegisterContext->Sw.SwSmiInputValue = Index;
+          break;
+        }
+      }
+      if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {
+        Status = gSmst->SmmFreePool (Record);
+        return EFI_OUT_OF_RESOURCES;
+      }
+      //
+      // Update ChildContext again as SwSmiInputValue has been changed
+      //
+      CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT));
+    }
+
+    //
+    // Check the validity of Context Value
+    //
+    if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) {
+      goto Error;
+    }
+
+    if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) {
+      goto Error;
+    }
+
+    InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+    CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc));
+    Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT);
+    //
+    // use default clear source function
+    //
+    break;
+
+  case GpiType:
+
+    InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+    CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc));
+    //
+    // use default clear source function
+    //
+    break;
+
+  case QNCnType:
+    //
+    // Check the validity of Context Type
+    //
+    if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) {
+      goto Error;
+    }
+
+    InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+    CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc));
+    Record->ClearSource = QNCSmmQNCnClearSource;
+    break;
+
+  case PeriodicTimerType:
+
+    Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc));
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+
+    InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+    Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);
+    Record->ClearSource = QNCSmmPeriodicTimerClearSource;
+    break;
+
+  default:
+    goto Error;
+    break;
+  };
+
+  if (Record->ClearSource == NULL) {
+    //
+    // Clear the SMI associated w/ the source using the default function
+    //
+    QNCSmmClearSource (&Record->SrcDesc);
+  } else {
+    //
+    // This source requires special handling to clear
+    //
+    Record->ClearSource (&Record->SrcDesc);
+  }
+
+  QNCSmmEnableSource (&Record->SrcDesc);
+
+  //
+  // Child's handle will be the address linked list link in the record
+  //
+  *DispatchHandle = (EFI_HANDLE) (&Record->Link);
+
+  return EFI_SUCCESS;
+
+Error:
+  FreePool (Record);
+  //
+  // DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status ));
+  //
+  return EFI_INVALID_PARAMETER;
+}
+
+EFI_STATUS
+QNCSmmCoreUnRegister (
+  IN QNC_SMM_GENERIC_PROTOCOL                         *This,
+  IN EFI_HANDLE                                        DispatchHandle
+  )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+// GC_TODO:    This - add argument and description to function comment
+// GC_TODO:    DispatchHandle - add argument and description to function comment
+// GC_TODO:    EFI_INVALID_PARAMETER - add return value to function comment
+// GC_TODO:    EFI_INVALID_PARAMETER - add return value to function comment
+// GC_TODO:    EFI_SUCCESS - add return value to function comment
+{
+  BOOLEAN         SafeToDisable;
+  DATABASE_RECORD *RecordToDelete;
+  DATABASE_RECORD *RecordInDb;
+  LIST_ENTRY      *LinkInDb;
+
+  if (DispatchHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+
+  RemoveEntryList (&RecordToDelete->Link);
+  RecordToDelete->Signature = 0;
+
+  //
+  // See if we can disable the source, reserved for future use since this might
+  //  not be the only criteria to disable
+  //
+  SafeToDisable = TRUE;
+  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+  while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+    if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) {
+      SafeToDisable = FALSE;
+      break;
+    }
+    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+  }
+  if (SafeToDisable) {
+    QNCSmmDisableSource( &RecordToDelete->SrcDesc );
+}
+
+  FreePool (RecordToDelete);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is the main entry point for an SMM handler dispatch
+  or communicate-based callback.
+
+  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
+  @param  RegisterContext Points to an optional handler context which was specified when the handler was registered.
+  @param  CommBuffer      A pointer to a collection of data in memory that will
+                          be conveyed from a non-SMM environment into an SMM environment.
+  @param  CommBufferSize  The size of the CommBuffer.
+
+  @return Status Code
+
+**/
+EFI_STATUS
+QNCSmmCoreDispatcher (
+  IN     EFI_HANDLE               DispatchHandle,
+  IN     CONST VOID               *RegisterContext,
+  IN OUT VOID                     *CommBuffer,
+  IN OUT UINTN                    *CommBufferSize
+  )
+{
+  //
+  // Used to prevent infinite loops
+  //
+  UINTN               EscapeCount;
+
+  BOOLEAN             ContextsMatch;
+  BOOLEAN             ResetListSearch;
+  BOOLEAN             EosSet;
+  BOOLEAN             SxChildWasDispatched;
+  BOOLEAN             ChildWasDispatched;
+
+  DATABASE_RECORD     *RecordInDb;
+  DATABASE_RECORD     ActiveRecordInDb;
+  LIST_ENTRY          *LinkInDb;
+  DATABASE_RECORD     *RecordToExhaust;
+  LIST_ENTRY          *LinkToExhaust;
+
+  QNC_SMM_CONTEXT     Context;
+  VOID                *CommunicationBuffer;
+  UINTN               BufferSize;
+
+  EFI_STATUS          Status;
+  UINT32              NewValue;
+
+  QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;
+
+  EscapeCount           = 100;
+  ContextsMatch         = FALSE;
+  ResetListSearch       = FALSE;
+  EosSet                = FALSE;
+  SxChildWasDispatched  = FALSE;
+  Status                = EFI_WARN_INTERRUPT_SOURCE_PENDING;
+  ChildWasDispatched    = FALSE;
+
+  //
+  // Mark all child handlers as not processed
+  //
+  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+    RecordInDb->Processed = FALSE;
+    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb);
+  }
+
+  //
+  // Preserve Index registers
+  //
+  SaveState ();
+
+  if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {
+    //
+    // We have children registered w/ us -- continue
+    //
+    while ((!EosSet) && (EscapeCount > 0)) {
+      EscapeCount--;
+
+      //
+      // Reset this flag in order to be able to process multiple SMI Sources in one loop.
+      //
+      ResetListSearch = FALSE;
+
+      LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+
+      while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {
+        RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+        //
+        // Make a copy of the record that contains an active SMI source,
+        // because un-register maybe invoked in callback function and
+        // RecordInDb maybe released
+        //
+        CopyMem (&ActiveRecordInDb, RecordInDb, sizeof (ActiveRecordInDb));
+
+        //
+        // look for the first active source
+        //
+        if (!SourceIsActive (&RecordInDb->SrcDesc)) {
+          //
+          // Didn't find the source yet, keep looking
+          //
+          LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+
+        } else {
+          //
+          // We found a source. If this is a sleep type, we have to go to
+          // appropriate sleep state anyway.No matter there is sleep child or not
+          //
+          if (RecordInDb->ProtocolType == SxType) {
+            SxChildWasDispatched = TRUE;
+          }
+          //
+          // "cache" the source description and don't query I/O anymore
+          //
+          CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));
+          LinkToExhaust = LinkInDb;
+
+          //
+          // exhaust the rest of the queue looking for the same source
+          //
+          while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {
+            RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);
+            LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, LinkToExhaust);
+            if (RecordToExhaust->Processed) {
+              //
+              // Record has already been processed.  Continue with next child handler.
+              //
+              continue;
+            }
+
+            if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {
+              //
+              // These source descriptions are equal, so this callback should be
+              // dispatched.
+              //
+              if (RecordToExhaust->ContextFunctions.GetContext != NULL) {
+                //
+                // This child requires that we get a calling context from
+                // hardware and compare that context to the one supplied
+                // by the child.
+                //
+                ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);
+
+                //
+                // Make sure contexts match before dispatching event to child
+                //
+                RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);
+                ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);
+
+              } else {
+                //
+                // This child doesn't require any more calling context beyond what
+                // it supplied in registration.  Simply pass back what it gave us.
+                //
+                ASSERT (RecordToExhaust->Callback != NULL);
+                ContextsMatch = TRUE;
+              }
+
+              //
+              // Mark this child handler so it will not be processed again
+              //
+              RecordToExhaust->Processed = TRUE;
+
+              if (ContextsMatch) {
+
+                if (RecordToExhaust->BufferSize != 0) {
+                  ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL);
+
+                  RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust);
+
+                  CommunicationBuffer = &RecordToExhaust->CommBuffer;
+                  BufferSize = RecordToExhaust->BufferSize;
+                } else {
+                  CommunicationBuffer = NULL;
+                  BufferSize = 0;
+                }
+
+                ASSERT (RecordToExhaust->Callback != NULL);
+
+                RecordToExhaust->Callback (
+                                   (EFI_HANDLE) & RecordToExhaust->Link,
+                                   RecordToExhaust->CallbackContext,
+                                   CommunicationBuffer,
+                                   &BufferSize
+                                   );
+
+                ChildWasDispatched = TRUE;
+                if (RecordToExhaust->ProtocolType == SxType) {
+                  SxChildWasDispatched = TRUE;
+                }
+              }
+              //
+              // Can not use RecordInDb after this point because Callback may have unregistered RecordInDb
+              // Restart processing of SMI handlers from the begining of the linked list because the
+              // state of the linked listed may have been modified due to unregister actions in the Callback.
+              //
+              LinkToExhaust = GetFirstNode (&mPrivateData.CallbackDataBase);
+            }
+          }
+
+          if (ActiveRecordInDb.ClearSource == NULL) {
+            //
+            // Clear the SMI associated w/ the source using the default function
+            //
+            QNCSmmClearSource (&ActiveSource);
+          } else {
+            //
+            // This source requires special handling to clear
+            //
+            ActiveRecordInDb.ClearSource (&ActiveSource);
+          }
+
+          if (ChildWasDispatched) {
+            //
+            // The interrupt was handled and quiesced
+            //
+            Status = EFI_SUCCESS;
+          } else {
+            //
+            // The interrupt was not handled but quiesced
+            //
+            Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
+          }
+
+          //
+          // Queue is empty, reset the search
+          //
+          ResetListSearch = TRUE;
+
+        }
+      }
+      EosSet = QNCSmmSetAndCheckEos ();
+    }
+  }
+  //
+  // If you arrive here, there are two possible reasons:
+  // (1) you've got problems with clearing the SMI status bits in the
+  // ACPI table.  If you don't properly clear the SMI bits, then you won't be able to set the
+  // EOS bit.  If this happens too many times, the loop exits.
+  // (2) there was a SMM communicate for callback messages that was received prior
+  // to this driver.
+  // If there is an asynchronous SMI that occurs while processing the Callback, let
+  // all of the drivers (including this one) have an opportunity to scan for the SMI
+  // and handle it.
+  // If not, we don't want to exit and have the foreground app. clear EOS without letting
+  // these other sources get serviced.
+  //
+  ASSERT (EscapeCount > 0);
+
+  //
+  // Restore Index registers
+  //
+  RestoreState ();
+
+  if (SxChildWasDispatched) {
+    //
+    // A child of the SmmSxDispatch protocol was dispatched during this call;
+    // put the system to sleep.
+    //
+    QNCSmmSxGoToSleep ();
+  }
+
+  //
+  // Ensure that SMI signal pin indicator is clear at the end of SMM handling.
+  //
+  NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG);
+  NewValue &= ~(HLEGACY_SMI_PIN_VALUE);
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue);
+
+  return Status;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf
new file mode 100644
index 0000000000..dec3c5043a
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf
@@ -0,0 +1,81 @@
+## @file
+# Component description file for QuarkNcSocId SmmDispatcher module.
+#
+# This driver is responsible for the registration of child drivers
+#  and the abstraction of the ICH SMI sources.
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = QNCSmmDispatcher
+  FILE_GUID                      = 2480271C-09C6-4f36-AD75-5E1390BD9929
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  VERSION_STRING                 = 1.0
+  PI_SPECIFICATION_VERSION       = 0x0001000A
+  ENTRY_POINT                    = InitializeQNCSmmDispatcher
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  QNC/QNCSmmPeriodicTimer.c
+  QNC/QNCSmmQncn.c
+  QNC/QNCSmmSx.c
+  QNC/QNCSmmSw.c
+  QNC/QNCSmmGpi.c
+  QNC/QNCSmmHelpers.c
+  QNCSmmHelpers.c
+  QNCSmmCore.c
+  QNCSmmHelpers.h
+  QNCxSmmHelpers.h
+  QNCSmmRegisters.h
+  QNCSmm.h
+  CommonHeader.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  SmmServicesTableLib
+  UefiBootServicesTableLib
+  DxeServicesTableLib
+  MemoryAllocationLib
+  PciLib
+  PcdLib
+  BaseMemoryLib
+  DebugLib
+  BaseLib
+  IoLib
+  DevicePathLib
+  S3IoLib
+  QNCAccessLib
+
+[Protocols]
+  gEfiSmmCpuProtocolGuid                        # PROTOCOL ALWAYS_CONSUMED
+  gEfiSmmReadyToLockProtocolGuid                # PROTOCOL ALWAYS_CONSUMED
+  gEfiSmmPeriodicTimerDispatch2ProtocolGuid     # PROTOCOL ALWAYS_PRODUCED
+  gEfiSmmPowerButtonDispatch2ProtocolGuid       # PROTOCOL ALWAYS_PRODUCED
+  gEfiSmmIchnDispatch2ProtocolGuid              # PROTOCOL ALWAYS_PRODUCED
+  gEfiSmmGpiDispatch2ProtocolGuid               # PROTOCOL ALWAYS_PRODUCED
+  gEfiSmmSwDispatch2ProtocolGuid                # PROTOCOL ALWAYS_PRODUCED
+  gEfiSmmSxDispatch2ProtocolGuid                # PROTOCOL ALWAYS_PRODUCED
+  gEfiSmmUsbDispatch2ProtocolGuid               # PROTOCOL ALWAYS_PRODUCED
+  gEfiSmmIoTrapDispatch2ProtocolGuid            # PROTOCOL ALWAYS_PRODUCED
+
+[Pcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
+
+[Depex]
+  gEfiSmmCpuProtocolGuid AND gEfiPciRootBridgeIoProtocolGuid
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c
new file mode 100644
index 0000000000..38729c94ca
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c
@@ -0,0 +1,367 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmm.h"
+#include "QNCSmmHelpers.h"
+
+//
+// #define BIT_ZERO 0x00000001
+//
+CONST UINT32  BIT_ZERO = 0x00000001;
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SUPPORT / HELPER FUNCTIONS (QNC version-independent)
+//
+BOOLEAN
+CompareEnables (
+  CONST IN QNC_SMM_SOURCE_DESC *Src1,
+  CONST IN QNC_SMM_SOURCE_DESC *Src2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Src1  - GC_TODO: add argument description
+  Src2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+{
+  BOOLEAN IsEqual;
+  UINTN   loopvar;
+
+  IsEqual = TRUE;
+  for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
+    //
+    // It's okay to compare a NULL bit description to a non-NULL bit description.
+    // They are unequal and these tests will generate the correct result.
+    //
+    if (Src1->En[loopvar].Bit != Src2->En[loopvar].Bit ||
+        Src1->En[loopvar].Reg.Type != Src2->En[loopvar].Reg.Type ||
+        Src1->En[loopvar].Reg.Data.raw != Src2->En[loopvar].Reg.Data.raw
+        ) {
+      IsEqual = FALSE;
+      break;
+      //
+      // out of for loop
+      //
+    }
+  }
+
+  return IsEqual;
+}
+
+BOOLEAN
+CompareStatuses (
+  CONST IN QNC_SMM_SOURCE_DESC *Src1,
+  CONST IN QNC_SMM_SOURCE_DESC *Src2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Src1  - GC_TODO: add argument description
+  Src2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+{
+  BOOLEAN IsEqual;
+  UINTN   loopvar;
+
+  IsEqual = TRUE;
+
+  for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
+    //
+    // It's okay to compare a NULL bit description to a non-NULL bit description.
+    // They are unequal and these tests will generate the correct result.
+    //
+    if (Src1->Sts[loopvar].Bit != Src2->Sts[loopvar].Bit ||
+        Src1->Sts[loopvar].Reg.Type != Src2->Sts[loopvar].Reg.Type ||
+        Src1->Sts[loopvar].Reg.Data.raw != Src2->Sts[loopvar].Reg.Data.raw
+        ) {
+      IsEqual = FALSE;
+      break;
+      //
+      // out of for loop
+      //
+    }
+  }
+
+  return IsEqual;
+}
+
+BOOLEAN
+CompareSources (
+  CONST IN QNC_SMM_SOURCE_DESC *Src1,
+  CONST IN QNC_SMM_SOURCE_DESC *Src2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Src1  - GC_TODO: add argument description
+  Src2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+{
+  return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, Src2));
+}
+
+BOOLEAN
+SourceIsActive (
+  CONST IN QNC_SMM_SOURCE_DESC *Src
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Src - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+{
+  BOOLEAN IsActive;
+  UINTN   loopvar;
+
+  BOOLEAN SciEn;
+
+  IsActive  = TRUE;
+
+  SciEn     = QNCSmmGetSciEn ();
+
+  if ((Src->Flags & QNC_SMM_SCI_EN_DEPENDENT) && (SciEn)) {
+    //
+    // This source is dependent on SciEn, and SciEn == 1.  An ACPI OS is present,
+    // so we shouldn't do anything w/ this source until SciEn == 0.
+    //
+    IsActive = FALSE;
+
+  } else {
+    //
+    // Read each bit desc from hardware and make sure it's a one
+    //
+    for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
+
+      if (!IS_BIT_DESC_NULL (Src->En[loopvar])) {
+
+        if (ReadBitDesc (&Src->En[loopvar]) == 0) {
+          IsActive = FALSE;
+          break;
+          //
+          // out of for loop
+          //
+        }
+
+      }
+    }
+
+    if (IsActive) {
+      //
+      // Read each bit desc from hardware and make sure it's a one
+      //
+      for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
+
+        if (!IS_BIT_DESC_NULL (Src->Sts[loopvar])) {
+
+          if (ReadBitDesc (&Src->Sts[loopvar]) == 0) {
+            IsActive = FALSE;
+            break;
+            //
+            // out of for loop
+            //
+          }
+
+        }
+      }
+    }
+  }
+
+  return IsActive;
+}
+
+VOID
+QNCSmmEnableSource (
+  CONST QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+{
+  UINTN loopvar;
+
+  //
+  // Set enables to 1 by writing a 1
+  //
+  for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
+    if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) {
+      WriteBitDesc (&SrcDesc->En[loopvar], 1);
+    }
+  }
+
+  QNCSmmClearSource (SrcDesc);
+
+}
+
+VOID
+QNCSmmDisableSource (
+  CONST QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+{
+  UINTN loopvar;
+
+  for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
+    if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) {
+      WriteBitDesc (&SrcDesc->En[loopvar], 0);
+    }
+  }
+}
+
+VOID
+QNCSmmClearSource (
+  CONST QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+{
+  UINTN loopvar;
+  BOOLEAN ValueToWrite;
+
+  ValueToWrite =
+    ((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE;
+
+  for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
+    if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) {
+      WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite);
+    }
+  }
+}
+
+VOID
+QNCSmmClearSourceAndBlock (
+  CONST QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+// GC_TODO: function comment should start with '/*++'
+/*
+  Sets the source to a 1 or 0 and then waits for it to clear.
+  Be very careful when calling this function -- it will not
+  ASSERT.  An acceptable case to call the function is when
+  waiting for the NEWCENTURY_STS bit to clear (which takes
+  3 RTCCLKs).
+*/
+// GC_TODO: function comment should end with '--*/'
+// GC_TODO: function comment is missing 'Routine Description:'
+// GC_TODO: function comment is missing 'Arguments:'
+// GC_TODO: function comment is missing 'Returns:'
+// GC_TODO:    SrcDesc - add argument and description to function comment
+{
+  UINTN   loopvar;
+  BOOLEAN IsSet;
+  BOOLEAN ValueToWrite;
+
+  ValueToWrite =
+    ((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE;
+
+  for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
+
+    if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) {
+      //
+      // Write the bit
+      //
+      WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite);
+
+      //
+      // Don't return until the bit actually clears.
+      //
+      IsSet = TRUE;
+      while (IsSet) {
+        IsSet = ReadBitDesc (&SrcDesc->Sts[loopvar]);
+        //
+        // IsSet will eventually clear -- or else we'll have
+        // an infinite loop.
+        //
+      }
+    }
+  }
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h
new file mode 100644
index 0000000000..0cd26da904
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h
@@ -0,0 +1,219 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef QNC_SMM_HELPERS_H
+#define QNC_SMM_HELPERS_H
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmm.h"
+#include "QNCxSmmHelpers.h"
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SUPPORT / HELPER FUNCTIONS (QNC version-independent)
+//
+VOID
+QNCSmmPublishDispatchProtocols (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  None
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+CompareEnables (
+  CONST IN QNC_SMM_SOURCE_DESC *Src1,
+  CONST IN QNC_SMM_SOURCE_DESC *Src2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Src1  - GC_TODO: add argument description
+  Src2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+CompareStatuses (
+  CONST IN QNC_SMM_SOURCE_DESC *Src1,
+  CONST IN QNC_SMM_SOURCE_DESC *Src2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Src1  - GC_TODO: add argument description
+  Src2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+CompareSources (
+  CONST IN QNC_SMM_SOURCE_DESC *Src1,
+  CONST IN QNC_SMM_SOURCE_DESC *Src2
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Src1  - GC_TODO: add argument description
+  Src2  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+SourceIsActive (
+  CONST IN QNC_SMM_SOURCE_DESC *Src
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  Src - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmEnableSource (
+  CONST QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmDisableSource (
+  CONST QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmClearSource (
+  CONST QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmClearSourceAndBlock (
+  CONST QNC_SMM_SOURCE_DESC *SrcDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h
new file mode 100644
index 0000000000..aec0c70283
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h
@@ -0,0 +1,13 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef QNC_SMM_REGISTERS_H
+#define QNC_SMM_REGISTERS_H
+#include "CommonHeader.h"
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h
new file mode 100644
index 0000000000..3f89b6411f
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h
@@ -0,0 +1,178 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef QNCX_SMM_HELPERS_H
+#define QNCX_SMM_HELPERS_H
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmm.h"
+
+EFI_STATUS
+QNCSmmInitHardware (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  None
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+QNCSmmEnableGlobalSmiBit (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Enables the QNC to generate SMIs. Note that no SMIs will be generated
+  if no SMI sources are enabled. Conversely, no enabled SMI source will
+  generate SMIs if SMIs are not globally enabled. This is the main
+  switchbox for SMI generation.
+
+Arguments:
+
+  None
+
+Returns:
+
+  EFI_SUCCESS.
+  Asserts, otherwise.
+
+--*/
+;
+
+EFI_STATUS
+QNCSmmClearSmi (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  None
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+QNCSmmSetAndCheckEos (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  None
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+QNCSmmGetSciEn (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  None
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+//
+// ///////////////////////////////////////////////////////////////////////////
+//
+// These may or may not need to change w/ the QNC version;
+// they're here because they're highly IA-32 dependent.
+//
+BOOLEAN
+ReadBitDesc (
+  CONST QNC_SMM_BIT_DESC *BitDesc
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  BitDesc - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+VOID
+WriteBitDesc (
+  CONST QNC_SMM_BIT_DESC  *BitDesc,
+  CONST BOOLEAN          ValueToWrite
+  )
+/*++
+
+Routine Description:
+
+  GC_TODO: Add function description
+
+Arguments:
+
+  BitDesc       - GC_TODO: add argument description
+  ValueToWrite  - GC_TODO: add argument description
+
+Returns:
+
+  GC_TODO: add return values
+
+--*/
+;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c
new file mode 100644
index 0000000000..637792d147
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c
@@ -0,0 +1,376 @@
+/** @file
+This is the driver that publishes the SMM Access Ppi
+instance for the Quark SOC.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <PiPei.h>
+#include <Ppi/SmmAccess.h>
+#include <Guid/SmramMemoryReserve.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PciLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/QNCSmmLib.h>
+#include <QNCAccess.h>
+
+#define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \
+  CR ( \
+  a, \
+  SMM_ACCESS_PRIVATE_DATA, \
+  SmmAccess, \
+  SMM_ACCESS_PRIVATE_DATA_SIGNATURE \
+  )
+
+#define MAX_CPU_SOCKET      1
+#define MAX_SMRAM_RANGES    4
+
+typedef struct {
+  UINTN                            Signature;
+  EFI_HANDLE                       Handle;
+  PEI_SMM_ACCESS_PPI               SmmAccess;
+  UINTN                            NumberRegions;
+  EFI_SMRAM_DESCRIPTOR             SmramDesc[MAX_SMRAM_RANGES];
+  UINT8                            TsegSize;
+  UINT8                            MaxBusNumber;
+  UINT8                            SocketPopulated[MAX_CPU_SOCKET];
+  UINT8                            SocketBusNum[MAX_CPU_SOCKET];
+} SMM_ACCESS_PRIVATE_DATA;
+
+#define  SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a')
+
+
+EFI_STATUS
+EFIAPI
+Open (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN PEI_SMM_ACCESS_PPI         *This,
+  IN UINTN                      DescriptorIndex
+  )
+/*++
+
+Routine Description:
+
+  This routine accepts a request to "open" a region of SMRAM.  The
+  region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
+  The use of "open" means that the memory is visible from all PEIM
+  and SMM agents.
+
+Arguments:
+
+  PeiServices      - General purpose services available to every PEIM.
+  This             -  Pointer to the SMM Access Interface.
+  DescriptorIndex  -  Region of SMRAM to Open.
+
+Returns:
+
+  EFI_SUCCESS            -  The region was successfully opened.
+  EFI_DEVICE_ERROR       -  The region could not be opened because locked by
+                            chipset.
+  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
+
+--*/
+{
+  SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+
+  SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+  if (DescriptorIndex >= SmmAccess->NumberRegions) {
+    return EFI_INVALID_PARAMETER;
+  } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Open TSEG
+  //
+  if (!QNCOpenSmramRegion ()) {
+    SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
+    return EFI_DEVICE_ERROR;
+  }
+
+  SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+  SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_OPEN;
+  SmmAccess->SmmAccess.OpenState = TRUE;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Close (
+  IN EFI_PEI_SERVICES        **PeiServices,
+  IN PEI_SMM_ACCESS_PPI      *This,
+  IN UINTN                   DescriptorIndex
+  )
+/*++
+
+Routine Description:
+
+  This routine accepts a request to "close" a region of SMRAM.  This is valid for
+  compatible SMRAM region.
+
+Arguments:
+
+  PeiServices      - General purpose services available to every PEIM.
+  This             -  Pointer to the SMM Access Interface.
+  DescriptorIndex  -  Region of SMRAM to Close.
+
+Returns:
+
+  EFI_SUCCESS            -  The region was successfully closed.
+  EFI_DEVICE_ERROR       -  The region could not be closed because locked by
+                            chipset.
+  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
+
+--*/
+{
+  SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+  BOOLEAN                 OpenState;
+  UINTN                   Index;
+
+
+  SmmAccess     = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+  if (DescriptorIndex >= SmmAccess->NumberRegions) {
+    return EFI_INVALID_PARAMETER;
+  } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_CLOSED) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Close TSEG
+  //
+  if (!QNCCloseSmramRegion ()) {
+    SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
+    return EFI_DEVICE_ERROR;
+  }
+
+  SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~EFI_SMRAM_OPEN;
+  SmmAccess->SmramDesc[DescriptorIndex].RegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+
+  //
+  // Find out if any regions are still open
+  //
+  OpenState = FALSE;
+  for (Index = 0; Index < SmmAccess->NumberRegions; Index++) {
+    if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {
+      OpenState = TRUE;
+    }
+  }
+
+  SmmAccess->SmmAccess.OpenState = OpenState;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Lock (
+  IN EFI_PEI_SERVICES          **PeiServices,
+  IN PEI_SMM_ACCESS_PPI        *This,
+  IN UINTN                     DescriptorIndex
+  )
+/*++
+
+Routine Description:
+
+  This routine accepts a request to "lock" SMRAM.  The
+  region could be legacy AB or TSEG near top of physical memory.
+  The use of "lock" means that the memory can no longer be opened
+  to PEIM.
+
+Arguments:
+
+  PeiServices      - General purpose services available to every PEIM.
+  This             -  Pointer to the SMM Access Interface.
+  DescriptorIndex  -  Region of SMRAM to Lock.
+
+Returns:
+
+  EFI_SUCCESS            -  The region was successfully locked.
+  EFI_DEVICE_ERROR       -  The region could not be locked because at least
+                            one range is still open.
+  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
+
+--*/
+{
+  SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+
+  SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+  if (DescriptorIndex >= SmmAccess->NumberRegions) {
+    return EFI_INVALID_PARAMETER;
+  } else if (SmmAccess->SmmAccess.OpenState) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
+  SmmAccess->SmmAccess.LockState                     = TRUE;
+
+  //
+  // Lock TSEG
+  //
+  QNCLockSmramRegion ();
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+GetCapabilities (
+  IN EFI_PEI_SERVICES                **PeiServices,
+  IN PEI_SMM_ACCESS_PPI              *This,
+  IN OUT UINTN                       *SmramMapSize,
+  IN OUT EFI_SMRAM_DESCRIPTOR        *SmramMap
+  )
+/*++
+
+Routine Description:
+
+  This routine services a user request to discover the SMRAM
+  capabilities of this platform.  This will report the possible
+  ranges that are possible for SMRAM access, based upon the
+  memory controller capabilities.
+
+Arguments:
+
+  PeiServices   - General purpose services available to every PEIM.
+  This          -  Pointer to the SMRAM Access Interface.
+  SmramMapSize  -  Pointer to the variable containing size of the
+                   buffer to contain the description information.
+  SmramMap      -  Buffer containing the data describing the Smram
+                   region descriptors.
+Returns:
+
+  EFI_BUFFER_TOO_SMALL  -  The user did not provide a sufficient buffer.
+  EFI_SUCCESS           -  The user provided a sufficiently-sized buffer.
+
+--*/
+{
+  EFI_STATUS                Status;
+  SMM_ACCESS_PRIVATE_DATA  *SmmAccess;
+  UINTN                     BufferSize;
+
+  SmmAccess           = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+  BufferSize          = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);
+
+  if (*SmramMapSize < BufferSize) {
+    Status = EFI_BUFFER_TOO_SMALL;
+  } else {
+    CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);
+    Status = EFI_SUCCESS;
+  }
+
+  *SmramMapSize = BufferSize;
+
+  return Status;
+}
+
+
+EFI_STATUS
+EFIAPI
+SmmAccessPeiEntryPoint (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+/*++
+
+Routine Description:
+
+    This is the constructor for the SMM Access Ppi
+
+Arguments:
+
+    FfsHeader       - FfsHeader.
+    PeiServices     - General purpose services available to every PEIM.
+
+Returns:
+
+  EFI_SUCCESS     -  Protocol successfully started and installed.
+  EFI_UNSUPPORTED -  Protocol can't be started.
+--*/
+{
+
+  EFI_STATUS                      Status;
+  UINTN                           Index;
+  EFI_SMRAM_HOB_DESCRIPTOR_BLOCK  *DescriptorBlock;
+  SMM_ACCESS_PRIVATE_DATA         *SmmAccessPrivate;
+  EFI_PEI_PPI_DESCRIPTOR          *PpiList;
+  EFI_HOB_GUID_TYPE               *GuidHob;
+
+  //
+  // Initialize private data
+  //
+  SmmAccessPrivate = AllocatePool (sizeof(*SmmAccessPrivate));
+  ASSERT(SmmAccessPrivate);
+
+  PpiList = AllocatePool (sizeof(*PpiList));
+  ASSERT (PpiList);
+
+  //
+  // Build SMM related information
+  //
+  SmmAccessPrivate->Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;
+
+  //
+  // Get Hob list
+  //
+  GuidHob    = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
+  DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
+  ASSERT (DescriptorBlock);
+
+  // Get CPU Max bus number
+
+  SmmAccessPrivate->MaxBusNumber = PCI_BUS_NUMBER_QNC;
+  for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {
+    SmmAccessPrivate->SocketPopulated[Index] = TRUE;
+    SmmAccessPrivate->SocketBusNum[Index]    = PCI_BUS_NUMBER_QNC;
+  }
+
+  //
+  // Use the hob to publish SMRAM capabilities
+  //
+  ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);
+  for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {
+    SmmAccessPrivate->SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;
+    SmmAccessPrivate->SmramDesc[Index].CpuStart      = DescriptorBlock->Descriptor[Index].CpuStart;
+    SmmAccessPrivate->SmramDesc[Index].PhysicalSize  = DescriptorBlock->Descriptor[Index].PhysicalSize;
+    SmmAccessPrivate->SmramDesc[Index].RegionState   = DescriptorBlock->Descriptor[Index].RegionState;
+  }
+
+  SmmAccessPrivate->NumberRegions              = Index;
+  SmmAccessPrivate->SmmAccess.Open             = Open;
+  SmmAccessPrivate->SmmAccess.Close            = Close;
+  SmmAccessPrivate->SmmAccess.Lock             = Lock;
+  SmmAccessPrivate->SmmAccess.GetCapabilities  = GetCapabilities;
+  SmmAccessPrivate->SmmAccess.LockState        = FALSE;
+  SmmAccessPrivate->SmmAccess.OpenState        = FALSE;
+
+  PpiList->Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+  PpiList->Guid  = &gPeiSmmAccessPpiGuid;
+  PpiList->Ppi   = &SmmAccessPrivate->SmmAccess;
+
+  Status      = (**PeiServices).InstallPpi (PeiServices, PpiList);
+  ASSERT_EFI_ERROR(Status);
+
+  DEBUG (
+    (EFI_D_INFO, "SMM Base:Size %08X:%08X\n",
+    (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalStart),
+    (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize)
+    ));
+
+  SmmAccessPrivate->TsegSize = (UINT8)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf
new file mode 100644
index 0000000000..34d90b26ea
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf
@@ -0,0 +1,45 @@
+## @file
+# Component description file for SmmAccessPei module
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+INF_VERSION          = 0x00010005
+BASE_NAME            = SmmAccessPei
+FILE_GUID            = B4E0CDFC-30CD-4b29-A445-B0AA95A532E4
+MODULE_TYPE          = PEIM
+VERSION_STRING       = 1.0
+ENTRY_POINT          = SmmAccessPeiEntryPoint
+
+[Sources]
+  SmmAccessPei.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelFrameworkPkg/IntelFrameworkPkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  PeimEntryPoint
+  BaseMemoryLib
+  MemoryAllocationLib
+  DebugLib
+  HobLib
+  PeiServicesLib
+  PciLib
+  SmmLib
+
+[Guids]
+  gEfiSmmPeiSmramMemoryReserveGuid             # ALWAYS_CONSUMED
+
+[Ppis]
+  gPeiSmmAccessPpiGuid                         # ALWAYS_PRODUCED
+  gEfiPeiMemoryDiscoveredPpiGuid               # ALWAYS_CONSUMED
+
+[Depex]
+  gEfiPeiMemoryDiscoveredPpiGuid
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c
new file mode 100644
index 0000000000..243e4c9e99
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c
@@ -0,0 +1,274 @@
+/** @file
+This module provides an implementation of the SMM Control PPI for use with
+the QNC.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Ppi/SmmControl.h>
+
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+
+#include <IntelQNCPeim.h>
+#include <Library/QNCAccessLib.h>
+#include <Uefi/UefiBaseType.h>
+
+/**
+  Generates an SMI using the parameters passed in.
+
+  @param  PeiServices         Describes the list of possible PEI Services.
+  @param  This                A pointer to an instance of
+                              EFI_SMM_CONTROL_PPI
+  @param  ArgumentBuffer      The argument buffer
+  @param  ArgumentBufferSize  The size of the argument buffer
+  @param  Periodic            TRUE to indicate a periodical SMI
+  @param  ActivationInterval  Interval of the periodical SMI
+
+  @retval EFI_INVALID_PARAMETER  Periodic is TRUE or ArgumentBufferSize > 1
+  @retval EFI_SUCCESS            SMI generated
+
+**/
+EFI_STATUS
+EFIAPI
+PeiActivate (
+  IN      EFI_PEI_SERVICES           **PeiServices,
+  IN      PEI_SMM_CONTROL_PPI        *This,
+  IN OUT  INT8                       *ArgumentBuffer OPTIONAL,
+  IN OUT  UINTN                      *ArgumentBufferSize OPTIONAL,
+  IN      BOOLEAN                    Periodic OPTIONAL,
+  IN      UINTN                      ActivationInterval OPTIONAL
+  );
+
+/**
+  Clears an SMI.
+
+  @param  PeiServices         Describes the list of possible PEI Services.
+  @param  This                Pointer to an instance of EFI_SMM_CONTROL_PPI
+  @param  Periodic            TRUE to indicate a periodical SMI
+
+  @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDeactivate (
+  IN  EFI_PEI_SERVICES            **PeiServices,
+  IN  PEI_SMM_CONTROL_PPI         *This,
+  IN  BOOLEAN                     Periodic OPTIONAL
+  );
+
+PEI_SMM_CONTROL_PPI      mSmmControlPpi = {
+  PeiActivate,
+  PeiDeactivate
+};
+
+EFI_PEI_PPI_DESCRIPTOR   mPpiList = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gPeiSmmControlPpiGuid,
+  &mSmmControlPpi
+};
+
+/**
+  Clear SMI related chipset status and re-enable SMI by setting the EOS bit.
+
+  @retval EFI_SUCCESS       The requested operation has been carried out successfully
+  @retval EFI_DEVICE_ERROR  The EOS bit could not be set.
+
+**/
+EFI_STATUS
+SmmClear (
+  VOID
+  )
+{
+  UINT16                       GPE0BLK_Base;
+
+  //
+  // Get GPE0BLK_Base
+  //
+  GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+  //
+  // Clear the Power Button Override Status Bit, it gates EOS from being set.
+  // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.
+  //
+
+  //
+  // Clear the APM SMI Status Bit
+  //
+  IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
+
+  //
+  // Set the EOS Bit
+  //
+  IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
+
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+SmmTrigger (
+  IN UINT8   Data
+  )
+/*++
+
+Routine Description:
+
+  Trigger the software SMI
+
+Arguments:
+
+  Data                          The value to be set on the software SMI data port
+
+Returns:
+
+  EFI_SUCCESS                   Function completes successfully
+
+--*/
+{
+  UINT16        GPE0BLK_Base;
+  UINT32        NewValue;
+
+  //
+  // Get GPE0BLK_Base
+  //
+  GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+  //
+  // Enable the APMC SMI
+  //
+  IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);
+
+  //
+  // Enable SMI globally
+  //
+  NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+  NewValue |= SMI_EN;
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+
+  //
+  // Generate the APMC SMI
+  //
+  IoWrite8 (PcdGet16 (PcdSmmActivationPort), Data);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Generates an SMI using the parameters passed in.
+
+  @param  PeiServices         Describes the list of possible PEI Services.
+  @param  This                A pointer to an instance of
+                              EFI_SMM_CONTROL_PPI
+  @param  ArgumentBuffer      The argument buffer
+  @param  ArgumentBufferSize  The size of the argument buffer
+  @param  Periodic            TRUE to indicate a periodical SMI
+  @param  ActivationInterval  Interval of the periodical SMI
+
+  @retval EFI_INVALID_PARAMETER  Periodic is TRUE or ArgumentBufferSize > 1
+  @retval EFI_SUCCESS            SMI generated
+
+**/
+EFI_STATUS
+EFIAPI
+PeiActivate (
+  IN      EFI_PEI_SERVICES           **PeiServices,
+  IN      PEI_SMM_CONTROL_PPI        *This,
+  IN OUT  INT8                       *ArgumentBuffer OPTIONAL,
+  IN OUT  UINTN                      *ArgumentBufferSize OPTIONAL,
+  IN      BOOLEAN                    Periodic OPTIONAL,
+  IN      UINTN                      ActivationInterval OPTIONAL
+  )
+{
+  INT8       Data;
+  EFI_STATUS Status;
+  //
+  // Periodic SMI not supported.
+  //
+  if (Periodic) {
+    DEBUG ((DEBUG_WARN, "Invalid parameter\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (ArgumentBuffer == NULL) {
+    Data = 0xFF;
+  } else {
+    if (ArgumentBufferSize == NULL || *ArgumentBufferSize != 1) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    Data = *ArgumentBuffer;
+  }
+  //
+  // Clear any pending the APM SMI
+  //
+  Status = SmmClear ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return SmmTrigger (Data);
+}
+
+/**
+  Clears an SMI.
+
+  @param  PeiServices         Describes the list of possible PEI Services.
+  @param  This                Pointer to an instance of EFI_SMM_CONTROL_PPI
+  @param  Periodic            TRUE to indicate a periodical SMI
+
+  @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDeactivate (
+  IN  EFI_PEI_SERVICES            **PeiServices,
+  IN  PEI_SMM_CONTROL_PPI         *This,
+  IN  BOOLEAN                     Periodic OPTIONAL
+  )
+{
+  if (Periodic) {
+    return EFI_INVALID_PARAMETER;
+  }
+  return SmmClear ();
+}
+
+/**
+  This is the constructor for the SMM Control Ppi.
+
+  This function installs EFI_SMM_CONTROL_PPI.
+
+  @param   FileHandle       Handle of the file being invoked.
+  @param   PeiServices      Describes the list of possible PEI Services.
+
+  @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
+  @return The status returned from InstallPpi().
+
+--*/
+EFI_STATUS
+EFIAPI
+SmmControlPeiEntry (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  EFI_STATUS  Status;
+
+  Status      = (**PeiServices).InstallPpi (PeiServices, &mPpiList);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf
new file mode 100644
index 0000000000..a790641013
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf
@@ -0,0 +1,51 @@
+## @file
+# Component description file for SmmControlPei module.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SmmControlPei
+  FILE_GUID                      = 60EC7720-512B-4490-9FD1-A336769AE01F
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = SmmControlPeiEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  SmmControlPei.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  PeimEntryPoint
+  DebugLib
+  PeiServicesLib
+  PcdLib
+  IoLib
+  PciLib
+  QNCAccessLib
+
+[Ppis]
+  gPeiSmmControlPpiGuid                        # ALWAYS_PRODUCED
+
+[Pcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort
+
+[Depex]
+  TRUE
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c
new file mode 100644
index 0000000000..cbcd63c036
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c
@@ -0,0 +1,927 @@
+/** @file
+PCH SPI Common Driver implements the SPI Host Controller Compatibility Interface.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PchSpi.h"
+
+VOID
+FillOutPublicInfoStruct (
+  SPI_INSTANCE          *SpiInstance
+  )
+/*++
+
+Routine Description:
+
+  Fillout SpiInstance->InitInfo;
+
+Arguments:
+
+  SpiInstance   - Pointer to SpiInstance to initialize
+
+Returns:
+
+  NONE
+
+--*/
+{
+  UINT8         Index;
+
+  SpiInstance->InitInfo.InitTable = &SpiInstance->SpiInitTable;
+
+  //
+  // Give invalid index in case operation not supported.
+  //
+  SpiInstance->InitInfo.JedecIdOpcodeIndex = 0xff;
+  SpiInstance->InitInfo.OtherOpcodeIndex = 0xff;
+  SpiInstance->InitInfo.WriteStatusOpcodeIndex = 0xff;
+  SpiInstance->InitInfo.ProgramOpcodeIndex = 0xff;
+  SpiInstance->InitInfo.ReadOpcodeIndex = 0xff;
+  SpiInstance->InitInfo.EraseOpcodeIndex = 0xff;
+  SpiInstance->InitInfo.ReadStatusOpcodeIndex = 0xff;
+  SpiInstance->InitInfo.FullChipEraseOpcodeIndex = 0xff;
+  for (Index = 0; Index < SPI_NUM_OPCODE; Index++) {
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) {
+      SpiInstance->InitInfo.JedecIdOpcodeIndex = Index;
+    }
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationOther) {
+      SpiInstance->InitInfo.OtherOpcodeIndex = Index;
+    }
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) {
+      SpiInstance->InitInfo.WriteStatusOpcodeIndex = Index;
+    }
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_1_Byte ||
+        SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_64_Byte) {
+      SpiInstance->InitInfo.ProgramOpcodeIndex = Index;
+    }
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadData ||
+        SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFastRead ||
+        SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDualOutputFastRead) {
+      SpiInstance->InitInfo.ReadOpcodeIndex = Index;
+    }
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_256_Byte ||
+        SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_4K_Byte ||
+        SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_8K_Byte ||
+        SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_64K_Byte) {
+      SpiInstance->InitInfo.EraseOpcodeIndex = Index;
+    }
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadStatus) {
+      SpiInstance->InitInfo.ReadStatusOpcodeIndex = Index;
+    }
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFullChipErase) {
+      SpiInstance->InitInfo.FullChipEraseOpcodeIndex = Index;
+    }
+  }
+}
+
+EFI_STATUS
+SpiProtocolConstructor (
+  SPI_INSTANCE          *SpiInstance
+  )
+/*++
+
+Routine Description:
+
+  Initialize an SPI protocol instance.
+  The function will assert in debug if PCH RCBA has not been initialized
+
+Arguments:
+
+  SpiInstance   - Pointer to SpiInstance to initialize
+
+Returns:
+
+  EFI_SUCCESS     The protocol instance was properly initialized
+  EFI_UNSUPPORTED The PCH is not supported by this module
+
+--*/
+{
+  SpiInstance->InitDone = FALSE;  // Indicate NOT READY.
+
+  //
+  // Check if the current PCH is known and supported by this code
+  //
+  if (!IsQncSupported ()) {
+    DEBUG ((DEBUG_ERROR, "PCH SPI Protocol not supported due to no proper QNC LPC found!\n"));
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Initialize the SPI protocol instance
+  //
+  SpiInstance->Signature            = PCH_SPI_PRIVATE_DATA_SIGNATURE;
+  SpiInstance->Handle               = NULL;
+  SpiInstance->SpiProtocol.Init     = SpiProtocolInit;
+  SpiInstance->SpiProtocol.Lock     = SpiProtocolLock;
+  SpiInstance->SpiProtocol.Execute  = SpiProtocolExecute;
+  SpiInstance->SpiProtocol.Info     = SpiProtocolInfo;
+
+  //
+  // Sanity check to ensure PCH RCBA initialization has occurred previously.
+  //
+  SpiInstance->PchRootComplexBar = MmioRead32 (
+                                    PciDeviceMmBase (PCI_BUS_NUMBER_QNC,
+                                    PCI_DEVICE_NUMBER_QNC_LPC,
+                                    PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_RCBA
+                                    ) & B_QNC_LPC_RCBA_MASK;
+  ASSERT (SpiInstance->PchRootComplexBar != 0);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UnlockFlashComponents (
+  IN      EFI_SPI_PROTOCOL      *This,
+  IN      UINT8                 UnlockCmdOpcodeIndex
+  )
+/*++
+
+Routine Description:
+
+  Issue unlock command to disable block protection, this only needs to be done once per SPI power on
+
+Arguments:
+
+  This                      A pointer to "EFI_SPI_PROTOCOL" for issuing commands
+  UnlockCmdOpcodeIndex      The index of the Unlock command
+
+Returns:
+
+  EFI_SUCCESS               UnLock operation succeed.
+  EFI_DEVICE_ERROR          Device error, operation failed.
+
+--*/
+{
+  EFI_STATUS    Status;
+  SPI_INSTANCE  *SpiInstance;
+  UINT8         SpiStatus;
+
+  if (UnlockCmdOpcodeIndex >= SPI_NUM_OPCODE) {
+    return EFI_UNSUPPORTED;
+  }
+
+  SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+
+  //
+  // Issue unlock command to disable block protection, this only needs to be done once per SPI power on
+  //
+  SpiStatus = 0;
+  //
+  // Issue unlock command to the flash component 1 at first
+  //
+  Status = SpiProtocolExecute (
+            This,
+            UnlockCmdOpcodeIndex,
+            SpiInstance->SpiInitTable.PrefixOpcode[0] == PCH_SPI_COMMAND_WRITE_ENABLE ? 0 : 1,
+            TRUE,
+            TRUE,
+            TRUE,
+            (UINTN) 0,
+            sizeof (SpiStatus),
+            &SpiStatus,
+            EnumSpiRegionAll
+            );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Unlock flash component 1 fail!\n"));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiProtocolInit (
+  IN EFI_SPI_PROTOCOL       *This,
+  IN SPI_INIT_TABLE         *InitTable
+  )
+/*++
+
+Routine Description:
+
+  Initialize the host controller to execute SPI command.
+
+Arguments:
+
+  This                    Pointer to the EFI_SPI_PROTOCOL instance.
+  InitTable               Initialization data to be programmed into the SPI host controller.
+
+Returns:
+
+  EFI_SUCCESS             Initialization completed.
+  EFI_ACCESS_DENIED       The SPI static configuration interface has been locked-down.
+  EFI_INVALID_PARAMETER   Bad input parameters.
+  EFI_UNSUPPORTED         Can't get Descriptor mode VSCC values
+--*/
+{
+  EFI_STATUS    Status;
+  UINT8         Index;
+  UINT16        OpcodeType;
+  SPI_INSTANCE  *SpiInstance;
+  UINTN         PchRootComplexBar;
+  UINT8         UnlockCmdOpcodeIndex;
+  UINT8         FlashPartId[3];
+
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+  PchRootComplexBar = SpiInstance->PchRootComplexBar;
+
+  if (InitTable != NULL) {
+    //
+    // Copy table into SPI driver Private data structure
+    //
+    CopyMem (
+      &SpiInstance->SpiInitTable,
+      InitTable,
+      sizeof (SPI_INIT_TABLE)
+      );
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Check if the SPI interface has been locked-down.
+  //
+  if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {
+    ASSERT_EFI_ERROR (EFI_ACCESS_DENIED);
+    return EFI_ACCESS_DENIED;
+  }
+  //
+  // Clear all the status bits for status regs.
+  //
+  MmioOr16 (
+    (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS),
+    (UINT16) ((B_QNC_RCRB_SPIS_CDS | B_QNC_RCRB_SPIS_BAS))
+    );
+  MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS);
+
+  //
+  // Set the Prefix Opcode registers.
+  //
+  MmioWrite16 (
+    PchRootComplexBar + R_QNC_RCRB_SPIPREOP,
+    (SpiInstance->SpiInitTable.PrefixOpcode[1] << 8) | InitTable->PrefixOpcode[0]
+    );
+  MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIPREOP);
+
+  //
+  // Set Opcode Type Configuration registers.
+  //
+  for (Index = 0, OpcodeType = 0; Index < SPI_NUM_OPCODE; Index++) {
+    switch (SpiInstance->SpiInitTable.OpcodeMenu[Index].Type) {
+    case EnumSpiOpcodeRead:
+      OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_READ << (Index * 2));
+      break;
+    case EnumSpiOpcodeWrite:
+      OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_WRITE << (Index * 2));
+      break;
+    case EnumSpiOpcodeWriteNoAddr:
+      OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE << (Index * 2));
+      break;
+    default:
+      OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_READ << (Index * 2));
+      break;
+    }
+  }
+  MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE, OpcodeType);
+  MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE);
+
+  //
+  // Setup the Opcode Menu registers.
+  //
+  UnlockCmdOpcodeIndex = SPI_NUM_OPCODE;
+  for (Index = 0; Index < SPI_NUM_OPCODE; Index++) {
+    MmioWrite8 (
+      PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index,
+      SpiInstance->SpiInitTable.OpcodeMenu[Index].Code
+      );
+    MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index);
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) {
+      Status = SpiProtocolExecute (
+                This,
+                Index,
+                0,
+                TRUE,
+                TRUE,
+                FALSE,
+                (UINTN) 0,
+                3,
+                FlashPartId,
+                EnumSpiRegionDescriptor
+                );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      if (FlashPartId[0] != SpiInstance->SpiInitTable.VendorId  ||
+          FlashPartId[1] != SpiInstance->SpiInitTable.DeviceId0 ||
+          FlashPartId[2] != SpiInstance->SpiInitTable.DeviceId1) {
+        return EFI_INVALID_PARAMETER;
+      }
+    }
+
+    if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) {
+      UnlockCmdOpcodeIndex = Index;
+    }
+  }
+
+  Status = UnlockFlashComponents (
+            This,
+            UnlockCmdOpcodeIndex
+            );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Unlock flash components fail!\n"));
+  }
+
+  SpiPhaseInit ();
+  FillOutPublicInfoStruct (SpiInstance);
+  SpiInstance->InitDone = TRUE;
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiProtocolLock (
+  IN EFI_SPI_PROTOCOL     *This
+  )
+/*++
+
+Routine Description:
+
+  Lock the SPI Static Configuration Interface.
+  Once locked, the interface can not be changed and can only be clear by system reset.
+
+Arguments:
+
+  This      Pointer to the EFI_SPI_PROTOCOL instance.
+
+Returns:
+
+  EFI_SUCCESS             Lock operation succeed.
+  EFI_DEVICE_ERROR        Device error, operation failed.
+  EFI_ACCESS_DENIED       The interface has already been locked.
+
+--*/
+{
+  SPI_INSTANCE  *SpiInstance;
+  UINTN         PchRootComplexBar;
+
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+  PchRootComplexBar = SpiInstance->PchRootComplexBar;
+
+  //
+  // Check if the SPI interface has been locked-down.
+  //
+  if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // Lock-down the configuration interface.
+  //
+  MmioOr16 ((UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS), (UINT16) (B_QNC_RCRB_SPIS_SCL));
+
+  //
+  // Verify if it's really locked.
+  //
+  if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) == 0) {
+    return EFI_DEVICE_ERROR;
+  } else {
+    //
+    // Save updated register in S3 Boot script.
+    //
+    S3BootScriptSaveMemWrite (
+      S3BootScriptWidthUint16,
+        (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS),
+        1,
+        (VOID *) (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS)
+        );
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiProtocolExecute (
+  IN     EFI_SPI_PROTOCOL   *This,
+  IN     UINT8              OpcodeIndex,
+  IN     UINT8              PrefixOpcodeIndex,
+  IN     BOOLEAN            DataCycle,
+  IN     BOOLEAN            Atomic,
+  IN     BOOLEAN            ShiftOut,
+  IN     UINTN              Address,
+  IN     UINT32             DataByteCount,
+  IN OUT UINT8              *Buffer,
+  IN     SPI_REGION_TYPE    SpiRegionType
+  )
+/*++
+
+Routine Description:
+
+  Execute SPI commands from the host controller.
+  This function would be called by runtime driver, please do not use any MMIO marco here
+
+Arguments:
+
+  This              Pointer to the EFI_SPI_PROTOCOL instance.
+  OpcodeIndex       Index of the command in the OpCode Menu.
+  PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
+  DataCycle         TRUE if the SPI cycle contains data
+  Atomic            TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+  ShiftOut          If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+  Address           In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+                    Region, this value specifies the offset from the Region Base; for BIOS Region,
+                    this value specifies the offset from the start of the BIOS Image. In Non
+                    Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+                    Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+                    Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+                    supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+                    the flash (in Non Descriptor Mode)
+  DataByteCount     Number of bytes in the data portion of the SPI cycle. This function may break the
+                    data transfer into multiple operations. This function ensures each operation does
+                    not cross 256 byte flash address boundary.
+                    *NOTE: if there is some SPI chip that has a stricter address boundary requirement
+                    (e.g., its write page size is < 256 byte), then the caller cannot rely on this
+                    function to cut the data transfer at proper address boundaries, and it's the
+                    caller's reponsibility to pass in a properly cut DataByteCount parameter.
+  Buffer            Pointer to caller-allocated buffer containing the dada received or sent during the
+                    SPI cycle.
+  SpiRegionType     SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+                    EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+                    Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+                    and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+                    to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+Returns:
+
+  EFI_SUCCESS             Command succeed.
+  EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  EFI_UNSUPPORTED         Command not supported.
+  EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+--*/
+{
+  EFI_STATUS  Status;
+  UINT16      BiosCtlSave;
+  UINT32      SmiEnSave;
+
+  BiosCtlSave = 0;
+  SmiEnSave   = 0;
+
+  //
+  // Check if the parameters are valid.
+  //
+  if ((OpcodeIndex >= SPI_NUM_OPCODE) || (PrefixOpcodeIndex >= SPI_NUM_PREFIX_OPCODE)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Make sure it's safe to program the command.
+  //
+  if (!WaitForSpiCycleComplete (This, FALSE)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Acquire access to the SPI interface is not required any more.
+  //
+  //
+  // Disable SMIs to make sure normal mode flash access is not interrupted by an SMI
+  // whose SMI handler accesses flash (e.g. for error logging)
+  //
+  SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));
+
+  //
+  // Save BIOS Ctrl register
+  //
+  BiosCtlSave = PciRead16 (
+                  PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
+                  PCI_DEVICE_NUMBER_QNC_LPC,
+                  PCI_FUNCTION_NUMBER_QNC_LPC,
+                  R_QNC_LPC_BIOS_CNTL)
+                  ) & (B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP);
+
+  //
+  // Enable flash writing
+  //
+  PciOr16 (
+    PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
+    PCI_DEVICE_NUMBER_QNC_LPC,
+    PCI_FUNCTION_NUMBER_QNC_LPC,
+    R_QNC_LPC_BIOS_CNTL),
+    (UINT16) (B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)
+    );
+
+  //
+  // If shifts the data out, disable Prefetching and Caching.
+  //
+  if (ShiftOut) {
+    PciAndThenOr16 (
+      PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
+      PCI_DEVICE_NUMBER_QNC_LPC,
+      PCI_FUNCTION_NUMBER_QNC_LPC,
+      R_QNC_LPC_BIOS_CNTL),
+      (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE)),
+      (UINT16) ((B_QNC_LPC_BIOS_CNTL_BCD))
+      );
+  }
+  //
+  // Sends the command to the SPI interface to execute.
+  //
+  Status = SendSpiCmd (
+            This,
+            OpcodeIndex,
+            PrefixOpcodeIndex,
+            DataCycle,
+            Atomic,
+            ShiftOut,
+            Address,
+            DataByteCount,
+            Buffer,
+            SpiRegionType
+            );
+
+  //
+  // Restore BIOS Ctrl register
+  //
+  PciAndThenOr16 (
+    PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
+    PCI_DEVICE_NUMBER_QNC_LPC,
+    PCI_FUNCTION_NUMBER_QNC_LPC,
+    R_QNC_LPC_BIOS_CNTL),
+    (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)),
+    (UINT16) (BiosCtlSave)
+      );
+  //
+  // Restore SMIs.
+  //
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, SmiEnSave);
+
+  return Status;
+}
+
+VOID
+SpiOffset2Physical (
+  IN      EFI_SPI_PROTOCOL  *This,
+  IN      UINTN             SpiRegionOffset,
+  IN      SPI_REGION_TYPE   SpiRegionType,
+  OUT     UINTN             *HardwareSpiAddress,
+  OUT     UINTN             *BaseAddress,
+  OUT     UINTN             *LimitAddress
+  )
+/*++
+
+Routine Description:
+
+  Convert SPI offset to Physical address of SPI hardware
+
+Arguments:
+
+  This               Pointer to the EFI_SPI_PROTOCOL instance.
+  SpiRegionOffset    In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+                     Region, this value specifies the offset from the Region Base; for BIOS Region,
+                     this value specifies the offset from the start of the BIOS Image. In Non
+                     Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+                     Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+                     Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+                     supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+                     the flash (in Non Descriptor Mode)
+  BaseAddress        Base Address of the region.
+  SpiRegionType      SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+                     EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+                     Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+                     and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+                     to base of the 1st flash device (i.e., it is a Flash Linear Address).
+  HardwareSpiAddress Return absolution SPI address (i.e., Flash Linear Address)
+  BaseAddress        Return base address of the region type
+  LimitAddress       Return limit address of the region type
+
+Returns:
+
+  EFI_SUCCESS             Command succeed.
+
+--*/
+{
+  SPI_INSTANCE  *SpiInstance;
+
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+
+  if (SpiRegionType == EnumSpiRegionAll) {
+    //
+    // EnumSpiRegionAll indicates address is relative to flash device (i.e., address is Flash
+    // Linear Address)
+    //
+    *HardwareSpiAddress = SpiRegionOffset;
+  } else {
+    //
+    // Otherwise address is relative to BIOS image
+    //
+    *HardwareSpiAddress = SpiRegionOffset + SpiInstance->SpiInitTable.BiosStartOffset;
+  }
+}
+
+EFI_STATUS
+SendSpiCmd (
+  IN     EFI_SPI_PROTOCOL   *This,
+  IN     UINT8              OpcodeIndex,
+  IN     UINT8              PrefixOpcodeIndex,
+  IN     BOOLEAN            DataCycle,
+  IN     BOOLEAN            Atomic,
+  IN     BOOLEAN            ShiftOut,
+  IN     UINTN              Address,
+  IN     UINT32             DataByteCount,
+  IN OUT UINT8              *Buffer,
+  IN     SPI_REGION_TYPE    SpiRegionType
+  )
+/*++
+
+Routine Description:
+
+  This function sends the programmed SPI command to the slave device.
+
+Arguments:
+
+  OpcodeIndex       Index of the command in the OpCode Menu.
+  PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
+  DataCycle         TRUE if the SPI cycle contains data
+  Atomic            TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+  ShiftOut          If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+  Address           In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+                    Region, this value specifies the offset from the Region Base; for BIOS Region,
+                    this value specifies the offset from the start of the BIOS Image. In Non
+                    Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+                    Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+                    Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+                    supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+                    the flash (in Non Descriptor Mode)
+  DataByteCount     Number of bytes in the data portion of the SPI cycle. This function may break the
+                    data transfer into multiple operations. This function ensures each operation does
+                    not cross 256 byte flash address boundary.
+                    *NOTE: if there is some SPI chip that has a stricter address boundary requirement
+                    (e.g., its write page size is < 256 byte), then the caller cannot rely on this
+                    function to cut the data transfer at proper address boundaries, and it's the
+                    caller's reponsibility to pass in a properly cut DataByteCount parameter.
+  Buffer            Data received or sent during the SPI cycle.
+  SpiRegionType     SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+                    EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+                    Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+                    and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+                    to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+Returns:
+
+  EFI_SUCCESS             SPI command completes successfully.
+  EFI_DEVICE_ERROR        Device error, the command aborts abnormally.
+  EFI_ACCESS_DENIED       Some unrecognized command encountered in hardware sequencing mode
+  EFI_INVALID_PARAMETER   The parameters specified are not valid.
+
+--*/
+{
+  UINT32        Index;
+  SPI_INSTANCE  *SpiInstance;
+  UINTN         HardwareSpiAddr;
+  UINTN         SpiBiosSize;
+  UINTN         BaseAddress;
+  UINTN         LimitAddress;
+  UINT32        SpiDataCount;
+  UINT8         OpCode;
+  UINTN         PchRootComplexBar;
+
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+  PchRootComplexBar = SpiInstance->PchRootComplexBar;
+  SpiBiosSize       = SpiInstance->SpiInitTable.BiosSize;
+  OpCode            = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + OpcodeIndex);
+
+  //
+  // Check if the value of opcode register is 0 or the BIOS Size of SpiInitTable is 0
+  //
+  if (OpCode == 0 || SpiBiosSize == 0) {
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SpiOffset2Physical (This, Address, SpiRegionType, &HardwareSpiAddr, &BaseAddress, &LimitAddress);
+  //
+  // Have direct access to BIOS region in Descriptor mode,
+  //
+  if (SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex].Type == EnumSpiOpcodeRead &&
+      SpiRegionType == EnumSpiRegionBios) {
+    CopyMem (
+      Buffer,
+      (UINT8 *) ((HardwareSpiAddr - BaseAddress) + (UINT32) (~(SpiBiosSize - 1))),
+      DataByteCount
+      );
+    return EFI_SUCCESS;
+  }
+  //
+  // DEBUG((EFI_D_ERROR, "SPIADDR %x, %x, %x, %x\n", Address, HardwareSpiAddr, BaseAddress,
+  // LimitAddress));
+  //
+  if ((DataCycle == FALSE) && (DataByteCount > 0)) {
+    DataByteCount = 0;
+  }
+
+  do {
+    //
+    // Trim at 256 byte boundary per operation,
+    // - PCH SPI controller requires trimming at 4KB boundary
+    // - Some SPI chips require trimming at 256 byte boundary for write operation
+    // - Trimming has limited performance impact as we can read / write atmost 64 byte
+    //   per operation
+    //
+    if (HardwareSpiAddr + DataByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 - 1))) {
+      SpiDataCount = (((UINT32) (HardwareSpiAddr) + BIT8) &~(BIT8 - 1)) - (UINT32) (HardwareSpiAddr);
+    } else {
+      SpiDataCount = DataByteCount;
+    }
+    //
+    // Calculate the number of bytes to shift in/out during the SPI data cycle.
+    // Valid settings for the number of bytes duing each data portion of the
+    // PCH SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64
+    //
+    if (SpiDataCount >= 64) {
+      SpiDataCount = 64;
+    } else if ((SpiDataCount &~0x07) != 0) {
+      SpiDataCount = SpiDataCount &~0x07;
+    }
+    //
+    // If shifts data out, load data into the SPI data buffer.
+    //
+    if (ShiftOut) {
+      for (Index = 0; Index < SpiDataCount; Index++) {
+        MmioWrite8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index, Buffer[Index]);
+        MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);
+      }
+    }
+
+    MmioWrite32 (
+      (PchRootComplexBar + R_QNC_RCRB_SPIA),
+      (UINT32) (HardwareSpiAddr & B_QNC_RCRB_SPIA_MASK)
+      );
+    MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIA);
+
+    //
+    // Execute the command on the SPI compatible mode
+    //
+
+    //
+    // Clear error flags
+    //
+    MmioOr16 ((PchRootComplexBar + R_QNC_RCRB_SPIS), B_QNC_RCRB_SPIS_BAS);
+
+    //
+    // Initialte the SPI cycle
+    //
+    if (DataCycle) {
+      MmioWrite16 (
+        (PchRootComplexBar + R_QNC_RCRB_SPIC),
+        ( (UINT16) (B_QNC_RCRB_SPIC_DC) | (UINT16) (((SpiDataCount - 1) << 8) & B_QNC_RCRB_SPIC_DBC) |
+          (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |
+          (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |
+          (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |
+          (UINT16) (B_QNC_RCRB_SPIC_SCGO)));
+    } else {
+      MmioWrite16 (
+        (PchRootComplexBar + R_QNC_RCRB_SPIC),
+        ( (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |
+          (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |
+          (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |
+          (UINT16) (B_QNC_RCRB_SPIC_SCGO)));
+    }
+
+    MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIC);
+
+    //
+    // end of command execution
+    //
+    // Wait the SPI cycle to complete.
+    //
+    if (!WaitForSpiCycleComplete (This, TRUE)) {
+      return EFI_DEVICE_ERROR;
+    }
+    //
+    // If shifts data in, get data from the SPI data buffer.
+    //
+    if (!ShiftOut) {
+      for (Index = 0; Index < SpiDataCount; Index++) {
+        Buffer[Index] = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);
+      }
+    }
+
+    HardwareSpiAddr += SpiDataCount;
+    Buffer += SpiDataCount;
+    DataByteCount -= SpiDataCount;
+  } while (DataByteCount > 0);
+
+  return EFI_SUCCESS;
+}
+
+BOOLEAN
+WaitForSpiCycleComplete (
+  IN     EFI_SPI_PROTOCOL   *This,
+  IN     BOOLEAN            ErrorCheck
+  )
+/*++
+
+Routine Description:
+
+  Wait execution cycle to complete on the SPI interface. Check both Hardware
+  and Software Sequencing status registers
+
+Arguments:
+
+  This                - The SPI protocol instance
+  UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation
+  ErrorCheck          - TRUE if the SpiCycle needs to do the error check
+
+Returns:
+
+  TRUE       SPI cycle completed on the interface.
+  FALSE      Time out while waiting the SPI cycle to complete.
+             It's not safe to program the next command on the SPI interface.
+
+--*/
+{
+  UINT64        WaitTicks;
+  UINT64        WaitCount;
+  UINT16        Data16;
+  SPI_INSTANCE  *SpiInstance;
+  UINTN         PchRootComplexBar;
+
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+  PchRootComplexBar = SpiInstance->PchRootComplexBar;
+
+  //
+  // Convert the wait period allowed into to tick count
+  //
+  WaitCount = WAIT_TIME / WAIT_PERIOD;
+
+  //
+  // Wait for the SPI cycle to complete.
+  //
+  for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) {
+    Data16 = MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS);
+    if ((Data16 & B_QNC_RCRB_SPIS_SCIP) == 0) {
+      MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIS, (B_QNC_RCRB_SPIS_BAS | B_QNC_RCRB_SPIS_CDS));
+      if ((Data16 & B_QNC_RCRB_SPIS_BAS) && (ErrorCheck == TRUE)) {
+        return FALSE;
+      } else {
+        return TRUE;
+      }
+    }
+
+    MicroSecondDelay (WAIT_PERIOD);
+  }
+
+  return FALSE;
+}
+
+EFI_STATUS
+EFIAPI
+SpiProtocolInfo (
+  IN EFI_SPI_PROTOCOL     *This,
+  OUT SPI_INIT_INFO      **InitInfoPtr
+  )
+/*++
+
+Routine Description:
+
+  Return info about SPI host controller, to help callers usage of Execute
+  service.
+
+  If 0xff is returned as an opcode index in init info struct
+  then device does not support the operation.
+
+Arguments:
+
+  This                    Pointer to the EFI_SPI_PROTOCOL instance.
+  InitInfoPtr             Pointer to init info written to this memory location.
+
+Returns:
+
+  EFI_SUCCESS             Information returned.
+  EFI_INVALID_PARAMETER   Invalid parameter.
+  EFI_NOT_READY           Required resources not setup.
+  Others                  Unexpected error happened.
+
+--*/
+{
+  SPI_INSTANCE  *SpiInstance;
+
+  if (This == NULL || InitInfoPtr == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+  if (SpiInstance->Signature != PCH_SPI_PRIVATE_DATA_SIGNATURE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!SpiInstance->InitDone) {
+    *InitInfoPtr = NULL;
+    return EFI_NOT_READY;
+  }
+  *InitInfoPtr = &SpiInstance->InitInfo;
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h
new file mode 100644
index 0000000000..1e3a50d30c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h
@@ -0,0 +1,317 @@
+/** @file
+Header file for the PCH SPI Common Driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _SPI_COMMON_H_
+#define _SPI_COMMON_H_
+
+#include "Protocol/Spi.h"
+#include <Library/PciLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IntelQNCLib.h>
+#include <Library/QNCAccessLib.h>
+#include <Uefi/UefiBaseType.h>
+
+//
+// Maximum time allowed while waiting the SPI cycle to complete
+//  Wait Time = 6 seconds = 6000000 microseconds
+//  Wait Period = 10 microseconds
+//
+#define WAIT_TIME   6000000
+#define WAIT_PERIOD 10
+//
+// PCH Required SPI Commands -------- COMMAND SET I ------------
+// SPI flash device must support in order to be compatible with PCH
+//
+#define PCH_SPI_COMMAND_PROGRAM_BYTE          0x02
+#define PCH_SPI_COMMAND_READ_DATA             0x03
+#define PCH_SPI_COMMAND_WRITE_DISABLE         0x04
+#define PCH_SPI_COMMAND_READ_STATUS           0x05
+#define PCH_SPI_COMMAND_WRITE_ENABLE          0x06
+#define PCH_SPI_COMMAND_FAST_READ             0x0B
+#define PCH_SPI_COMMAND_READ_ID               0x9F
+#define PCH_SPI_COMMAND_DUAL_FAST_READ        0x3B  // Dual Output Fast Read
+
+//
+// Need to support at least one of the following two kinds of size of sector for erasing
+//
+#define PCH_SPI_COMMAND_4KB_ERASE   0x20
+#define PCH_SPI_COMMAND_64KB_ERASE  0xD8
+//
+// Recommended SPI Commands -------- COMMAND SET II ------------
+// SPI flash device best to support
+//
+#define PCH_SPI_COMMAND_WRITE_STATUS    0x01
+#define PCH_SPI_COMMAND_FULL_CHIP_ERASE 0xC7
+
+//
+// Private data structure definitions for the driver
+//
+#define PCH_SPI_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('P', 'S', 'P', 'I')
+
+typedef struct {
+  UINTN             Signature;
+  EFI_HANDLE        Handle;
+  EFI_SPI_PROTOCOL  SpiProtocol;
+  SPI_INIT_TABLE    SpiInitTable;
+  UINTN             PchRootComplexBar;
+  BOOLEAN           InitDone; // Set to TRUE on SpiProtocolInit SUCCESS.
+  SPI_INIT_INFO     InitInfo;
+} SPI_INSTANCE;
+
+#define SPI_INSTANCE_FROM_SPIPROTOCOL(a)  CR (a, SPI_INSTANCE, SpiProtocol, PCH_SPI_PRIVATE_DATA_SIGNATURE)
+
+//
+// Function prototypes used by the SPI protocol.
+//
+EFI_STATUS
+SpiProtocolConstructor (
+  SPI_INSTANCE          *SpiInstance
+  )
+/*++
+
+Routine Description:
+
+  Initialize an SPI protocol instance.
+  The function will assert in debug if PCH RCBA has not been initialized
+
+Arguments:
+
+  SpiInstance   - Pointer to SpiInstance to initialize
+
+Returns:
+
+  EFI_SUCCESS     The protocol instance was properly initialized
+  EFI_UNSUPPORTED The PCH is not supported by this module
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SpiProtocolInit (
+  IN EFI_SPI_PROTOCOL       *This,
+  IN SPI_INIT_TABLE         *InitTable
+  )
+/*++
+
+Routine Description:
+
+  Initialize the host controller to execute SPI command.
+
+Arguments:
+
+  This                    Pointer to the EFI_SPI_PROTOCOL instance.
+  InitTable               Initialization data to be programmed into the SPI host controller.
+
+Returns:
+
+  EFI_SUCCESS             Initialization completed.
+  EFI_ACCESS_DENIED       The SPI static configuration interface has been locked-down.
+  EFI_INVALID_PARAMETER   Bad input parameters.
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SpiProtocolLock (
+  IN EFI_SPI_PROTOCOL       *This
+  )
+/*++
+
+Routine Description:
+
+  Lock the SPI Static Configuration Interface.
+  Once locked, the interface can not be changed and can only be clear by system reset.
+
+Arguments:
+
+  This      Pointer to the EFI_SPI_PROTOCOL instance.
+
+Returns:
+
+  EFI_SUCCESS             Lock operation succeed.
+  EFI_DEVICE_ERROR        Device error, operation failed.
+  EFI_ACCESS_DENIED       The interface has already been locked.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SpiProtocolExecute (
+  IN     EFI_SPI_PROTOCOL   *This,
+  IN     UINT8              OpcodeIndex,
+  IN     UINT8              PrefixOpcodeIndex,
+  IN     BOOLEAN            DataCycle,
+  IN     BOOLEAN            Atomic,
+  IN     BOOLEAN            ShiftOut,
+  IN     UINTN              Address,
+  IN     UINT32             DataByteCount,
+  IN OUT UINT8              *Buffer,
+  IN     SPI_REGION_TYPE    SpiRegionType
+  )
+/*++
+
+Routine Description:
+
+  Execute SPI commands from the host controller.
+
+Arguments:
+
+  This                    Pointer to the EFI_SPI_PROTOCOL instance.
+  OpcodeIndex             Index of the command in the OpCode Menu.
+  PrefixOpcodeIndex       Index of the first command to run when in an atomic cycle sequence.
+  DataCycle               TRUE if the SPI cycle contains data
+  Atomic                  TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+  ShiftOut                If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+  Address                 In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+                          Region, this value specifies the offset from the Region Base; for BIOS Region,
+                          this value specifies the offset from the start of the BIOS Image. In Non
+                          Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+                          Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+                          Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+                          supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+                          the flash (in Non Descriptor Mode)
+  DataByteCount           Number of bytes in the data portion of the SPI cycle.
+  Buffer                  Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle.
+  SpiRegionType           SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+                          EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+                          Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+                          and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+                          to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+Returns:
+
+  EFI_SUCCESS             Command succeed.
+  EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  EFI_UNSUPPORTED         Command not supported.
+  EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+--*/
+;
+
+EFI_STATUS
+SendSpiCmd (
+  IN     EFI_SPI_PROTOCOL   *This,
+  IN     UINT8              OpcodeIndex,
+  IN     UINT8              PrefixOpcodeIndex,
+  IN     BOOLEAN            DataCycle,
+  IN     BOOLEAN            Atomic,
+  IN     BOOLEAN            ShiftOut,
+  IN     UINTN              Address,
+  IN     UINT32             DataByteCount,
+  IN OUT UINT8              *Buffer,
+  IN     SPI_REGION_TYPE    SpiRegionType
+  )
+/*++
+
+Routine Description:
+
+  This function sends the programmed SPI command to the slave device.
+
+Arguments:
+
+  OpcodeIndex       Index of the command in the OpCode Menu.
+  PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
+  DataCycle         TRUE if the SPI cycle contains data
+  Atomic            TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+  ShiftOut          If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+  Address           In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+                    Region, this value specifies the offset from the Region Base; for BIOS Region,
+                    this value specifies the offset from the start of the BIOS Image. In Non
+                    Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+                    Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+                    Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+                    supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+                    the flash (in Non Descriptor Mode)
+  DataByteCount     Number of bytes in the data portion of the SPI cycle. This function may break the
+                    data transfer into multiple operations. This function ensures each operation does
+                    not cross 256 byte flash address boundary.
+                    *NOTE: if there is some SPI chip that has a stricter address boundary requirement
+                    (e.g., its write page size is < 256 byte), then the caller cannot rely on this
+                    function to cut the data transfer at proper address boundaries, and it's the
+                    caller's reponsibility to pass in a properly cut DataByteCount parameter.
+  Buffer            Data received or sent during the SPI cycle.
+  SpiRegionType     SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+                    EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+                    Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+                    and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+                    to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+Returns:
+
+  EFI_SUCCESS             SPI command completes successfully.
+  EFI_DEVICE_ERROR        Device error, the command aborts abnormally.
+  EFI_ACCESS_DENIED       Some unrecognized command encountered in hardware sequencing mode
+  EFI_INVALID_PARAMETER   The parameters specified are not valid.
+
+--*/
+;
+
+BOOLEAN
+WaitForSpiCycleComplete (
+  IN     EFI_SPI_PROTOCOL   *This,
+  IN     BOOLEAN            ErrorCheck
+  )
+/*++
+
+Routine Description:
+
+  Wait execution cycle to complete on the SPI interface. Check both Hardware
+  and Software Sequencing status registers
+
+Arguments:
+
+  This                - The SPI protocol instance
+  UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation
+  ErrorCheck          - TRUE if the SpiCycle needs to do the error check
+
+Returns:
+
+  TRUE       SPI cycle completed on the interface.
+  FALSE      Time out while waiting the SPI cycle to complete.
+             It's not safe to program the next command on the SPI interface.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SpiProtocolInfo (
+  IN EFI_SPI_PROTOCOL     *This,
+  OUT SPI_INIT_INFO      **InitInfoPtr
+  )
+/*++
+
+Routine Description:
+
+  Return info about SPI host controller, to help callers usage of Execute
+  service.
+
+  If 0xff is returned as an opcode index in init info struct
+  then device does not support the operation.
+
+Arguments:
+
+  This                    Pointer to the EFI_SPI_PROTOCOL instance.
+  InitInfoPtr             Pointer to init info written to this memory location.
+
+Returns:
+
+  EFI_SUCCESS             Information returned.
+  EFI_INVALID_PARAMETER   Invalid parameter.
+  EFI_NOT_READY           Required resources not setup.
+  Others                  Unexpected error happened.
+
+--*/
+;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf
new file mode 100644
index 0000000000..c20c12c91d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf
@@ -0,0 +1,84 @@
+## @file
+#    Component description file for the SPI Runtime driver.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PchSpiRuntime
+  FILE_GUID                      = C194C6EA-B68C-4981-B64B-9BD271474B20
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = InstallPchSpi
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+################################################################################
+#
+# Sources Section - list of files that are required for the build to succeed.
+#
+################################################################################
+[Sources]
+  RuntimeDxe/PchSpi.h
+  RuntimeDxe/PchSpi.c
+  Common/SpiCommon.c
+  Common/SpiCommon.h
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+#                              this module.
+#
+################################################################################
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+################################################################################
+#
+# Library Class Section - list of Library Classes that are required for
+#                         this module.
+#
+################################################################################
+[LibraryClasses]
+  UefiRuntimeServicesTableLib
+  UefiRuntimeLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  IntelQNCLib
+  QNCAccessLib
+  TimerLib
+  DxeServicesTableLib
+  UefiLib
+  DebugLib
+  MemoryAllocationLib
+  S3BootScriptLib
+  PciExpressLib
+
+################################################################################
+#
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names
+#                           that this module uses or produces.
+#
+################################################################################
+[Protocols]
+  gEfiSpiProtocolGuid
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioSize
+
+[Depex]
+  TRUE
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf
new file mode 100644
index 0000000000..13b2f77e0a
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf
@@ -0,0 +1,50 @@
+## @file
+# Spi smm driver
+#
+# Component description file for the SPI SMM driver.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[defines]
+  INF_VERSION                 = 0x00010005
+  BASE_NAME                       = PchSpiSmm
+  FILE_GUID                       = 27F4917B-A707-4aad-9676-26DF168CBF0D
+  MODULE_TYPE                     = DXE_SMM_DRIVER
+  VERSION_STRING                  = 1.0
+  PI_SPECIFICATION_VERSION        = 0x0001000A
+  ENTRY_POINT                     = InstallPchSpi
+
+[Sources]
+  Smm/PchSpi.h
+  Smm/PchSpi.c
+  Common/SpiCommon.c
+  Common/SpiCommon.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  IoLib
+  IntelQNCLib
+  QNCAccessLib
+  TimerLib
+  S3BootScriptLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  BaseLib
+  SmmServicesTableLib
+
+[Protocols]
+  gEfiSmmSpiProtocolGuid      # PRODUCES
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+
+[Depex]
+  gEfiSmmBase2ProtocolGuid
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c
new file mode 100644
index 0000000000..393d60b29e
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c
@@ -0,0 +1,205 @@
+/** @file
+PCH SPI Runtime Driver implements the SPI Host Controller Compatibility Interface.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "PchSpi.h"
+
+extern EFI_GUID gEfiEventVirtualAddressChangeGuid;
+
+//
+// Global variables
+//
+SPI_INSTANCE  *mSpiInstance;
+CONST UINT32 mSpiRegister[] = {
+  R_QNC_RCRB_SPIS,
+  R_QNC_RCRB_SPIPREOP,
+  R_QNC_RCRB_SPIOPMENU,
+  R_QNC_RCRB_SPIOPMENU + 4
+  };
+
+//
+// Function implementations
+//
+VOID
+PchSpiVirtualddressChangeEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+/*++
+
+Routine Description:
+
+  Fixup internal data pointers so that the services can be called in virtual mode.
+
+Arguments:
+
+  Event     The event registered.
+  Context   Event context. Not used in this event handler.
+
+Returns:
+
+  None.
+
+--*/
+{
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->PchRootComplexBar));
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Init));
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Lock));
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Execute));
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance));
+}
+
+EFI_STATUS
+EFIAPI
+InstallPchSpi (
+  IN EFI_HANDLE            ImageHandle,
+  IN EFI_SYSTEM_TABLE      *SystemTable
+  )
+/*++
+
+Routine Description:
+
+  Entry point for the SPI host controller driver.
+
+Arguments:
+
+  ImageHandle       Image handle of this driver.
+  SystemTable       Global system service table.
+
+Returns:
+
+  EFI_SUCCESS           Initialization complete.
+  EFI_UNSUPPORTED       The chipset is unsupported by this driver.
+  EFI_OUT_OF_RESOURCES  Do not have enough resources to initialize the driver.
+  EFI_DEVICE_ERROR      Device error, driver exits abnormally.
+
+--*/
+{
+  EFI_STATUS                      Status;
+  UINT64                          BaseAddress;
+  UINT64                          Length;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdMemorySpaceDescriptor;
+  UINT64                          Attributes;
+  EFI_EVENT                       Event;
+
+  DEBUG ((DEBUG_INFO, "InstallPchSpi() Start\n"));
+
+  //
+  // Allocate Runtime memory for the SPI protocol instance.
+  //
+  mSpiInstance = AllocateRuntimeZeroPool (sizeof (SPI_INSTANCE));
+  if (mSpiInstance == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  //
+  // Initialize the SPI protocol instance
+  //
+  Status = SpiProtocolConstructor (mSpiInstance);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Install the EFI_SPI_PROTOCOL interface
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &(mSpiInstance->Handle),
+                  &gEfiSpiProtocolGuid,
+                  &(mSpiInstance->SpiProtocol),
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    FreePool (mSpiInstance);
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Set RCBA space in GCD to be RUNTIME so that the range will be supported in
+  // virtual address mode in EFI aware OS runtime.
+  // It will assert if RCBA Memory Space is not allocated
+  // The caller is responsible for the existence and allocation of the RCBA Memory Spaces
+  //
+  BaseAddress = (EFI_PHYSICAL_ADDRESS) (mSpiInstance->PchRootComplexBar);
+  Length      = PcdGet64 (PcdRcbaMmioSize);
+
+  Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdMemorySpaceDescriptor);
+  ASSERT_EFI_ERROR (Status);
+
+  Attributes = GcdMemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;
+
+  Status = gDS->AddMemorySpace (
+                  EfiGcdMemoryTypeMemoryMappedIo,
+                  BaseAddress,
+                  Length,
+                  EFI_MEMORY_RUNTIME | EFI_MEMORY_UC
+                  );
+  ASSERT_EFI_ERROR(Status);
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  BaseAddress,
+                  Length,
+                  Attributes
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  PchSpiVirtualddressChangeEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &Event
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  DEBUG ((DEBUG_INFO, "InstallPchSpi() End\n"));
+
+  return EFI_SUCCESS;
+}
+
+VOID
+EFIAPI
+SpiPhaseInit (
+  VOID
+  )
+/*++
+Routine Description:
+
+  This function is a a hook for Spi Dxe phase specific initialization
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  UINTN  Index;
+
+  //
+  // Disable SMM BIOS write protect if it's not a SMM protocol
+  //
+  MmioAnd8 (
+    PciDeviceMmBase (PCI_BUS_NUMBER_QNC,
+    PCI_DEVICE_NUMBER_QNC_LPC,
+    PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_BIOS_CNTL,
+    (UINT8) (~B_QNC_LPC_BIOS_CNTL_SMM_BWP)
+    );
+
+    //
+    // Save SPI Registers for S3 resume usage
+    //
+    for (Index = 0; Index < sizeof (mSpiRegister) / sizeof (UINT32); Index++) {
+    S3BootScriptSaveMemWrite (
+      S3BootScriptWidthUint32,
+        (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]),
+        1,
+        (VOID *) (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index])
+        );
+    }
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h
new file mode 100644
index 0000000000..33d64297f5
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h
@@ -0,0 +1,79 @@
+/** @file
+Header file for the PCH SPI Runtime Driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCH_SPI_H_
+#define _PCH_SPI_H_
+
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/Spi.h>
+#include "SpiCommon.h"
+#include <Library/PciExpressLib.h>
+#include <IntelQNCRegs.h>
+#include <Library/IntelQNCLib.h>
+#include <Library/QNCAccessLib.h>
+#include <Library/TimerLib.h>
+
+#define EFI_INTERNAL_POINTER  0x00000004
+
+
+//
+// Function prototypes used by the SPI protocol.
+//
+VOID
+PchSpiVirtualddressChangeEvent (
+  IN EFI_EVENT              Event,
+  IN VOID                   *Context
+  )
+/*++
+
+Routine Description:
+
+  Fixup internal data pointers so that the services can be called in virtual mode.
+
+Arguments:
+
+  Event     The event registered.
+  Context   Event context. Not used in this event handler.
+
+Returns:
+
+  None.
+
+--*/
+;
+
+VOID
+EFIAPI
+SpiPhaseInit (
+  VOID
+  )
+/*++
+Routine Description:
+
+  This function is a hook for Spi Dxe phase specific initialization
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+;
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c
new file mode 100644
index 0000000000..fe5cde3de7
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c
@@ -0,0 +1,123 @@
+/** @file
+
+PCH SPI SMM Driver implements the SPI Host Controller Compatibility Interface.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+#include "PchSpi.h"
+
+SPI_INSTANCE          *mSpiInstance;
+
+CONST UINT32  mSpiRegister[] = {
+    R_QNC_RCRB_SPIS,
+    R_QNC_RCRB_SPIPREOP,
+    R_QNC_RCRB_SPIOPMENU,
+    R_QNC_RCRB_SPIOPMENU + 4
+  };
+
+EFI_STATUS
+EFIAPI
+InstallPchSpi (
+  IN EFI_HANDLE            ImageHandle,
+  IN EFI_SYSTEM_TABLE      *SystemTable
+  )
+/*++
+
+Routine Description:
+
+  Entry point for the SPI host controller driver.
+
+Arguments:
+
+  ImageHandle       Image handle of this driver.
+  SystemTable       Global system service table.
+
+Returns:
+
+  EFI_SUCCESS           Initialization complete.
+  EFI_UNSUPPORTED       The chipset is unsupported by this driver.
+  EFI_OUT_OF_RESOURCES  Do not have enough resources to initialize the driver.
+  EFI_DEVICE_ERROR      Device error, driver exits abnormally.
+
+--*/
+{
+  EFI_STATUS    Status;
+
+  //
+  // Allocate pool for SPI protocol instance
+  //
+  Status = gSmst->SmmAllocatePool (
+                    EfiRuntimeServicesData, // MemoryType don't care
+                    sizeof (SPI_INSTANCE),
+                    (VOID **) &mSpiInstance
+                    );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (mSpiInstance == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ZeroMem ((VOID *) mSpiInstance, sizeof (SPI_INSTANCE));
+  //
+  // Initialize the SPI protocol instance
+  //
+  Status = SpiProtocolConstructor (mSpiInstance);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Install the SMM EFI_SPI_PROTOCOL interface
+  //
+  Status = gSmst->SmmInstallProtocolInterface (
+            &(mSpiInstance->Handle),
+            &gEfiSmmSpiProtocolGuid,
+            EFI_NATIVE_INTERFACE,
+            &(mSpiInstance->SpiProtocol)
+            );
+  if (EFI_ERROR (Status)) {
+    gSmst->SmmFreePool (mSpiInstance);
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+VOID
+EFIAPI
+SpiPhaseInit (
+  VOID
+  )
+/*++
+Routine Description:
+
+  This function is a a hook for Spi Smm phase specific initialization
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  UINTN  Index;
+
+  //
+  // Save SPI Registers for S3 resume usage
+  //
+  for (Index = 0; Index < sizeof (mSpiRegister) / sizeof (UINT32); Index++) {
+    S3BootScriptSaveMemWrite (
+      S3BootScriptWidthUint32,
+      (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]),
+      1,
+      (VOID *) (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index])
+      );
+  }
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h
new file mode 100644
index 0000000000..a016a0e7c4
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h
@@ -0,0 +1,47 @@
+/** @file
+Header file for the PCH SPI SMM Driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PCH_SPI_H_
+#define _PCH_SPI_H_
+
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Protocol/Spi.h>
+#include "SpiCommon.h"
+#include <Library/SmmServicesTableLib.h>
+#include <IntelQNCRegs.h>
+#include <Library/IntelQNCLib.h>
+#include <Library/QNCAccessLib.h>
+#include <Library/TimerLib.h>
+
+VOID
+EFIAPI
+SpiPhaseInit (
+  VOID
+  )
+/*++
+Routine Description:
+
+  This function is a hook for Spi Smm phase specific initialization
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+;
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec b/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec
new file mode 100644
index 0000000000..22cb0a2d79
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec
@@ -0,0 +1,234 @@
+## @file
+# INTEL Quark SoC Module Package Reference Implementations
+#
+# This Module provides FRAMEWORK reference implementation for INTEL Quark SoC.
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+
+[Defines]
+  DEC_SPECIFICATION              = 0x00010005
+  PACKAGE_NAME                   = QuarkSocPkg
+  PACKAGE_GUID                   = 28DECF17-6C75-448f-87DC-BDE4BD579919
+  PACKAGE_VERSION                = 0.1
+
+
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+#                   Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+#  SEC PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER BASE
+#
+################################################################################
+[Includes]
+  #
+  # North Cluster
+  #
+  QuarkNorthCluster/Include
+  QuarkNorthCluster/MemoryInit/Pei
+
+  #
+  # South Cluster
+  #
+  QuarkSouthCluster/Include
+
+################################################################################
+#
+# Library Class Header section - list of Library Class header files that are
+#                                provided by this package.
+#
+################################################################################
+[LibraryClasses]
+  #
+  # North Cluster
+  #
+  QNCAccessLib|QuarkNorthCluster/Include/Library/QNCAccessLib.h
+  IntelQNCLib|QuarkNorthCluster/Include/Library/IntelQNCLib.h
+  IohLib|QuarkSouthCluster/Include/Library/IohLib.h
+  I2cLib|QuarkSouthCluster/Include/Library/I2cLib.h
+
+################################################################################
+#
+# Global Guid Definition section - list of Global Guid C Name Data Structures
+#                                  that are provided by this package.
+#
+################################################################################
+[Guids]
+  #
+  # North Cluster
+  #
+  gEfiQuarkNcSocIdTokenSpaceGuid  = { 0xca452c6a, 0xdf0c, 0x4dc9, { 0x82, 0xfb, 0xea, 0xe2, 0xab, 0x31, 0x29, 0x46 }}
+  gQncS3CodeInLockBoxGuid   =  { 0x1f18c5b3, 0x29ed, 0x4d9e, {0xa5, 0x4, 0x6d, 0x97, 0x8e, 0x7e, 0xd5, 0x69}}
+  gQncS3ContextInLockBoxGuid = { 0xe5769ea9, 0xe706, 0x454b, {0x95, 0x7f, 0xaf, 0xc6, 0xdb, 0x4b, 0x8a, 0xd}}
+
+  #
+  # South Cluster
+  #
+  gEfiQuarkSCSocIdTokenSpaceGuid  = { 0xef251b71, 0xceed, 0x484e, { 0x82, 0xe3, 0x3a, 0x1f, 0x34, 0xf5, 0x12, 0xe2 }}
+
+################################################################################
+#
+# Global Ppi Definition section - list of Global Ppi C Name Data Structures
+#                                  that are provided by this package.
+#
+################################################################################
+[Ppis]
+  #
+  # North Cluster
+  #
+  gQNCMemoryInitPpiGuid = { 0x21ff1fee, 0xd33a, 0x4fce, { 0xa6, 0x5e, 0x95, 0x5e, 0xa3, 0xc4, 0x1f, 0x40}}
+
+################################################################################
+#
+# Global Protocols Definition section - list of Global Protocols C Name Data
+#                                  Structures that are provided by this package.
+#
+################################################################################
+[Protocols]
+  #
+  # North Cluster
+  #
+  gEfiPlatformPolicyProtocolGuid = { 0x2977064F, 0xAB96, 0x4FA9, { 0x85, 0x45, 0xF9, 0xC4, 0x02, 0x51, 0xE0, 0x7F }}
+  gEfiSmmIchnDispatch2ProtocolGuid = { 0xadf3a128, 0x416d, 0x4060, { 0x8d, 0xdf, 0x30, 0xa1, 0xd7, 0xaa, 0xb6, 0x99 }}
+  gEfiSpiProtocolGuid = { 0x1156efc6, 0xea32, 0x4396, { 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 }}
+  gEfiSmmSpiProtocolGuid  = { 0xD9072C35, 0xEB8F, 0x43ad, { 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 }}
+  gEfiQncS3SupportProtocolGuid  = { 0xe287d20b, 0xd897, 0x4e1e, { 0xa5, 0xd9, 0x97, 0x77, 0x63, 0x93, 0x6a, 0x4 }}
+
+  #
+  # South Cluster
+  #
+  gEfiSDHostIoProtocolGuid = {0xb63f8ec7, 0xa9c9, 0x4472, {0xa4, 0xc0, 0x4d, 0x8b, 0xf3, 0x65, 0xcc, 0x51}}
+
+################################################################################
+#
+# PCD Declarations section - list of all PCDs Declared by this Package
+#                            Only this package should be providing the
+#                            declaration, other packages should not.
+#
+################################################################################
+
+[PcdsFeatureFlag]
+  #
+  # North Cluster
+  #
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed|TRUE|BOOLEAN|0x10000001
+
+  #
+  # South Cluster
+  #
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdEhciRecoveryEnabled|FALSE|BOOLEAN|0x10000003
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdI2CFastModeEnabled|FALSE|BOOLEAN|0x10000005
+
+  #
+  # Feature Flag equivalent to linux SDHCI_QUIRK_NO_HISPD_BIT to stop
+  # setting of SD HCI hi_spd_en bit in HOST_CTL register.
+  #
+  # Alway TRUE ie high speed enable bit must never
+  # be set so we stay within SD interface Setup/Hold time.
+  #
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdSdHciQuirkNoHiSpd|TRUE|BOOLEAN|0x10000004
+
+[PcdsFixedAtBuild]
+  #
+  # North Cluster
+  #
+
+  # Values of Io Port Base Address, MMIO base address and space size.
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress|0x1000|UINT16|0x10000200
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoBaseAddress|0x1010|UINT16|0x10000201
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoLVL2|0x1014|UINT16|0x10000202
+
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress|0x1080|UINT16|0x10000205
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress|0x1100|UINT16|0x10000206
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress|0x1040|UINT16|0x10000207
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdWdtbaIoBaseAddress|0x1140|UINT16|0x10000209
+
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioBaseAddress|0xFED1C000|UINT64|0x1000020B
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicBaseAddress|0xFEC00000|UINT64|0x1000020C
+
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicSize|0x1000|UINT64|0x1000020D
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioSize|0x4000|UINT64|0x1000020E
+
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciExpressSize|0x02000000|UINT64|0x1000020F
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetBaseAddress|0xFED00000|UINT64|0x10000210
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetSize|0x400|UINT64|0x10000211
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdTSegSize|0x200000|UINT32|0x10000212
+
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeIoBase|0x2000|UINT16|0x10000214
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeIoSize|0xE000|UINT16|0x10000215
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory32Base|0x90000000|UINT32|0x1000021B
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory32Size|0x20000000|UINT32|0x1000021C
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory64Base|0xB0000000|UINT64|0x1000021D
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory64Size|0x30000000|UINT64|0x1000021E
+
+  # Values for programming Interrupt Route Configuration Registers:
+  # Indicates which interrupt routing is connected to the INTA/B/C/D pins reported in the
+  # "DxIP" register fields. This will be the internal routing, the device interrupt is connected
+  # to the interrupt controller.
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent0IR|0x0000|UINT16|0x10000223
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent1IR|0x7654|UINT16|0x10000224
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent2IR|0x0000|UINT16|0x10000225
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent3IR|0x3210|UINT16|0x10000226
+
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort|0xb2|UINT16|0x10000232
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort|0xb3|UINT16|0x10000233
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationData|0x55|UINT8|0x10000234
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrNum|0x0|UINT32|0x10000235
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrTable|0x0|UINT64|0x10000236
+
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdESramMemorySize|0x00080000|UINT32|0x10000240
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables|0x03|UINT32|0x10000237
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPcieRootPortConfiguration|{0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00}|VOID*|0x10000239
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkMicrocodeFile |{ 0x8B, 0xEA, 0x5E, 0xD7, 0xD2, 0x23, 0xD4, 0x4E, 0xBC, 0x4F, 0x57, 0x51, 0xD4, 0xA1, 0x8D, 0xCF }|VOID*|0x1000023A
+
+  #
+  # South Cluster
+  #
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohI2cMmioBase|0xA001F000|UINT64|0x20000005
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiP2PMemoryBaseAddress|0xA0000000|UINT32|0x20000006
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiQNCUsbControllerMemoryBaseAddress|0xA0010000|UINT32|0x20000007
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioMmioBase|0xA0020000|UINT64|0x20000008
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohMac0MmioBase|0xA0024000|UINT64|0x20000009
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohMac1MmioBase|0xA0028000|UINT64|0x2000000A
+
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartBusNumber|0x00|UINT8|0x20000013
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartDevNumber|0x14|UINT8|0x20000014
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartFunctionNumber|0x5|UINT8|0x20000001
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber|0x00|UINT8|0x20000029
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioDevNumber|0x15|UINT8|0x2000002A
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioFunctionNumber|0x2|UINT8|0x2000002B
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBarRegister|0x14|UINT8|0x2000002D
+
+[PcdsDynamic, PcdsDynamicEx]
+  #
+  # North Cluster
+  #
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxAddress|0|UINT64|0x30000026
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxSize|0|UINT64|0x30000027
+
+  ## Intel(R) Quark(TM) Soc X1000 processor MRC Parameters.  Default is for Galileo Gen 2 platform.<BR><BR>
+  # @Prompt Intel(R) Quark(TM) Soc X1000 processor MRC Parameters.
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdMrcParameters|{0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x7c, 0x92, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x40, 0x9c, 0x00, 0x00, 0x06}|VOID*|0x40000001
+
+  #
+  # South Cluster
+  #
+  ## MAC0 address for the Ethernet Controller in Intel(R) Quark(TM) Soc X1000 processor.  Default is 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff.<BR><BR>
+  # @Prompt Ethernet MAC 0 Address.
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohEthernetMac0|{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}|VOID*|0x50000001
+
+  ## MAC1 address for the Ethernet Controller in Intel(R) Quark(TM) Soc X1000 processor.  Default is 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff.<BR><BR>
+  # @Prompt Ethernet MAC 1 Address.
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohEthernetMac1|{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}|VOID*|0x50000002
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc b/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc
new file mode 100644
index 0000000000..e743a5e272
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc
@@ -0,0 +1,254 @@
+## @file
+# INTEL Quark SoC Module Package Reference Implementations
+#
+# This DSC file is used for Package Level build.
+#
+# This Module provides FRAMEWORK reference implementation for INTEL Quark SoC.
+#   Copyright (c) 2013-2016 Intel Corporation.
+#
+#   SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+  PLATFORM_NAME                  = QuarkSocPkg
+  PLATFORM_GUID                  = 5F9864F4-EAFB-4ded-A41A-CA501EE50502
+  PLATFORM_VERSION               = 0.1
+  DSC_SPECIFICATION              = 0x00010005
+  OUTPUT_DIRECTORY               = Build/QuarkSocPkg
+  SUPPORTED_ARCHITECTURES        = IA32
+  BUILD_TARGETS                  = DEBUG|RELEASE
+  SKUID_IDENTIFIER               = DEFAULT
+
+################################################################################
+#
+# SKU Identification section - list of all SKU IDs supported by this
+#                              Platform.
+#
+################################################################################
+[SkuIds]
+  0|DEFAULT              # The entry: 0|DEFAULT is reserved and always required.
+
+################################################################################
+#
+# Library Class section - list of all Library Classes needed by this Platform.
+#
+################################################################################
+[LibraryClasses]
+  #
+  # Entry point
+  #
+  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+  #
+  # Basic
+  #
+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+  BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf
+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+  CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
+  IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+  PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+  PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
+  PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf
+  CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
+  PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+!if $(CFG_SOURCE_DEBUG) == 1
+  PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
+!else
+  PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
+!endif
+  #
+  # UEFI & PI
+  #
+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+  UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+  PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
+  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+  DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+  DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
+  UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
+  #
+  # Framework
+  #
+  S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
+  S3IoLib|MdePkg/Library/BaseS3IoLib/BaseS3IoLib.inf
+  S3PciLib|MdePkg/Library/BaseS3PciLib/BaseS3PciLib.inf
+  #
+  # Generic Modules
+  #
+  OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
+
+  #
+  # CPU
+  #
+  MtrrLib|QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf
+  #
+  # Quark North Cluster
+  #
+  SmmLib|QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf
+  SmbusLib|QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf
+  TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
+  ResetSystemLib|QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf
+  IntelQNCLib|QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf
+  QNCAccessLib|QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf
+  #
+  # Quark South Cluster
+  #
+  IohLib|QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf
+  SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
+  PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
+  #
+  # Misc
+  #
+  DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
+  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+  PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+!if $(CFG_SOURCE_DEBUG) == TRUE
+  DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf
+!else
+  DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+!endif
+
+[LibraryClasses.IA32.PEIM,LibraryClasses.IA32.PEI_CORE]
+  #
+  # SEC and PEI phase common
+  #
+  PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
+  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+  MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+  ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+  LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
+  PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
+!if $(CFG_SOURCE_DEBUG) == TRUE
+  DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf
+!endif
+  TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
+
+[LibraryClasses.IA32.SEC]
+  #
+  # SEC specific phase
+  #
+  ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
+
+[LibraryClasses.IA32]
+  #
+  # DXE phase common
+  #
+  PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+  HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+  LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
+!if $(CFG_SOURCE_DEBUG) == 1
+  DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
+!endif
+
+[LibraryClasses.IA32.DXE_SMM_DRIVER]
+  SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf
+  ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
+  MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf
+  LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
+!if $(CFG_SOURCE_DEBUG) == TRUE
+  DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
+!endif
+
+[LibraryClasses.IA32.SMM_CORE]
+  ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
+
+[LibraryClasses.IA32.DXE_RUNTIME_DRIVER]
+  ReportStatusCodeLib|MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
+
+[LibraryClasses.IA32.UEFI_DRIVER,LibraryClasses.IA32.UEFI_APPLICATION]
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+
+[PcdsFixedAtBuild]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl|0x03
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl|0x07
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable|FALSE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|44236800
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0x14, 0x05, 0x84, 0x00, 0xFF}
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride|4
+
+  gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber           |0
+  gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber        |31
+  gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber      |0
+  gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset|0x4b
+  gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask          |0x80
+  gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset   |0x48
+  gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress        |0x1000
+  gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset             |0x0008
+
+[PcdsFeatureFlag]
+
+################################################################################
+#
+# Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+
+[PcdsDynamicDefault.common.DEFAULT]
+
+###################################################################################################
+#
+# Components Section - list of the modules and components that will be processed by compilation
+#                      tools and the EDK II tools to generate PE32/PE32+/Coff image files.
+#
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
+#       into firmware volume images. This section is just a list of modules to compile from
+#       source into UEFI-compliant binaries.
+#       It is the FDF file that contains information on combining binary files into firmware
+#       volume images, whose concept is beyond UEFI and is described in PI specification.
+#       Binary modules do not need to be listed in this section, as they should be
+#       specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
+#       Logo (Logo.bmp), and etc.
+#       There may also be modules listed in this section that are not required in the FDF file,
+#       When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
+#       generated for it, but the binary will not be put into any firmware volume.
+#
+###################################################################################################
+
+[Components]
+  QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf
+  QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf
+  QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf
+  QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf
+  QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf
+  QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf {
+    <LibraryClasses>
+      PciExpressLib|MdePkg/Library/DxeRuntimePciExpressLib/DxeRuntimePciExpressLib.inf
+  }
+  QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf
+  QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf {
+    <LibraryClasses>
+      DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+      PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+  }
+  QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf
+  QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf
+
+  QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf
+  QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf
+  QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf
+  QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf
+  QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf
+  QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h
new file mode 100644
index 0000000000..f038c34238
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h
@@ -0,0 +1,114 @@
+/** @file
+
+Header file for chipset CE-AT spec.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CE_ATA_H
+#define _CE_ATA_H
+
+#pragma pack(1)
+
+
+#define  DATA_UNIT_SIZE       512
+
+
+#define  CMD60                60
+#define  CMD61                61
+
+
+#define RW_MULTIPLE_REGISTER  CMD60
+#define RW_MULTIPLE_BLOCK     CMD61
+
+
+#define CE_ATA_SIG_CE         0xCE
+#define CE_ATA_SIG_AA         0xAA
+
+
+#define Reg_Features_Exp      01
+#define Reg_SectorCount_Exp   02
+#define Reg_LBALow_Exp        03
+#define Reg_LBAMid_Exp        04
+#define Reg_LBAHigh_Exp       05
+#define Reg_Control           06
+#define Reg_Features_Error    09
+#define Reg_SectorCount       10
+#define Reg_LBALow            11
+#define Reg_LBAMid            12
+#define Reg_LBAHigh           13
+#define Reg_Device_Head       14
+#define Reg_Command_Status    15
+
+#define Reg_scrTempC          0x80
+#define Reg_scrTempMaxP       0x84
+#define Reg_scrTempMinP       0x88
+#define Reg_scrStatus         0x8C
+#define Reg_scrReallocsA      0x90
+#define Reg_scrERetractsA     0x94
+#define Reg_scrCapabilities   0x98
+#define Reg_scrControl        0xC0
+
+
+
+typedef struct {
+  UINT8  Reserved0;
+  UINT8  Features_Exp;
+  UINT8  SectorCount_Exp;
+  UINT8  LBALow_Exp;
+  UINT8  LBAMid_Exp;
+  UINT8  LBAHigh_Exp;
+  UINT8  Control;
+  UINT8  Reserved1[2];
+  UINT8  Features_Error;
+  UINT8  SectorCount;
+  UINT8  LBALow;
+  UINT8  LBAMid;
+  UINT8  LBAHigh;
+  UINT8  Device_Head;
+  UINT8  Command_Status;
+}TASK_FILE;
+
+
+//
+//Reduced ATA command set
+//
+#define IDENTIFY_DEVICE       0xEC
+#define READ_DMA_EXT          0x25
+#define WRITE_DMA_EXT         0x35
+#define STANDBY_IMMEDIATE     0xE0
+#define FLUSH_CACHE_EXT       0xEA
+
+
+
+typedef struct {
+  UINT16  Reserved0[10];
+  UINT16  SerialNumber[10];
+  UINT16  Reserved1[3];
+  UINT16  FirmwareRevision[4];
+  UINT16  ModelNumber[20];
+  UINT16  Reserved2[33];
+  UINT16  MajorVersion;
+  UINT16  Reserved3[19];
+  UINT16  MaximumLBA[4];
+  UINT16  Reserved4[2];
+  UINT16  Sectorsize;
+  UINT16  Reserved5;
+  UINT16  DeviceGUID[4];
+  UINT16  Reserved6[94];
+  UINT16  Features;
+  UINT16  MaxWritesPerAddress;
+  UINT16  Reserved7[47];
+  UINT16  IntegrityWord;
+}IDENTIFY_DEVICE_DATA;
+
+
+
+
+
+#pragma pack()
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h
new file mode 100644
index 0000000000..e2a3c313fc
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h
@@ -0,0 +1,95 @@
+/** @file
+Include file for I2C DXE Driver register definitions (PCIe config. space and memory space).
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _I2C_REGS_H_
+#define _I2C_REGS_H_
+
+
+//----------------------------------------------------------------------------
+/// I2C Device Address
+//----------------------------------------------------------------------------
+typedef struct {
+  ///
+  /// The I2C hardware address to which the I2C device is preassigned or allocated.
+  ///
+  UINTN I2CDeviceAddress : 10;
+} EFI_I2C_DEVICE_ADDRESS;
+
+//----------------------------------------------------------------------------
+/// I2C Addressing Mode (7-bit or 10 bit)
+//----------------------------------------------------------------------------
+typedef enum _EFI_I2C_ADDR_MODE {
+  EfiI2CSevenBitAddrMode,
+  EfiI2CTenBitAddrMode,
+} EFI_I2C_ADDR_MODE;
+
+
+//----------------------------------------------------------------------------
+// I2C Controller B:D:F
+//----------------------------------------------------------------------------
+#define I2C_Bus     0x00
+#define I2C_Device  0x15
+#define I2C_Func    0x02
+
+//----------------------------------------------------------------------------
+// Memory Mapped Registers
+//----------------------------------------------------------------------------
+#define I2C_REG_CON                        0x00          // Control Register
+#define   B_I2C_REG_CON_SPEED                (BIT2+BIT1)   // standard mode (01) or fast mode (10)
+#define   B_I2C_REG_CON_10BITADD_MASTER      (BIT4)        // 7-bit addressing (0) or 10-bit addressing (1)
+#define I2C_REG_TAR                        0x04          // Master Target Address Register
+#define   B_I2C_REG_TAR                      (BIT9+BIT8+BIT7+BIT6+BIT5+BIT4+BIT3+BIT2+BIT1+BIT0) // Master Target Address bits
+#define I2C_REG_DATA_CMD                   0x10          // Data Buffer and Command Register
+#define   B_I2C_REG_DATA_CMD_RW              (BIT8)      // Data Buffer and Command Register Read/Write bit
+#define   B_I2C_REG_DATA_CMD_STOP            (BIT9)      // Data Buffer and Command Register STOP bit
+#define   B_I2C_REG_DATA_CMD_RESTART         (BIT10)     // Data Buffer and Command Register RESTART bit
+#define I2C_REG_SS_SCL_HCNT                0x14          // Standard Speed Clock SCL High Count Register
+#define I2C_REG_SS_SCL_LCNT                0x18          // Standard Speed Clock SCL Low Count Register
+#define I2C_REG_FS_SCL_HCNT                0x1C          // Fast Speed Clock SCL High Count Register
+#define I2C_REG_FS_SCL_LCNT                0x20          // Fast Speed Clock SCL Low Count Register
+#define I2C_REG_INTR_STAT                  0x2C          // Interrupt Status Register
+#define   B_I2C_REG_INTR_STAT_STOP_DET       (BIT9)        // Interrupt Status Register STOP_DET signal status
+#define I2C_REG_INTR_MASK                  0x30          // Interrupt Status Mask Register
+#define I2C_REG_RAW_INTR_STAT              0x34          // Raw Interrupt Status Register
+#define   I2C_REG_RAW_INTR_STAT_STOP_DET    (BIT9)         // Raw Interrupt Status Register STOP_DET signal status.
+#define   I2C_REG_RAW_INTR_STAT_TX_ABRT     (BIT6)         // Raw Interrupt Status Register TX Abort status.
+#define   I2C_REG_RAW_INTR_STAT_TX_OVER     (BIT3)         // Raw Interrupt Status Register TX Overflow signal status.
+#define   I2C_REG_RAW_INTR_STAT_RX_OVER     (BIT1)         // Raw Interrupt Status Register RX Overflow signal status.
+#define   I2C_REG_RAW_INTR_STAT_RX_UNDER    (BIT0)         // Raw Interrupt Status Register RX Underflow signal status.
+#define I2C_REG_RX_TL                      0x38          // Receive FIFO Threshold Level Register
+#define I2C_REG_TX_TL                      0x3C          // Transmit FIFO Threshold Level Register
+#define I2C_REG_CLR_INT                    0x40          // Clear Combined and Individual Interrupt Register
+#define I2C_REG_CLR_RX_UNDER               0x44          // Clear RX Under Interrupt Register
+#define I2C_REG_CLR_RX_OVER                0x48          // Clear RX Over Interrupt Register
+#define I2C_REG_CLR_TX_OVER                0x4C          // Clear TX Over Interrupt Register
+#define I2C_REG_CLR_RD_REQ                 0x50          // Clear RD REQ Interrupt Register
+#define I2C_REG_CLR_TX_ABRT                0x54          // Clear TX ABRT Interrupt Register
+#define I2C_REG_CLR_ACTIVITY               0x5C          // Clear Activity Interrupt Register
+#define I2C_REG_CLR_STOP_DET               0x60          // Clear STOP DET Interrupt Register
+#define   B_I2C_REG_CLR_STOP_DET             (BIT0)        // Clear STOP DET Interrupt Register
+#define I2C_REG_CLR_START_DET              0x64          // Clear START DET Interrupt Register
+#define   B_I2C_REG_CLR_START_DET          (BIT0)          // Clear START DET Interrupt Register
+#define I2C_REG_ENABLE                     0x6C          // Enable Register
+#define   B_I2C_REG_ENABLE                   (BIT0)        // Enable (1) or disable (0) I2C Controller
+#define I2C_REG_STATUS                     0x70          // Status Register
+#define I2C_REG_TXFLR                      0x74          // Transmit FIFO Level Register
+#define   B_I2C_REG_TXFLR                   (BIT3+BIT2+BIT1+BIT0)  // Transmit FIFO Level Register bits
+#define I2C_REG_RXFLR                      0x78          // Receive FIFO Level Register
+#define   B_I2C_REG_RXFLR                   (BIT3+BIT2+BIT1+BIT0)  // Receive FIFO Level Register bits
+#define I2C_REG_SDA_HOLD                   0x7C          // SDA HOLD Register
+#define I2C_REG_TX_ABRT_SOURCE             0x80          // Transmit Abort Source Register
+#define I2C_REG_ENABLE_STATUS              0x9C          // Enable Status Register
+#define I2C_REG_FS_SPKLEN                  0xA0          // SS and FS Spike Suppression Limit Register
+
+//
+// Features.
+//
+#define I2C_FIFO_SIZE                      16
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h
new file mode 100644
index 0000000000..f6066e8d10
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h
@@ -0,0 +1,248 @@
+/** @file
+Header file for QuarkSCSocId Ioh.
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+#ifndef _IOH_H_
+#define _IOH_H_
+
+#ifndef BIT0
+#define BIT0    0x01
+#define BIT1    0x02
+#define BIT2    0x04
+#define BIT3    0x08
+#define BIT4    0x10
+#define BIT5    0x20
+#define BIT6    0x40
+#define BIT7    0x80
+#define BIT8    0x100
+#define BIT9    0x200
+#define BIT00   0x00000001
+#define BIT01   0x00000002
+#define BIT02   0x00000004
+#define BIT03   0x00000008
+#define BIT04   0x00000010
+#define BIT05   0x00000020
+#define BIT06   0x00000040
+#define BIT07   0x00000080
+#define BIT08   0x00000100
+#define BIT09   0x00000200
+#define BIT10   0x00000400
+#define BIT11   0x00000800
+#define BIT12   0x00001000
+#define BIT13   0x00002000
+#define BIT14   0x00004000
+#define BIT15   0x00008000
+#define BIT16   0x00010000
+#define BIT17   0x00020000
+#define BIT18   0x00040000
+#define BIT19   0x00080000
+#define BIT20   0x00100000
+#define BIT21   0x00200000
+#define BIT22   0x00400000
+#define BIT23   0x00800000
+#define BIT24   0x01000000
+#define BIT25   0x02000000
+#define BIT26   0x04000000
+#define BIT27   0x08000000
+#define BIT28   0x10000000
+#define BIT29   0x20000000
+#define BIT30   0x40000000
+#define BIT31   0x80000000
+#endif
+
+#define IOH_PCI_CFG_ADDRESS(bus,dev,func,reg) \
+    ((UINT32) ( (((UINTN)bus) << 24) + (((UINTN)dev) << 16) + \
+    (((UINTN)func) << 8) + ((UINTN)reg) ))& 0x00000000ffffffff
+
+//----------------------------------------------------------------------------
+
+#define INTEL_VENDOR_ID         0x8086  // Intel Vendor ID
+
+//----------------------------------------------------------------------------
+// Pci Configuration Map Register Offsets
+//----------------------------------------------------------------------------
+#define PCI_REG_VID             0x00    // Vendor ID Register
+#define PCI_REG_DID             0x02    // Device ID Register
+#define PCI_REG_PCICMD          0x04    // PCI Command Register
+#define PCI_REG_PCISTS          0x06    // PCI Status Register
+#define PCI_REG_RID             0x08    // PCI Revision ID Register
+#define PCI_REG_PI              0x09    // Programming Interface
+#define PCI_REG_SCC             0x0a    // Sub Class Code Register
+#define PCI_REG_BCC             0x0b    // Base Class Code Register
+#define PCI_REG_PMLT            0x0d    // Primary Master Latnecy Timer
+#define PCI_REG_HDR             0x0e    // Header Type Register
+#define PCI_REG_PBUS            0x18    // Primary Bus Number Register
+#define PCI_REG_SBUS            0x19    // Secondary Bus Number Register
+#define PCI_REG_SUBUS           0x1a    // Subordinate Bus Number Register
+#define PCI_REG_SMLT            0x1b    // Secondary Master Latnecy Timer
+#define PCI_REG_IOBASE          0x1c    // I/O base Register
+#define PCI_REG_IOLIMIT         0x1d    // I/O Limit Register
+#define PCI_REG_SECSTATUS       0x1e    // Secondary Status Register
+#define PCI_REG_MEMBASE         0x20    // Memory Base Register
+#define PCI_REG_MEMLIMIT        0x22    // Memory Limit Register
+#define PCI_REG_PRE_MEMBASE     0x24    // Prefretchable memory Base register
+#define PCI_REG_PRE_MEMLIMIT    0x26    // Prefretchable memory Limit register
+#define PCI_REG_SVID0           0x2c    // Subsystem Vendor ID low byte
+#define PCI_REG_SVID1           0x2d    // Subsystem Vendor ID high byte
+#define PCI_REG_SID0            0x2e    // Subsystem ID low byte
+#define PCI_REG_SID1            0x2f    // Subsystem ID high byte
+#define PCI_REG_IOBASE_U        0x30    // I/O base Upper Register
+#define PCI_REG_IOLIMIT_U       0x32    // I/O Limit Upper Register
+#define PCI_REG_INTLINE         0x3c    // Interrupt Line Register
+#define PCI_REG_BRIDGE_CNTL     0x3e    // Bridge Control Register
+
+//---------------------------------------------------------------------------
+// QuarkSCSocId Packet Hub definitions
+//---------------------------------------------------------------------------
+
+#define PCIE_BRIDGE_VID_DID     0x88008086
+
+//---------------------------------------------------------------------------
+// Quark South Cluster definitions.
+//---------------------------------------------------------------------------
+
+#define IOH_BUS                           0
+#define IOH_PCI_IOSF2AHB_0_DEV_NUM        0x14
+#define IOH_PCI_IOSF2AHB_0_MAX_FUNCS      7
+#define IOH_PCI_IOSF2AHB_1_DEV_NUM        0x15
+#define IOH_PCI_IOSF2AHB_1_MAX_FUNCS      3
+
+//---------------------------------------------------------------------------
+// Quark South Cluster USB definitions.
+//---------------------------------------------------------------------------
+
+#define IOH_USB_BUS_NUMBER                IOH_BUS
+#define IOH_USB_CONTROLLER_MMIO_RANGE     0x1000
+#define IOH_MAX_OHCI_USB_CONTROLLERS      1
+#define IOH_MAX_EHCI_USB_CONTROLLERS      1
+#define IOH_MAX_USBDEVICE_USB_CONTROLLERS 1
+
+#define R_IOH_USB_VENDOR_ID               0x00
+#define   V_IOH_USB_VENDOR_ID               INTEL_VENDOR_ID
+#define R_IOH_USB_DEVICE_ID               0x02
+#define R_IOH_USB_COMMAND                 0x04
+#define   B_IOH_USB_COMMAND_BME             BIT2
+#define   B_IOH_USB_COMMAND_MSE             BIT1
+#define   B_IOH_USB_COMMAND_ISE             BIT0
+#define R_IOH_USB_MEMBAR                  0x10
+#define   B_IOH_USB_MEMBAR_ADDRESS_MASK     0xFFFFF000  // [31:12].
+#define R_IOH_USB_OHCI_HCCABAR            0x18
+
+//---------------------------------------------------------------------------
+// Quark South Cluster OHCI definitions
+//---------------------------------------------------------------------------
+#define IOH_USB_OHCI_DEVICE_NUMBER        IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_OHCI_FUNCTION_NUMBER          0x04
+
+//---------------------------------------------------------------------------
+// Quark South Cluster EHCI definitions
+//---------------------------------------------------------------------------
+#define IOH_USB_EHCI_DEVICE_NUMBER        IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_EHCI_FUNCTION_NUMBER          0x03
+
+//
+// EHCI memory mapped registers offset from memory BAR0.
+//
+#define R_IOH_EHCI_CAPLENGTH              0x00
+#define R_IOH_EHCI_INSNREG01              0x94
+#define   B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP    (16)
+#define   B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_MASK  (0xff << B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP)
+#define   B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP     (0)
+#define   B_IOH_EHCI_INSNREG01_IN_THRESHOLD_MASK   (0xff << B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP)
+
+//
+// EHCI memory mapped registers offset from memory BAR0 + Cap length value.
+//
+#define R_IOH_EHCI_CONFIGFLAGS            0x40
+
+//---------------------------------------------------------------------------
+// Quark South Cluster USB Device definitions
+//---------------------------------------------------------------------------
+#define IOH_USBDEVICE_DEVICE_NUMBER       IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_USBDEVICE_FUNCTION_NUMBER     0x02
+
+//
+// USB Device memory mapped registers offset from memory BAR0.
+//
+#define R_IOH_USBDEVICE_D_INTR_UDC_REG                      0x40c
+#define R_IOH_USBDEVICE_D_INTR_MSK_UDC_REG                  0x410
+#define   B_IOH_USBDEVICE_D_INTR_MSK_UDC_REG_MASK1_MASK       0xff
+#define R_IOH_USBDEVICE_EP_INTR_UDC_REG                     0x414
+#define R_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG                 0x418
+#define   B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_OUT_EP_MASK     0x000f0000
+#define   B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_IN_EP_MASK      0x0000000f
+
+//---------------------------------------------------------------------------
+// Quark South Cluster 10/100 Mbps Ethernet Device definitions.
+//---------------------------------------------------------------------------
+#define IOH_MAC0_BUS_NUMBER                                 IOH_BUS
+#define IOH_MAC0_DEVICE_NUMBER                              IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_MAC0_FUNCTION_NUMBER                            0x06
+#define IOH_MAC1_BUS_NUMBER                                 IOH_BUS
+#define IOH_MAC1_DEVICE_NUMBER                              IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_MAC1_FUNCTION_NUMBER                            0x07
+
+//
+// MAC Device PCI config registers.
+//
+#define R_IOH_MAC_DEVICE_ID                                 0x02
+#define   V_IOH_MAC_VENDOR_ID                                 INTEL_VENDOR_ID
+#define R_IOH_MAC_DEVICE_ID                                 0x02
+#define   V_IOH_MAC_DEVICE_ID                                 0x0937
+#define R_IOH_MAC_COMMAND                                   0x04
+#define   B_IOH_MAC_COMMAND_BME                               BIT2
+#define   B_IOH_MAC_COMMAND_MSE                               BIT1
+#define   B_IOH_MAC_COMMAND_ISE                               BIT0
+#define R_IOH_MAC_MEMBAR                                    0x10
+#define   B_IOH_MAC_MEMBAR_ADDRESS_MASK                       0xFFFFF000
+
+//
+// LAN Device memory mapped registers offset from memory BAR0.
+//
+#define R_IOH_MAC_GMAC_REG_8                                0x20
+#define   B_IOH_MAC_USERVER_MASK                              0x0000FF00
+#define   B_IOH_MAC_SNPSVER_MASK                              0x000000FF
+#define R_IOH_MAC_GMAC_REG_16                               0x40
+#define   B_IOH_MAC_ADDRHI_MASK                               0x0000FFFF
+#define   B_IOH_MAC_AE                                        BIT31
+#define R_IOH_MAC_GMAC_REG_17                               0x44
+#define   B_IOH_MAC_ADDRLO_MASK                               0xFFFFFFFF
+
+//---------------------------------------------------------------------------
+// Quark I2C / GPIO definitions
+//---------------------------------------------------------------------------
+
+#define   V_IOH_I2C_GPIO_VENDOR_ID          INTEL_VENDOR_ID
+#define   V_IOH_I2C_GPIO_DEVICE_ID          0x0934
+
+#define R_IOH_I2C_MEMBAR                  0x10
+#define   B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK   0xFFFFF000  // [31:12].
+
+#define GPIO_SWPORTA_DR                   0x00
+#define GPIO_SWPORTA_DDR                  0x04
+#define GPIO_INTEN                        0x30
+#define GPIO_INTMASK                      0x34
+#define GPIO_INTTYPE_LEVEL                0x38
+#define GPIO_INT_POLARITY                 0x3C
+#define GPIO_INTSTATUS                    0x40
+#define GPIO_RAW_INTSTATUS                0x44
+#define GPIO_DEBOUNCE                     0x48
+#define GPIO_PORTA_EOI                    0x4C
+#define GPIO_EXT_PORTA                    0x50
+#define GPIO_EXT_PORTB                    0x54
+#define GPIO_LS_SYNC                      0x60
+#define GPIO_CONFIG_REG2                  0x70
+#define GPIO_CONFIG_REG1                  0x74
+
+//---------------------------------------------------------------------------
+// Quark South Cluster UART definitions.
+//---------------------------------------------------------------------------
+
+#define R_IOH_UART_MEMBAR                 0x10
+#define   B_IOH_UART_MEMBAR_ADDRESS_MASK    0xFFFFF000  // [31:12].
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h
new file mode 100644
index 0000000000..a259dd8df7
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h
@@ -0,0 +1,18 @@
+/** @file
+Macros to simplify and abstract the interface to PCI configuration.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _IOH_ACCESS_H_
+#define _IOH_ACCESS_H_
+
+#include "Ioh.h"
+#include "IohCommonDefinitions.h"
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h
new file mode 100644
index 0000000000..09f13e2f2a
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h
@@ -0,0 +1,342 @@
+/** @file
+This header file provides common definitions just for MCH using to avoid including extra module's file.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IOH_COMMON_DEFINITIONS_H_
+#define _IOH_COMMON_DEFINITIONS_H_
+
+//
+// PCI CONFIGURATION MAP REGISTER OFFSETS
+//
+#ifndef PCI_VID
+#define PCI_VID             0x0000        // Vendor ID Register
+#define PCI_DID             0x0002        // Device ID Register
+#define PCI_CMD             0x0004        // PCI Command Register
+#define PCI_STS             0x0006        // PCI Status Register
+#define PCI_RID             0x0008        // Revision ID Register
+#define PCI_IFT             0x0009        // Interface Type
+#define PCI_SCC             0x000A        // Sub Class Code Register
+#define PCI_BCC             0x000B        // Base Class Code Register
+#define PCI_CLS             0x000C        // Cache Line Size
+#define PCI_PMLT            0x000D        // Primary Master Latency Timer
+#define PCI_HDR             0x000E        // Header Type Register
+#define PCI_BIST            0x000F        // Built in Self Test Register
+#define PCI_BAR0            0x0010        // Base Address Register 0
+#define PCI_BAR1            0x0014        // Base Address Register 1
+#define PCI_BAR2            0x0018        // Base Address Register 2
+#define PCI_PBUS            0x0018        // Primary Bus Number Register
+#define PCI_SBUS            0x0019        // Secondary Bus Number Register
+#define PCI_SUBUS           0x001A        // Subordinate Bus Number Register
+#define PCI_SMLT            0x001B        // Secondary Master Latency Timer
+#define PCI_BAR3            0x001C        // Base Address Register 3
+#define PCI_IOBASE          0x001C        // I/O base Register
+#define PCI_IOLIMIT         0x001D        // I/O Limit Register
+#define PCI_SECSTATUS       0x001E        // Secondary Status Register
+#define PCI_BAR4            0x0020        // Base Address Register 4
+#define PCI_MEMBASE         0x0020        // Memory Base Register
+#define PCI_MEMLIMIT        0x0022        // Memory Limit Register
+#define PCI_BAR5            0x0024        // Base Address Register 5
+#define PCI_PRE_MEMBASE     0x0024        // Prefetchable memory Base register
+#define PCI_PRE_MEMLIMIT    0x0026        // Prefetchable memory Limit register
+#define PCI_PRE_MEMBASE_U   0x0028        // Prefetchable memory base upper 32 bits
+#define PCI_PRE_MEMLIMIT_U  0x002C        // Prefetchable memory limit upper 32 bits
+#define PCI_SVID            0x002C        // Subsystem Vendor ID
+#define PCI_SID             0x002E        // Subsystem ID
+#define PCI_IOBASE_U        0x0030        // I/O base Upper Register
+#define PCI_IOLIMIT_U       0x0032        // I/O Limit Upper Register
+#define PCI_CAPP            0x0034        // Capabilities Pointer
+#define PCI_EROM            0x0038        // Expansion ROM Base Address
+#define PCI_INTLINE         0x003C        // Interrupt Line Register
+#define PCI_INTPIN          0x003D        // Interrupt Pin Register
+#define PCI_MAXGNT          0x003E        // Max Grant Register
+#define PCI_BRIDGE_CNTL     0x003E        // Bridge Control Register
+#define PCI_MAXLAT          0x003F        // Max Latency Register
+#endif
+//
+// Bit Difinitions
+//
+#ifndef BIT0
+#define BIT0                     0x0001
+#define BIT1                     0x0002
+#define BIT2                     0x0004
+#define BIT3                     0x0008
+#define BIT4                     0x0010
+#define BIT5                     0x0020
+#define BIT6                     0x0040
+#define BIT7                     0x0080
+#define BIT8                     0x0100
+#define BIT9                     0x0200
+#define BIT10                    0x0400
+#define BIT11                    0x0800
+#define BIT12                    0x1000
+#define BIT13                    0x2000
+#define BIT14                    0x4000
+#define BIT15                    0x8000
+#define BIT16                0x00010000
+#define BIT17                0x00020000
+#define BIT18                0x00040000
+#define BIT19                0x00080000
+#define BIT20                0x00100000
+#define BIT21                0x00200000
+#define BIT22                0x00400000
+#define BIT23                0x00800000
+#define BIT24                0x01000000
+#define BIT25                0x02000000
+#define BIT26                0x04000000
+#define BIT27                0x08000000
+#define BIT28                0x10000000
+#define BIT29                0x20000000
+#define BIT30                0x40000000
+#define BIT31                0x80000000
+#endif
+
+
+//
+//  Common Memory mapped Io access macros ------------------------------------------
+//
+#define IohMmioAddress( BaseAddr, Register ) \
+    ( (UINTN)BaseAddr + \
+      (UINTN)(Register) \
+    )
+
+//
+// UINT64
+//
+#define IohMmio64Ptr( BaseAddr, Register ) \
+    ( (volatile UINT64 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio64( BaseAddr, Register ) \
+    *IohMmio64Ptr( BaseAddr, Register )
+
+#define IohMmio64Or( BaseAddr, Register, OrData ) \
+    IohMmio64( BaseAddr, Register ) = \
+      (UINT64) ( \
+        IohMmio64( BaseAddr, Register ) | \
+        (UINT64)(OrData) \
+      )
+
+#define IohMmio64And( BaseAddr, Register, AndData ) \
+    IohMmio64( BaseAddr, Register ) = \
+      (UINT64) ( \
+        IohMmio64( BaseAddr, Register ) & \
+        (UINT64)(AndData) \
+      )
+
+#define IohMmio64AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    IohMmio64( BaseAddr, Register ) = \
+      (UINT64) ( \
+        ( IohMmio64( BaseAddr, Register ) & \
+            (UINT64)(AndData) \
+        ) | \
+        (UINT64)(OrData) \
+      )
+
+//
+// UINT32
+//
+#define IohMmio32Ptr( BaseAddr, Register ) \
+    ( (volatile UINT32 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio32( BaseAddr, Register ) \
+    *IohMmio32Ptr( BaseAddr, Register )
+
+#define IohMmio32Or( BaseAddr, Register, OrData ) \
+    IohMmio32( BaseAddr, Register ) = \
+      (UINT32) ( \
+        IohMmio32( BaseAddr, Register ) | \
+        (UINT32)(OrData) \
+      )
+
+#define IohMmio32And( BaseAddr, Register, AndData ) \
+    IohMmio32( BaseAddr, Register ) = \
+      (UINT32) ( \
+        IohMmio32( BaseAddr, Register ) & \
+        (UINT32)(AndData) \
+      )
+
+#define IohMmio32AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    IohMmio32( BaseAddr, Register ) = \
+      (UINT32) ( \
+        ( IohMmio32( BaseAddr, Register ) & \
+            (UINT32)(AndData) \
+        ) | \
+        (UINT32)(OrData) \
+      )
+//
+// UINT16
+//
+
+#define IohMmio16Ptr( BaseAddr, Register ) \
+    ( (volatile UINT16 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio16( BaseAddr, Register ) \
+    *IohMmio16Ptr( BaseAddr, Register )
+
+#define IohMmio16Or( BaseAddr, Register, OrData ) \
+    IohMmio16( BaseAddr, Register ) = \
+      (UINT16) ( \
+        IohMmio16( BaseAddr, Register ) | \
+        (UINT16)(OrData) \
+      )
+
+#define IohMmio16And( BaseAddr, Register, AndData ) \
+    IohMmio16( BaseAddr, Register ) = \
+      (UINT16) ( \
+        IohMmio16( BaseAddr, Register ) & \
+        (UINT16)(AndData) \
+      )
+
+#define IohMmio16AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    IohMmio16( BaseAddr, Register ) = \
+      (UINT16) ( \
+        ( IohMmio16( BaseAddr, Register ) & \
+            (UINT16)(AndData) \
+        ) | \
+        (UINT16)(OrData) \
+      )
+//
+// UINT8
+//
+#define IohMmio8Ptr( BaseAddr, Register ) \
+    ( (volatile UINT8 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio8( BaseAddr, Register ) \
+    *IohMmio8Ptr( BaseAddr, Register )
+
+#define IohMmio8Or( BaseAddr, Register, OrData ) \
+    IohMmio8( BaseAddr, Register ) = \
+      (UINT8) ( \
+        IohMmio8( BaseAddr, Register ) | \
+        (UINT8)(OrData) \
+      )
+
+#define IohMmio8And( BaseAddr, Register, AndData ) \
+    IohMmio8( BaseAddr, Register ) = \
+      (UINT8) ( \
+        IohMmio8( BaseAddr, Register ) & \
+        (UINT8)(AndData) \
+      )
+
+#define IohMmio8AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    IohMmio8( BaseAddr, Register ) = \
+      (UINT8) ( \
+        ( IohMmio8( BaseAddr, Register ) & \
+            (UINT8)(AndData) \
+          ) | \
+        (UINT8)(OrData) \
+      )
+
+//
+//  Common Memory mapped Pci access macros ------------------------------------------
+//
+#define Ioh_PCI_EXPRESS_BASE_ADDRESS  0xE0000000
+
+
+#define IohMmPciAddress( Segment, Bus, Device, Function, Register ) \
+  ( (UINTN)Ioh_PCI_EXPRESS_BASE_ADDRESS + \
+    (UINTN)(Bus << 20) + \
+    (UINTN)(Device << 15) + \
+    (UINTN)(Function << 12) + \
+    (UINTN)(Register) \
+  )
+
+//
+// UINT32
+//
+#define IohMmPci32Ptr( Segment, Bus, Device, Function, Register ) \
+  ( (volatile UINT32 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define IohMmPci32( Segment, Bus, Device, Function, Register ) \
+  *IohMmPci32Ptr( Segment, Bus, Device, Function, Register )
+
+#define IohMmPci32Or( Segment, Bus, Device, Function, Register, OrData ) \
+  IohMmPci32( Segment, Bus, Device, Function, Register ) = \
+    (UINT32) ( \
+      IohMmPci32( Segment, Bus, Device, Function, Register ) | \
+      (UINT32)(OrData) \
+    )
+
+#define IohMmPci32And( Segment, Bus, Device, Function, Register, AndData ) \
+  IohMmPci32( Segment, Bus, Device, Function, Register ) = \
+    (UINT32) ( \
+      IohMmPci32( Segment, Bus, Device, Function, Register ) & \
+      (UINT32)(AndData) \
+    )
+
+#define IohMmPci32AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+  IohMmPci32( Segment, Bus, Device, Function, Register ) = \
+    (UINT32) ( \
+      ( IohMmPci32( Segment, Bus, Device, Function, Register ) & \
+          (UINT32)(AndData) \
+      ) | \
+      (UINT32)(OrData) \
+    )
+//
+// UINT16
+//
+#define IohMmPci16Ptr( Segment, Bus, Device, Function, Register ) \
+  ( (volatile UINT16 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define IohMmPci16( Segment, Bus, Device, Function, Register ) \
+  *IohMmPci16Ptr( Segment, Bus, Device, Function, Register )
+
+#define IohMmPci16Or( Segment, Bus, Device, Function, Register, OrData ) \
+  IohMmPci16( Segment, Bus, Device, Function, Register ) = \
+    (UINT16) ( \
+      IohMmPci16( Segment, Bus, Device, Function, Register ) | \
+      (UINT16)(OrData) \
+    )
+
+#define IohMmPci16And( Segment, Bus, Device, Function, Register, AndData ) \
+  IohMmPci16( Segment, Bus, Device, Function, Register ) = \
+    (UINT16) ( \
+      IohMmPci16( Segment, Bus, Device, Function, Register ) & \
+      (UINT16)(AndData) \
+    )
+
+#define IohMmPci16AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+  IohMmPci16( Segment, Bus, Device, Function, Register ) = \
+    (UINT16) ( \
+      ( IohMmPci16( Segment, Bus, Device, Function, Register ) & \
+          (UINT16)(AndData) \
+      ) | \
+      (UINT16)(OrData) \
+    )
+//
+// UINT8
+//
+#define IohMmPci8Ptr( Segment, Bus, Device, Function, Register ) \
+  ( (volatile UINT8 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define IohMmPci8( Segment, Bus, Device, Function, Register ) \
+  *IohMmPci8Ptr( Segment, Bus, Device, Function, Register )
+
+#define IohMmPci8Or( Segment, Bus, Device, Function, Register, OrData ) \
+  IohMmPci8( Segment, Bus, Device, Function, Register ) = \
+    (UINT8) ( \
+      IohMmPci8( Segment, Bus, Device, Function, Register ) | \
+      (UINT8)(OrData) \
+    )
+
+#define IohMmPci8And( Segment, Bus, Device, Function, Register, AndData ) \
+  IohMmPci8( Segment, Bus, Device, Function, Register ) = \
+    (UINT8) ( \
+      IohMmPci8( Segment, Bus, Device, Function, Register ) & \
+      (UINT8)(AndData) \
+    )
+
+#define IohMmPci8AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+  IohMmPci8( Segment, Bus, Device, Function, Register ) = \
+    (UINT8) ( \
+      ( IohMmPci8( Segment, Bus, Device, Function, Register ) & \
+          (UINT8)(AndData) \
+        ) | \
+      (UINT8)(OrData) \
+    )
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h
new file mode 100644
index 0000000000..d401c6b43e
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h
@@ -0,0 +1,152 @@
+/** @file
+
+Intel I2C library implementation built upon I/O library
+
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _I2C_LIB_H_
+#define _I2C_LIB_H_
+
+#include "I2cRegs.h"
+
+/**
+
+  The I2cWriteByte() function is a wrapper function for the WriteByte() function.
+  Provides a standard way to execute a standard single byte write to an IC2 device
+  (without accessing sub-addresses), as defined in the I2C Specification.
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param Buffer       Contains the value of byte data to execute to the
+                      I2C slave device.
+
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_INVALID_PARAMETER  This or Buffer pointers are invalid.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN OUT VOID                       *Buffer
+  );
+
+/**
+
+  The I2cReadByte() function is a wrapper function for the ReadByte() function.
+  Provides a standard way to execute a standard single byte read to an I2C device
+  (without accessing sub-addresses), as defined in the I2C Specification.
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param Buffer       Contains the value of byte data read from the
+                      I2C slave device.
+
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN OUT VOID                       *Buffer
+  );
+
+/**
+
+  The I2cWriteMultipleByte() function is a wrapper function for the WriteMultipleByte()
+  function. Provides a standard way to execute multiple byte writes to an I2C device (e.g. when
+  accessing sub-addresses or writing block of data), as defined in the I2C Specification.
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param Length       No. of bytes to be written.
+
+  @param Buffer       Contains the value of byte to be written to the
+                      I2C slave device.
+
+  @retval EFI_SUCCESS            Transfer success.
+  @retval EFI_INVALID_PARAMETER  This, Length or Buffer pointers are invalid.
+  @retval EFI_UNSUPPORTED        Unsupported input param.
+  @retval EFI_TIMEOUT            Timeout while waiting xfer.
+  @retval EFI_ABORTED            Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR       Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteMultipleByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN UINTN                          *Length,
+  IN OUT VOID                       *Buffer
+  );
+
+/**
+
+  The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte
+  function. Provides a standard way to execute multiple byte writes to an IC2 device
+  (e.g. when accessing sub-addresses or when reading block of data), as defined
+  in the I2C Specification (I2C combined write/read protocol).
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param WriteLength  No. of bytes to be written. In this case data
+                      written typically contains sub-address or sub-addresses
+                      in Hi-Lo format, that need to be read (I2C combined
+                      write/read protocol).
+
+  @param ReadLength   No. of bytes to be read from I2C slave device.
+                      need to be read.
+
+  @param Buffer       Contains the value of byte data read from the
+                      I2C slave device.
+
+  @retval EFI_SUCCESS            Transfer success.
+  @retval EFI_INVALID_PARAMETER  This, WriteLength, ReadLength or Buffer
+                                 pointers are invalid.
+  @retval EFI_UNSUPPORTED        Unsupported input param.
+  @retval EFI_TIMEOUT            Timeout while waiting xfer.
+  @retval EFI_ABORTED            Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR       Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadMultipleByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN UINTN                          *WriteLength,
+  IN UINTN                          *ReadLength,
+  IN OUT VOID                       *Buffer
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h
new file mode 100644
index 0000000000..a3aa071ef5
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h
@@ -0,0 +1,36 @@
+/** @file
+Library that provides Soc specific library services for SouthCluster devices.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __IOH_LIB_H__
+#define __IOH_LIB_H__
+
+#include "Ioh.h"
+
+EFI_STATUS
+EFIAPI
+InitializeIohSsvidSsid (
+   IN UINT8   Bus,
+   IN UINT8   Device,
+   IN UINT8   Func
+   );
+
+VOID
+EFIAPI
+EnableUsbMemIoBusMaster (
+   IN UINT8   UsbBusNumber
+  );
+
+UINT32
+EFIAPI
+ReadIohGpioValues (
+  VOID
+  );
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h
new file mode 100644
index 0000000000..549171e53e
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h
@@ -0,0 +1,274 @@
+/** @file
+
+Header file for Industry MMC 4.2 spec.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MMC_H
+#define _MMC_H
+
+#pragma pack(1)
+//
+//Command definition
+//
+
+#define  CMD0              0
+#define  CMD1              1
+#define  CMD2              2
+#define  CMD3              3
+#define  CMD4              4
+#define  CMD6              6
+#define  CMD7              7
+#define  CMD8              8
+#define  CMD9              9
+#define  CMD10             10
+#define  CMD11             11
+#define  CMD12             12
+#define  CMD13             13
+#define  CMD14             14
+#define  CMD15             15
+#define  CMD16             16
+#define  CMD17             17
+#define  CMD18             18
+#define  CMD19             19
+#define  CMD20             20
+#define  CMD23             23
+#define  CMD24             24
+#define  CMD25             25
+#define  CMD26             26
+#define  CMD27             27
+#define  CMD28             28
+#define  CMD29             29
+#define  CMD30             30
+#define  CMD35             35
+#define  CMD36             36
+#define  CMD38             38
+#define  CMD39             39
+#define  CMD40             40
+#define  CMD42             42
+#define  CMD55             55
+#define  CMD56             56
+
+
+
+#define  GO_IDLE_STATE           CMD0
+#define  SEND_OP_COND            CMD1
+#define  ALL_SEND_CID            CMD2
+#define  SET_RELATIVE_ADDR       CMD3
+#define  SET_DSR                 CMD4
+#define  SWITCH                  CMD6
+#define  SELECT_DESELECT_CARD    CMD7
+#define  SEND_EXT_CSD            CMD8
+#define  SEND_CSD                CMD9
+#define  SEND_CID                CMD10
+#define  READ_DAT_UNTIL_STOP     CMD11
+#define  STOP_TRANSMISSION       CMD12
+#define  SEND_STATUS             CMD13
+#define  BUSTEST_R               CMD14
+#define  GO_INACTIVE_STATE       CMD15
+#define  SET_BLOCKLEN            CMD16
+#define  READ_SINGLE_BLOCK       CMD17
+#define  READ_MULTIPLE_BLOCK     CMD18
+#define  BUSTEST_W               CMD19
+#define  WRITE_DAT_UNTIL_STOP    CMD20
+#define  SET_BLOCK_COUNT         CMD23
+#define  WRITE_BLOCK             CMD24
+#define  WRITE_MULTIPLE_BLOCK    CMD25
+#define  PROGRAM_CID             CMD26
+#define  PROGRAM_CSD             CMD27
+#define  SET_WRITE_PROT          CMD28
+#define  CLR_WRITE_PROT          CMD29
+#define  SEND_WRITE_PROT         CMD30
+#define  ERASE_GROUP_START       CMD35
+#define  ERASE_GROUP_END         CMD36
+#define  ERASE                   CMD38
+#define  FAST_IO                 CMD39
+#define  GO_IRQ_STATE            CMD40
+#define  LOCK_UNLOCK             CMD42
+#define  APP_CMD                 CMD55
+#define  GEN_CMD                 CMD56
+
+
+#define CMD_INDEX_MASK           0x3F
+#define AUTO_CMD12_ENABLE        BIT6
+#define AUTO_CMD23_ENABLE        BIT7
+
+#define FREQUENCY_OD            (400 * 1000)
+#define FREQUENCY_MMC_PP        (26 * 1000 * 1000)
+#define FREQUENCY_MMC_PP_HIGH   (52 * 1000 * 1000)
+
+#define DEFAULT_DSR_VALUE        0x404
+
+//
+//Registers definition
+//
+
+typedef struct {
+  UINT32  Reserved0:   7;  // 0
+  UINT32  V170_V195:   1;  // 1.70V - 1.95V
+  UINT32  V200_V260:   7;  // 2.00V - 2.60V
+  UINT32  V270_V360:   9;  // 2.70V - 3.60V
+  UINT32  Reserved1:   5;  // 0
+  UINT32  AccessMode:  2;  // 00b (byte mode), 10b (sector mode)
+  UINT32  Busy:        1;  // This bit is set to LOW if the card has not finished the power up routine
+}OCR;
+
+
+typedef struct {
+  UINT8   NotUsed:     1; //  1
+  UINT8   CRC:         7; //  CRC7 checksum
+  UINT8   MDT;            //  Manufacturing date
+  UINT32  PSN;            //  Product serial number
+  UINT8   PRV;            //  Product revision
+  UINT8   PNM[6];         //  Product name
+  UINT16  OID;            //  OEM/Application ID
+  UINT8   MID;            //  Manufacturer ID
+}CID;
+
+
+typedef struct {
+  UINT8   NotUsed:            1; //  1 [0:0]
+  UINT8   CRC:                7; //  CRC [7:1]
+  UINT8   ECC:                2; //  ECC code [9:8]
+  UINT8   FILE_FORMAT:        2; //  File format [11:10]
+  UINT8   TMP_WRITE_PROTECT:  1; //  Temporary write protection [12:12]
+  UINT8   PERM_WRITE_PROTECT: 1; //  Permanent write protection [13:13]
+  UINT8   COPY:               1; //  Copy flag (OTP) [14:14]
+  UINT8   FILE_FORMAT_GRP:    1; //  File format group [15:15]
+  UINT16  CONTENT_PROT_APP:   1; //  Content protection application [16:16]
+  UINT16  Reserved0:          4; //  0 [20:17]
+  UINT16  WRITE_BL_PARTIAL:   1; //  Partial blocks for write allowed [21:21]
+  UINT16  WRITE_BL_LEN:       4; //  Max. write data block length [25:22]
+  UINT16  R2W_FACTOR:         3; //  Write speed factor [28:26]
+  UINT16  DEFAULT_ECC:        2; //  Manufacturer default ECC [30:29]
+  UINT16  WP_GRP_ENABLE:      1; //  Write protect group enable [31:31]
+  UINT32  WP_GRP_SIZE:        5; //  Write protect group size [36:32]
+  UINT32  ERASE_GRP_MULT:     5; //  Erase group size multiplier [41:37]
+  UINT32  ERASE_GRP_SIZE:     5; //  Erase group size [46:42]
+  UINT32  C_SIZE_MULT:        3; //  Device size multiplier [49:47]
+  UINT32  VDD_W_CURR_MAX:     3; //  Max. write current @ VDD max [52:50]
+  UINT32  VDD_W_CURR_MIN:     3; //  Max. write current @ VDD min [55:53]
+  UINT32  VDD_R_CURR_MAX:     3; //  Max. read current @ VDD max [58:56]
+  UINT32  VDD_R_CURR_MIN:     3; //  Max. read current @ VDD min [61:59]
+  UINT32  C_SIZELow2:         2;//  Device size [73:62]
+  UINT32  C_SIZEHigh10:       10;//  Device size [73:62]
+  UINT32  Reserved1:          2; //  0 [75:74]
+  UINT32  DSR_IMP:            1; //  DSR implemented [76:76]
+  UINT32  READ_BLK_MISALIGN:  1; //  Read block misalignment [77:77]
+  UINT32  WRITE_BLK_MISALIGN: 1; //  Write block misalignment [78:78]
+  UINT32  READ_BL_PARTIAL:    1; //  Partial blocks for read allowed [79:79]
+  UINT32  READ_BL_LEN:        4; //  Max. read data block length [83:80]
+  UINT32  CCC:                12;//  Card command classes [95:84]
+  UINT8   TRAN_SPEED          ; //  Max. bus clock frequency [103:96]
+  UINT8   NSAC                ; //  Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+  UINT8   TAAC                ; //  Data read access-time 1 [119:112]
+  UINT8   Reserved2:          2; //  0 [121:120]
+  UINT8   SPEC_VERS:          4; //  System specification version [125:122]
+  UINT8   CSD_STRUCTURE:      2; //  CSD structure [127:126]
+}CSD;
+
+typedef struct {
+  UINT8  Reserved0[181];         //  0 [0:180]
+  UINT8  ERASED_MEM_CONT;        //  Erased Memory Content [181]
+  UINT8  Reserved2;              //  Erased Memory Content [182]
+  UINT8  BUS_WIDTH;              //  Bus Width Mode [183]
+  UINT8  Reserved3;              //  0 [184]
+  UINT8  HS_TIMING;              //  High Speed Interface Timing [185]
+  UINT8  Reserved4;              //  0 [186]
+  UINT8  POWER_CLASS;            //  Power Class [187]
+  UINT8  Reserved5;              //  0 [188]
+  UINT8  CMD_SET_REV;            //  Command Set Revision [189]
+  UINT8  Reserved6;              //  0 [190]
+  UINT8  CMD_SET;                //  Command Set [191]
+  UINT8  EXT_CSD_REV;            //  Extended CSD Revision [192]
+  UINT8  Reserved7;              //  0 [193]
+  UINT8  CSD_STRUCTURE;          //  CSD Structure Version [194]
+  UINT8  Reserved8;              //  0 [195]
+  UINT8  CARD_TYPE;              //  Card Type [196]
+  UINT8  Reserved9[3];           //  0 [199:197]
+  UINT8  PWR_CL_52_195;          //  Power Class for 52MHz @ 1.95V [200]
+  UINT8  PWR_CL_26_195;          //  Power Class for 26MHz @ 1.95V [201]
+  UINT8  PWR_CL_52_360;          //  Power Class for 52MHz @ 3.6V [202]
+  UINT8  PWR_CL_26_360;          //  Power Class for 26MHz @ 3.6V [203]
+  UINT8  Reserved10;             //  0 [204]
+  UINT8  MIN_PERF_R_4_26;        //  Minimum Read Performance for 4bit @26MHz [205]
+  UINT8  MIN_PERF_W_4_26;        //  Minimum Write Performance for 4bit @26MHz [206]
+  UINT8  MIN_PERF_R_8_26_4_52;   //  Minimum Read Performance for 8bit @26MHz/4bit @52MHz [207]
+  UINT8  MIN_PERF_W_8_26_4_52;   //  Minimum Write Performance for 8bit @26MHz/4bit @52MHz [208]
+  UINT8  MIN_PERF_R_8_52;        //  Minimum Read Performance for 8bit @52MHz [209]
+  UINT8  MIN_PERF_W_8_52;        //  Minimum Write Performance for 8bit @52MHz [210]
+  UINT8  Reserved11;             //  0 [211]
+  UINT8  SEC_COUNT[4];           //  Sector Count [215:212]
+  UINT8  Reserved12[288];        //  0 [503:216]
+  UINT8  S_CMD_SET;              //  Sector Count [504]
+  UINT8  Reserved13[7];          //  Sector Count [511:505]
+}EXT_CSD;
+
+
+//
+//Card Status definition
+//
+typedef struct {
+  UINT32  Reserved0:           2; //Reserved for Manufacturer Test Mode
+  UINT32  Reserved1:           2; //Reserved for Application Specific commands
+  UINT32  Reserved2:           1; //
+  UINT32  SAPP_CMD:            1; //
+  UINT32  Reserved3:           1; //Reserved
+  UINT32  SWITCH_ERROR:        1; //
+  UINT32  READY_FOR_DATA:      1; //
+  UINT32  CURRENT_STATE:       4; //
+  UINT32  ERASE_RESET:         1; //
+  UINT32  Reserved4:           1; //Reserved
+  UINT32  WP_ERASE_SKIP:       1; //
+  UINT32  CID_CSD_OVERWRITE:   1; //
+  UINT32  OVERRUN:             1; //
+  UINT32  UNDERRUN:            1; //
+  UINT32  ERROR:               1; //
+  UINT32  CC_ERROR:            1; //
+  UINT32  CARD_ECC_FAILED:     1; //
+  UINT32  ILLEGAL_COMMAND:     1; //
+  UINT32  COM_CRC_ERROR:       1; //
+  UINT32  LOCK_UNLOCK_FAILED:  1; //
+  UINT32  CARD_IS_LOCKED:      1; //
+  UINT32  WP_VIOLATION:        1; //
+  UINT32  ERASE_PARAM:         1; //
+  UINT32  ERASE_SEQ_ERROR:     1; //
+  UINT32  BLOCK_LEN_ERROR:     1; //
+  UINT32  ADDRESS_MISALIGN:    1; //
+  UINT32  ADDRESS_OUT_OF_RANGE:1; //
+}CARD_STATUS;
+
+typedef struct {
+  UINT32  CmdSet:              3;
+  UINT32  Reserved0:           5;
+  UINT32  Value:               8;
+  UINT32  Index:               8;
+  UINT32  Access:              2;
+  UINT32  Reserved1:           6;
+}SWITCH_ARGUMENT;
+
+#define CommandSet_Mode          0
+#define SetBits_Mode             1
+#define ClearBits_Mode           2
+#define WriteByte_Mode           3
+
+
+#define  Idle_STATE              0
+#define  Ready_STATE             1
+#define  Ident_STATE             2
+#define  Stby_STATE              3
+#define  Tran_STATE              4
+#define  Data_STATE              5
+#define  Rcv_STATE               6
+#define  Prg_STATE               7
+#define  Dis_STATE               8
+#define  Btst_STATE              9
+
+
+
+#pragma pack()
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h
new file mode 100644
index 0000000000..93db8d248a
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h
@@ -0,0 +1,146 @@
+/** @file
+
+Header file for Industry SD Card 2.0 spec.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_CARD_H
+#define _SD_CARD_H
+
+#include "MMC.h"
+
+#pragma pack(1)
+
+#define CHECK_PATTERN     0xAA  ///< Physical Layer Simplified Specification Version 3.01 recommended 0xAA
+
+#define ACMD6             6
+#define ACMD13            13
+#define ACMD23            23
+#define ACMD41            41
+#define ACMD42            42
+#define ACMD51            51
+
+
+#define SWITCH_FUNC              CMD6
+#define SEND_IF_COND             CMD8
+
+
+#define SET_BUS_WIDTH            ACMD6
+#define SD_STATUS                ACMD13
+#define SET_WR_BLK_ERASE_COUNT   ACMD23
+#define SD_SEND_OP_COND          ACMD41
+#define SET_CLR_CARD_DETECT      ACMD42
+#define SEND_SCR                 ACMD51
+
+
+
+#define SD_BUS_WIDTH_1              0
+#define SD_BUS_WIDTH_4              2
+
+
+
+#define FREQUENCY_SD_PP        (25 * 1000 * 1000)
+#define FREQUENCY_SD_PP_HIGH   (50 * 1000 * 1000)
+
+
+#define SD_SPEC_10                  0
+#define SD_SPEC_11                  1
+#define SD_SPEC_20                  2
+
+
+#define VOLTAGE_27_36               0x1
+
+typedef struct {
+  UINT8   NotUsed:            1; //  1 [0:0]
+  UINT8   CRC:                7; //  CRC [7:1]
+  UINT8   ECC:                2; //  ECC code [9:8]
+  UINT8   FILE_FORMAT:        2; //  File format [11:10]
+  UINT8   TMP_WRITE_PROTECT:  1; //  Temporary write protection [12:12]
+  UINT8   PERM_WRITE_PROTECT: 1; //  Permanent write protection [13:13]
+  UINT8   COPY:               1; //  Copy flag (OTP) [14:14]
+  UINT8   FILE_FORMAT_GRP:    1; //  File format group [15:15]
+  UINT16  Reserved0:          5; //  0 [20:16]
+  UINT16  WRITE_BL_PARTIAL:   1; //  Partial blocks for write allowed [21:21]
+  UINT16  WRITE_BL_LEN:       4; //  Max. write data block length [25:22]
+  UINT16  R2W_FACTOR:         3; //  Write speed factor [28:26]
+  UINT16  DEFAULT_ECC:        2; //  Manufacturer default ECC [30:29]
+  UINT16  WP_GRP_ENABLE:      1; //  Write protect group enable [31:31]
+  UINT16  WP_GRP_SIZE:        7; //  Write protect group size [38:32]
+  UINT16  SECTOR_SIZE:        7; //  Erase sector size [45:39]
+  UINT16  ERASE_BLK_EN:       1; //  Erase single block enable [46:46]
+  UINT16  Reserved1:          1; //  0 [47:47]
+
+  UINT32  C_SIZE:             22; //  Device size [69:48]
+  UINT32  Reserved2:          6;  //  0 [75:70]
+  UINT32  DSR_IMP:            1;  //  DSR implemented [76:76]
+  UINT32  READ_BLK_MISALIGN:  1;  //  Read block misalignment [77:77]
+  UINT32  WRITE_BLK_MISALIGN: 1;  //  Write block misalignment [78:78]
+  UINT32  READ_BL_PARTIAL:    1;  //  Partial blocks for read allowed [79:79]
+
+  UINT16  READ_BL_LEN:        4;  //  Max. read data block length [83:80]
+  UINT16  CCC:                12; //  Card command classes [95:84]
+  UINT8   TRAN_SPEED          ;   //  Max. bus clock frequency [103:96]
+  UINT8   NSAC                ;   //  Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+  UINT8   TAAC                ;   //  Data read access-time 1 [119:112]
+  UINT8   Reserved3:          6;  //  0 [125:120]
+  UINT8   CSD_STRUCTURE:      2;  //  CSD structure [127:126]
+}CSD_SDV2;
+
+typedef struct {
+  UINT32  Reserved0;
+  UINT32  Reserved1:               16;
+  UINT32  SD_BUS_WIDTH:            4;
+  UINT32  SD_SECURITY:             3;
+  UINT32  DATA_STAT_AFTER_ERASE:   1;
+  UINT32  SD_SPEC:                 4;
+  UINT32  SCR_STRUCT:              4;
+}SCR;
+
+
+typedef struct {
+  UINT8   Reserved0[50];
+  UINT8   ERASE_OFFSET:               2;
+  UINT8   ERASE_TIMEOUT:              6;
+  UINT16  ERASE_SIZE;
+  UINT8   Reserved1:                  4;
+  UINT8   AU_SIZE:                    4;
+  UINT8   PERFORMANCE_MOVE;
+  UINT8   SPEED_CLASS;
+  UINT32  SIZE_OF_PROTECTED_AREA;
+  UINT32  SD_CARD_TYPE:              16;
+  UINT32  Reserved2:                 13;
+  UINT32  SECURED_MODE:               1;
+  UINT32  DAT_BUS_WIDTH:              2;
+}SD_STATUS_REG;
+
+
+
+typedef struct {
+  UINT8   Reserved0[34];
+  UINT16  Group1BusyStatus;
+  UINT16  Group2BusyStatus;
+  UINT16  Group3BusyStatus;
+  UINT16  Group4BusyStatus;
+  UINT16  Group5BusyStatus;
+  UINT16  Group6BusyStatus;
+  UINT8   DataStructureVersion;
+  UINT8   Group21Status;
+  UINT8   Group43Status;
+  UINT8   Group65Status;
+  UINT16  Group1Function;
+  UINT16  Group2Function;
+  UINT16  Group3Function;
+  UINT16  Group4Function;
+  UINT16  Group5Function;
+  UINT16  Group6Function;
+  UINT16  MaxCurrent;
+}SWITCH_STATUS;
+
+
+#pragma pack()
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h
new file mode 100644
index 0000000000..7ce0793390
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h
@@ -0,0 +1,333 @@
+/** @file
+
+Interface definition for EFI_SD_HOST_IO_PROTOCOL.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_HOST_IO_H
+#define _SD_HOST_IO_H
+
+#include "SDCard.h"
+#include "CEATA.h"
+
+
+#define EFI_SD_HOST_IO_PROTOCOL_GUID  \
+  { \
+    0xb63f8ec7, 0xa9c9, 0x4472, {0xa4, 0xc0, 0x4d, 0x8b, 0xf3, 0x65, 0xcc, 0x51} \
+  }
+
+///
+/// Forward reference for pure ANSI compatability
+///
+typedef struct _EFI_SD_HOST_IO_PROTOCOL EFI_SD_HOST_IO_PROTOCOL;
+
+
+
+typedef enum {
+  ResponseNo = 0,
+  ResponseR1,
+  ResponseR1b,
+  ResponseR2,
+  ResponseR3,
+  ResponseR4,
+  ResponseR5,
+  ResponseR5b,
+  ResponseR6,
+  ResponseR7
+}RESPONSE_TYPE;
+
+typedef enum {
+  NoData = 0,
+  InData,
+  OutData
+}TRANSFER_TYPE;
+
+typedef enum {
+  Reset_Auto = 0,
+  Reset_DAT,
+  Reset_CMD,
+  Reset_DAT_CMD,
+  Reset_All
+}RESET_TYPE;
+
+#define PCI_SUBCLASS_SD_HOST_CONTROLLER           0x05
+#define PCI_IF_STANDARD_HOST_NO_DMA               0x00
+#define PCI_IF_STANDARD_HOST_SUPPORT_DMA          0x01
+
+#define   SDHCI_SPEC_100                          0
+#define   SDHCI_SPEC_200                          1
+#define   SDHCI_SPEC_300                          2
+
+//
+//MMIO Registers definition for MMC/SDIO controller
+//
+#define  MMIO_DMAADR                              0x00
+#define  MMIO_BLKSZ                               0x04
+#define  MMIO_BLKCNT                              0x06
+#define  MMIO_CMDARG                              0x08
+#define  MMIO_XFRMODE                             0x0C
+#define  MMIO_SDCMD                               0x0E
+#define  MMIO_RESP                                0x10
+#define  MMIO_BUFDATA                             0x20
+#define  MMIO_PSTATE                              0x24
+#define  MMIO_HOSTCTL                             0x28
+#define  MMIO_PWRCTL                              0x29
+#define  MMIO_BLKGAPCTL                           0x2A
+#define  MMIO_WAKECTL                             0x2B
+#define  MMIO_CLKCTL                              0x2C
+#define   V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL           0x80
+#define   V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL          0x3FF
+#define   B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK     0xC0
+
+#define  MMIO_TOCTL                               0x2E
+#define  MMIO_SWRST                               0x2F
+#define  MMIO_NINTSTS                             0x30
+#define  MMIO_ERINTSTS                            0x32
+#define  MMIO_NINTEN                              0x34
+#define  MMIO_ERINTEN                             0x36
+#define  MMIO_NINTSIGEN                           0x38
+#define  MMIO_ERINTSIGEN                          0x3A
+#define  MMIO_AC12ERRSTS                          0x3C
+#define  MMIO_HOSTCTL2                            0x3E
+#define  MMIO_CAP                                 0x40
+#define  MMIO_MCCAP                               0x48
+#define  MMIO_SLTINTSTS                           0xFC
+#define  MMIO_CTRLRVER                            0xFE
+#define  MMIO_SRST                                0x1FC
+
+//
+// Protocol definitions
+//
+
+/**
+  The main function used to send the command to the card inserted into the SD host slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  CommandIndex          The command index to set the command index field of command register.
+  @param  Argument              Command argument to set the argument field of command register.
+  @param  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param  Buffer                Contains the data read from / write to the device.
+  @param  BufferSize            The size of the buffer.
+  @param  ResponseType          RESPONSE_TYPE.
+  @param  TimeOut               Time out value in 1 ms unit.
+  @param  ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_OUT_OF_RESOURCES
+  @retval EFI_TIMEOUT
+  @retval EFI_DEVICE_ERROR
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SEND_COMMAND) (
+  IN   EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  );
+
+/**
+  Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+  It depends on the max frequency the host can support, divider, and host speed mode.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  MaxFrequency          Max frequency in HZ.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_CLOCK_FREQUENCY) (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     MaxFrequency
+  );
+
+
+/**
+  Set bus width of the host controller
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  BusWidth              Bus width in 1, 4, 8 bits.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_BUS_WIDTH) (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BusWidth
+  );
+
+/**
+  Set voltage which could supported by the host controller.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Voltage               Units in 0.1 V.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_HOST_VOLTAGE) (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     Voltage
+  );
+
+/**
+  Reset the host controller.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  ResetAll              TRUE to reset all.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_RESET_SD_HOST) (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  RESET_TYPE                 ResetType
+  );
+
+/**
+  Enable auto stop on the host controller.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Enable                TRUE to enable, FALSE to disable.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_ENABLE_AUTO_STOP_CMD) (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+/**
+  Find whether these is a card inserted into the slot. If so init the host.
+  If not, return EFI_NOT_FOUND.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+  @retval EFI_SUCCESS
+  @retval EFI_NOT_FOUND
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_DETECT_CARD_AND_INIT_HOST) (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This
+  );
+
+/**
+  Set the Block length on the host controller.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  BlockLength           card supportes block length.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_BLOCK_LENGTH) (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BlockLength
+  );
+
+/**
+  Enable/Disable High Speed transfer mode
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Enable                TRUE to Enable, FALSE to Disable
+
+  @return EFI_SUCCESS
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_HIGH_SPEED_MODE) (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_DUAL_DATARATE_MODE) (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+
+
+#define EFI_SD_HOST_IO_PROTOCOL_REVISION_01          0x02
+
+
+typedef struct {
+  UINT32  HighSpeedSupport:    1;  //High speed supported
+  UINT32  V18Support:          1;  //1.8V supported
+  UINT32  V30Support:          1;  //3.0V supported
+  UINT32  V33Support:          1;  //3.3V supported
+  UINT32  Reserved0:           4;
+  UINT32  HostVersion:         8;
+  UINT32  BusWidth4:           1;  // 4 bit width
+  UINT32  BusWidth8:           1;  // 8 bit width
+  UINT32  Reserved1:           14;
+  UINT32  BoundarySize;
+}HOST_CAPABILITY;
+
+
+//
+// Interface structure for the SD HOST I/O Protocol
+//
+struct _EFI_SD_HOST_IO_PROTOCOL {
+  UINT32                                             Revision;
+  HOST_CAPABILITY                                    HostCapability;
+  EFI_SD_HOST_IO_PROTOCOL_SEND_COMMAND               SendCommand;
+  EFI_SD_HOST_IO_PROTOCOL_SET_CLOCK_FREQUENCY        SetClockFrequency;
+  EFI_SD_HOST_IO_PROTOCOL_SET_BUS_WIDTH              SetBusWidth;
+  EFI_SD_HOST_IO_PROTOCOL_SET_HOST_VOLTAGE           SetHostVoltage;
+  EFI_SD_HOST_IO_PROTOCOL_RESET_SD_HOST              ResetSDHost;
+  EFI_SD_HOST_IO_PROTOCOL_ENABLE_AUTO_STOP_CMD       EnableAutoStopCmd;
+  EFI_SD_HOST_IO_PROTOCOL_DETECT_CARD_AND_INIT_HOST  DetectCardAndInitHost;
+  EFI_SD_HOST_IO_PROTOCOL_SET_BLOCK_LENGTH           SetBlockLength;
+  EFI_SD_HOST_IO_PROTOCOL_HIGH_SPEED_MODE            SetHighSpeedMode;
+  EFI_SD_HOST_IO_PROTOCOL_DUAL_DATARATE_MODE         SetDDRMode;
+};
+
+extern EFI_GUID gEfiSDHostIoProtocolGuid;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h
new file mode 100644
index 0000000000..dfc8a244c5
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h
@@ -0,0 +1,55 @@
+/** @file
+Common header file shared by all source files.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __COMMON_HEADER_H_
+#define __COMMON_HEADER_H_
+
+//
+// The package level header files this module uses
+//
+#include <PiDxe.h>
+#include <Ioh.h>
+#include <IohCommonDefinitions.h>
+
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Protocol/PciRootBridgeIo.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/DevicePath.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/S3PciLib.h>
+#include <Library/S3IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/TimerLib.h>
+#include <Library/IoLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IohLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <IndustryStandard/Pci.h>
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h
new file mode 100644
index 0000000000..1212ab86fd
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h
@@ -0,0 +1,83 @@
+/** @file
+Head file for BDS Platform specific code
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IOH_BDS_H
+#define _IOH_BDS_H
+
+#include <Ioh.h>
+#include <Protocol/DevicePath.h>
+#include <Library/DevicePathLib.h>
+
+extern EFI_DEVICE_PATH_PROTOCOL  *gDeviceConnectOption [];
+
+#define PCI_DEVICE_PATH_NODE(Func, Dev) \
+  { \
+    { \
+      HARDWARE_DEVICE_PATH, \
+      HW_PCI_DP, \
+      { \
+        (UINT8) (sizeof (PCI_DEVICE_PATH)), \
+        (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
+      } \
+    }, \
+    (Func), \
+    (Dev) \
+  }
+
+#define PNPID_DEVICE_PATH_NODE(PnpId) \
+  { \
+    { \
+      ACPI_DEVICE_PATH, \
+      ACPI_DP, \
+      { \
+        (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
+        (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
+      } \
+    }, \
+    EISA_PNP_ID((PnpId)), \
+    0 \
+  }
+
+
+
+#define gEndEntire \
+  { \
+    END_DEVICE_PATH_TYPE, \
+    END_ENTIRE_DEVICE_PATH_SUBTYPE, \
+    { \
+      END_DEVICE_PATH_LENGTH, \
+      0 \
+    } \
+  }
+
+#define gPciRootBridge \
+  PNPID_DEVICE_PATH_NODE(0x0A03)
+
+
+//
+// Platform Root Bridge
+//
+typedef struct {
+  ACPI_HID_DEVICE_PATH      PciRootBridge;
+  EFI_DEVICE_PATH_PROTOCOL  End;
+} PLATFORM_ROOT_BRIDGE_DEVICE_PATH;
+
+
+typedef struct {
+  ACPI_HID_DEVICE_PATH      PciRootBridge;
+  PCI_DEVICE_PATH           IohDevice;
+  EFI_DEVICE_PATH_PROTOCOL  End;
+} IOH_PCI_USB_DEVICE_PATH;
+
+//
+// Ioh BDS Functions
+//
+
+
+#endif // _IOH_BDS_H
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c
new file mode 100644
index 0000000000..cf6006626b
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c
@@ -0,0 +1,42 @@
+/** @file
+Defined the Ioh device path which will be used by
+platform Bbd to perform the platform policy connect.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "IohBds.h"
+
+//
+// Predefined platform root bridge
+//
+PLATFORM_ROOT_BRIDGE_DEVICE_PATH gPlatformRootBridge0 = {
+  gPciRootBridge,
+  gEndEntire
+};
+
+EFI_DEVICE_PATH_PROTOCOL* gPlatformRootBridges [] = {
+  (EFI_DEVICE_PATH_PROTOCOL*)&gPlatformRootBridge0,
+  NULL
+};
+
+//
+// Ioh USB EHCI controller device path
+//
+IOH_PCI_USB_DEVICE_PATH gIohUsbDevicePath0 = {
+  gPciRootBridge,
+  PCI_DEVICE_PATH_NODE(IOH_EHCI_FUNCTION_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER),
+  gEndEntire
+};
+
+//
+// Ioh predefined device connecting option
+//
+EFI_DEVICE_PATH_PROTOCOL* gDeviceConnectOption [] = {
+  //  (EFI_DEVICE_PATH_PROTOCOL*)&gIohUsbDevicePath0,
+  NULL
+};
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c
new file mode 100644
index 0000000000..8ea791a88c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c
@@ -0,0 +1,37 @@
+/** @file
+QuarkSCSocId module initialization module
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "CommonHeader.h"
+#include "IohBds.h"
+
+/**
+   The entry function for IohInit driver.
+
+   This function just call initialization function.
+
+   @param ImageHandle   The driver image handle for GmchInit driver
+   @param SystemTable   The pointer to System Table
+
+   @retval EFI_SUCCESS  Success to initialize every module.
+   @return EFI_STATUS   The status of initialization work.
+
+**/
+EFI_STATUS
+EFIAPI
+IohInit (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+
+  InitializeIohSsvidSsid(IOH_BUS, IOH_PCI_IOSF2AHB_0_DEV_NUM, 0);
+
+  InitializeIohSsvidSsid(IOH_BUS, IOH_PCI_IOSF2AHB_1_DEV_NUM, 0);
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf
new file mode 100644
index 0000000000..264a9eea7d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf
@@ -0,0 +1,76 @@
+## @file
+# Component description file for Quark South Cluster Init driver.
+#
+# IohInit driver implement QuarkSCSocId related drivers, includes:
+# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver.
+#
+# This driver mainly do full initialization for the Soc chipet includes:
+# 1. Initialize the PCI Express device.
+# 2. Initialize the PciHostBridge, and allocate the I/O and memory space from GCD service.
+# 3. Initialize the SmmAccess module and install EFI_SMM_ACCESS_PROTOCOL
+# 4. Initialize the LegacyRegion module, install EFI_LEGACY_REGION_PROTOCOL and set below 1M
+#    memory attribute from MTRR.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = IohInitDxe
+  FILE_GUID                      = 3FE2A8A3-C400-48F8-832F-7881A394C250
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = IohInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  IohInit.c
+  IohBds.h
+  IohData.c
+  CommonHeader.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  S3BootScriptLib
+  PcdLib
+  HobLib
+  PciLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  S3PciLib
+  UefiLib
+  DebugLib
+  UefiRuntimeServicesTableLib
+  UefiBootServicesTableLib
+  DxeServicesTableLib
+  UefiDriverEntryPoint
+  BaseLib
+  S3IoLib
+  IoLib
+  DevicePathLib
+  IohLib
+
+[Protocols]
+  gEfiPciRootBridgeIoProtocolGuid               # PROTOCOL ALWAYS_PRODUCED
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED
+  gEfiPciIoProtocolGuid
+
+[Pcd]
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartBusNumber
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartDevNumber
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartFunctionNumber
+
+[Depex]
+  TRUE
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h
new file mode 100644
index 0000000000..67c66ff4ac
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h
@@ -0,0 +1,214 @@
+/** @file
+Provides definition of entry point to the common I2C module that produces
+common I2C Controller functions used by I2C library services.
+
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _I2CCOMMON_H_
+#define _I2CCOMMON_H_
+
+#include <Uefi.h>
+#include <Base.h>
+
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/I2cLib.h>
+#include <IohAccess.h>
+#include <IohCommonDefinitions.h>
+#include "I2cRegs.h"
+
+//
+// Constants that define I2C Controller timeout and max. polling time.
+//
+#define MAX_T_POLL_COUNT         100
+#define TI2C_POLL                25  // microseconds
+#define MAX_STOP_DET_POLL_COUNT ((1000 * 1000) / TI2C_POLL)  // Extreme for expected Stop detect.
+
+/**
+  The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.
+
+  Always reads PCI configuration space to get MMIO base address of I2C Controller.
+
+  @return The IO port base address of I2C controller.
+
+**/
+UINTN
+GetI2CIoPortBaseAddress (
+  VOID
+  );
+
+/**
+  The EnableI2CMmioSpace() function enables access to I2C MMIO space.
+
+**/
+VOID
+EnableI2CMmioSpace (
+  VOID
+  );
+
+/**
+  The DisableI2CController() functions disables I2C Controller.
+
+**/
+VOID
+DisableI2CController (
+  VOID
+  );
+
+/**
+  The EnableI2CController() function enables the I2C Controller.
+
+**/
+VOID
+EnableI2CController (
+  VOID
+  );
+
+/**
+  The WaitForStopDet() function waits until I2C STOP Condition occurs,
+  indicating transfer completion.
+
+  @retval EFI_SUCCESS           Stop detected.
+  @retval EFI_TIMEOUT           Timeout while waiting for stop condition.
+  @retval EFI_ABORTED           Tx abort signaled in HW status register.
+  @retval EFI_DEVICE_ERROR      Tx or Rx overflow detected.
+
+**/
+EFI_STATUS
+WaitForStopDet (
+  VOID
+  );
+
+/**
+
+  The InitializeInternal() function initialises internal I2C Controller
+  register values that are commonly required for I2C Write and Read transfers.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @retval EFI_SUCCESS           I2C Operation completed successfully.
+
+**/
+EFI_STATUS
+InitializeInternal (
+  IN EFI_I2C_ADDR_MODE  AddrMode
+  );
+
+/**
+
+  The WriteByte() function provides a standard way to execute a
+  standard single byte write to an IC2 device (without accessing
+  sub-addresses), as defined in the I2C Specification.
+
+  @param  I2CAddress      I2C Slave device address
+  @param  Value           The 8-bit value to write.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteByte (
+  IN  UINTN          I2CAddress,
+  IN  UINT8          Value
+  );
+
+/**
+
+  The ReadByte() function provides a standard way to execute a
+  standard single byte read to an IC2 device (without accessing
+  sub-addresses), as defined in the I2C Specification.
+
+  @param  I2CAddress      I2C Slave device address
+  @param  ReturnDataPtr   Pointer to location to receive read byte.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadByte (
+  IN  UINTN          I2CAddress,
+  OUT UINT8          *ReturnDataPtr
+  );
+
+/**
+
+  The WriteMultipleByte() function provides a standard way to execute
+  multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+  when writing block of data), as defined in the I2C Specification.
+
+  @param I2CAddress   The I2C slave address of the device
+                      with which to communicate.
+
+  @param WriteBuffer  Contains the value of byte to be written to the
+                      I2C slave device.
+
+  @param Length       No. of bytes to be written.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Tx abort signaled in HW status register.
+  @retval EFI_DEVICE_ERROR      Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteMultipleByte (
+  IN  UINTN          I2CAddress,
+  IN  UINT8          *WriteBuffer,
+  IN  UINTN          Length
+  );
+
+/**
+
+  The ReadMultipleByte() function provides a standard way to execute
+  multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+  when reading block of data), as defined in the I2C Specification (I2C combined
+  write/read protocol).
+
+  @param I2CAddress   The I2C slave address of the device
+                      with which to communicate.
+
+  @param Buffer       Contains the value of byte data written or read from the
+                      I2C slave device.
+
+  @param WriteLength  No. of bytes to be written. In this case data
+                      written typically contains sub-address or sub-addresses
+                      in Hi-Lo format, that need to be read (I2C combined
+                      write/read protocol).
+
+  @param ReadLength   No. of bytes to be read from I2C slave device.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Tx abort signaled in HW status register.
+  @retval EFI_DEVICE_ERROR      Rx underflow or Rx/Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadMultipleByte (
+  IN  UINTN          I2CAddress,
+  IN  OUT UINT8      *Buffer,
+  IN  UINTN          WriteLength,
+  IN  UINTN          ReadLength
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c
new file mode 100644
index 0000000000..de99361f46
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c
@@ -0,0 +1,998 @@
+/** @file
+I2C Library for Quark I2C Controller.
+Follows I2C Controller setup instructions as detailed in
+Quark DataSheet (doc id: 329676) Section 19.1/19.1.3.
+
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CommonHeader.h"
+
+/**
+  The Called to Common Service Entry.
+
+  @return None.
+
+**/
+
+VOID
+I2cCommonServiceEntry  (
+  OUT UINT16 *SaveCmdPtr,
+  OUT UINT32 *SaveBar0Ptr
+  )
+{
+  *SaveBar0Ptr = IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
+  if (((*SaveBar0Ptr) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
+
+    IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) =
+      FixedPcdGet32 (PcdIohI2cMmioBase) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK;
+
+    //
+    // also Save Cmd Register, Setup by InitializeInternal later during xfers.
+    //
+    *SaveCmdPtr = IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD);
+  }
+}
+
+/**
+  The Called on Common Service Exit.
+
+  @return None.
+
+**/
+VOID
+I2cCommonServiceExit  (
+  IN CONST UINT16 SaveCmd,
+  IN CONST UINT32 SaveBar0
+
+  )
+{
+  if ((SaveBar0 & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
+    IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD) = SaveCmd;
+    IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) = SaveBar0;
+  }
+}
+
+
+/**
+  The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.
+
+  Always reads PCI configuration space to get MMIO base address of I2C Controller.
+
+  @return The IO port base address of I2C controller.
+
+**/
+UINTN
+GetI2CIoPortBaseAddress (
+  VOID
+  )
+{
+  UINTN     I2CIoPortBaseAddress;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
+
+  //
+  // Make sure that the IO port base address has been properly set.
+  //
+  ASSERT (I2CIoPortBaseAddress != 0);
+  ASSERT (I2CIoPortBaseAddress != 0xFF);
+
+  return I2CIoPortBaseAddress;
+}
+
+
+/**
+  The EnableI2CMmioSpace() function enables access to I2C MMIO space.
+
+**/
+VOID
+EnableI2CMmioSpace (
+  VOID
+  )
+{
+  UINT8 PciCmd;
+
+  //
+  // Read PCICMD.  Bus=0, Dev=0, Func=0, Reg=0x4
+  //
+  PciCmd = IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD);
+
+  //
+  // Enable Bus Master(Bit2), MMIO Space(Bit1) & I/O Space(Bit0)
+  //
+  PciCmd |= 0x7;
+  IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD) = PciCmd;
+
+}
+
+/**
+  The DisableI2CController() functions disables I2C Controller.
+
+**/
+VOID
+DisableI2CController (
+  VOID
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINT32      Addr;
+  UINT32      Data;
+  UINT8       PollCount;
+
+  PollCount = 0;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Disable the I2C Controller by setting IC_ENABLE.ENABLE to zero
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_ENABLE;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Read the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled
+  //
+  Data = 0xFF;
+  Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE_STATUS;
+  Data = *((volatile UINT32 *) (UINTN)(Addr)) & I2C_REG_ENABLE_STATUS;
+  while (Data != 0) {
+    //
+    // Poll the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled, until timeout (TI2C_POLL*MAX_T_POLL_COUNT).
+    //
+    PollCount++;
+    if (PollCount >= MAX_T_POLL_COUNT) {
+      break;
+    }
+    MicroSecondDelay(TI2C_POLL);
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= I2C_REG_ENABLE_STATUS;
+  }
+
+  //
+  // Asset if controller does not enter Disabled state.
+  //
+  ASSERT (PollCount < MAX_T_POLL_COUNT);
+
+  //
+  // Read IC_CLR_INTR register to automatically clear the combined interrupt,
+  // all individual interrupts and the IC_TX_ABRT_SOURCE register.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_INT;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+}
+
+/**
+  The EnableI2CController() function enables the I2C Controller.
+
+**/
+VOID
+EnableI2CController (
+  VOID
+  )
+{
+  UINTN   I2CIoPortBaseAddress;
+  UINT32  Addr;
+  UINT32  Data;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Enable the I2C Controller by setting IC_ENABLE.ENABLE to 1
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data |= B_I2C_REG_ENABLE;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Clear overflow and abort error status bits before transactions.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_OVER;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_OVER;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_ABRT;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+}
+
+/**
+  The WaitForStopDet() function waits until I2C STOP Condition occurs,
+  indicating transfer completion.
+
+  @retval EFI_SUCCESS           Stop detected.
+  @retval EFI_TIMEOUT           Timeout while waiting for stop condition.
+  @retval EFI_ABORTED           Tx abort signaled in HW status register.
+  @retval EFI_DEVICE_ERROR      Tx or Rx overflow detected.
+
+**/
+EFI_STATUS
+WaitForStopDet (
+  VOID
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINT32      Addr;
+  UINT32      Data;
+  UINT32      PollCount;
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  PollCount = 0;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Wait for STOP Detect.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+
+  do {
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    if ((Data & I2C_REG_RAW_INTR_STAT_TX_ABRT) != 0) {
+      Status = EFI_ABORTED;
+      break;
+    }
+    if ((Data & I2C_REG_RAW_INTR_STAT_TX_OVER) != 0) {
+      Status = EFI_DEVICE_ERROR;
+      break;
+    }
+    if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
+      Status = EFI_DEVICE_ERROR;
+      break;
+    }
+    if ((Data & I2C_REG_RAW_INTR_STAT_STOP_DET) != 0) {
+      Status = EFI_SUCCESS;
+      break;
+    }
+    MicroSecondDelay(TI2C_POLL);
+    PollCount++;
+    if (PollCount >= MAX_STOP_DET_POLL_COUNT) {
+      Status = EFI_TIMEOUT;
+      break;
+    }
+
+  } while (TRUE);
+
+  return Status;
+}
+
+/**
+
+  The InitializeInternal() function initialises internal I2C Controller
+  register values that are commonly required for I2C Write and Read transfers.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @retval EFI_SUCCESS           I2C Operation completed successfully.
+
+**/
+EFI_STATUS
+InitializeInternal (
+  IN  EFI_I2C_ADDR_MODE  AddrMode
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Addr;
+  UINT32      Data;
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  //
+  // Enable access to I2C Controller MMIO space.
+  //
+  EnableI2CMmioSpace ();
+
+  //
+  // Disable I2C Controller initially
+  //
+  DisableI2CController ();
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Clear START_DET
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_START_DET;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_CLR_START_DET;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Clear STOP_DET
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_STOP_DET;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_CLR_STOP_DET;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Set addressing mode to user defined (7 or 10 bit) and
+  // speed mode to that defined by PCD (standard mode default).
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CON;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  // Set Addressing Mode
+  if (AddrMode == EfiI2CSevenBitAddrMode) {
+    Data &= ~B_I2C_REG_CON_10BITADD_MASTER;
+  } else {
+    Data |= B_I2C_REG_CON_10BITADD_MASTER;
+  }
+  // Set Speed Mode
+  Data &= ~B_I2C_REG_CON_SPEED;
+  if (FeaturePcdGet (PcdI2CFastModeEnabled)) {
+    Data |= BIT2;
+  } else {
+    Data |= BIT1;
+  }
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+  return Status;
+
+}
+
+/**
+
+  The WriteByte() function provides a standard way to execute a
+  standard single byte write to an IC2 device (without accessing
+  sub-addresses), as defined in the I2C Specification.
+
+  @param  I2CAddress      I2C Slave device address
+  @param  Value           The 8-bit value to write.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteByte (
+  IN  UINTN          I2CAddress,
+  IN  UINT8          Value
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Addr;
+  UINT32      Data;
+  EFI_STATUS  Status;
+
+  //
+  // Get I2C Memory Mapped registers base address
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Write to the IC_TAR register the address of the slave device to be addressed
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_TAR;
+  Data |= I2CAddress;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Enable the I2C Controller
+  //
+  EnableI2CController ();
+
+  //
+  // Write the data and transfer direction to the IC_DATA_CMD register.
+  // Also specify that transfer should be terminated by STOP condition.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= 0xFFFFFF00;
+  Data |= (UINT8)Value;
+  Data &= ~B_I2C_REG_DATA_CMD_RW;
+  Data |= B_I2C_REG_DATA_CMD_STOP;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Wait for transfer completion.
+  //
+  Status = WaitForStopDet ();
+
+  //
+  // Ensure I2C Controller disabled.
+  //
+  DisableI2CController();
+
+  return Status;
+}
+
+/**
+
+  The ReadByte() function provides a standard way to execute a
+  standard single byte read to an IC2 device (without accessing
+  sub-addresses), as defined in the I2C Specification.
+
+  @param  I2CAddress      I2C Slave device address
+  @param  ReturnDataPtr   Pointer to location to receive read byte.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadByte (
+  IN  UINTN          I2CAddress,
+  OUT UINT8          *ReturnDataPtr
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Addr;
+  UINT32      Data;
+  EFI_STATUS  Status;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Write to the IC_TAR register the address of the slave device to be addressed
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_TAR;
+  Data |= I2CAddress;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Enable the I2C Controller
+  //
+  EnableI2CController ();
+
+  //
+  // Write transfer direction to the IC_DATA_CMD register and
+  // specify that transfer should be terminated by STOP condition.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= 0xFFFFFF00;
+  Data |= B_I2C_REG_DATA_CMD_RW;
+  Data |= B_I2C_REG_DATA_CMD_STOP;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Wait for transfer completion
+  //
+  Status = WaitForStopDet ();
+  if (!EFI_ERROR(Status)) {
+
+    //
+    // Clear RX underflow before reading IC_DATA_CMD.
+    //
+    Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+    //
+    // Obtain and return read data byte from RX buffer (IC_DATA_CMD[7:0]).
+    //
+    Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= 0x000000FF;
+    *ReturnDataPtr = (UINT8) Data;
+
+    Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
+    if (Data != 0) {
+      Status = EFI_DEVICE_ERROR;
+    }
+  }
+
+  //
+  // Ensure I2C Controller disabled.
+  //
+  DisableI2CController ();
+
+  return Status;
+}
+
+/**
+
+  The WriteMultipleByte() function provides a standard way to execute
+  multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+  when writing block of data), as defined in the I2C Specification.
+
+  @param I2CAddress   The I2C slave address of the device
+                      with which to communicate.
+
+  @param WriteBuffer  Contains the value of byte to be written to the
+                      I2C slave device.
+
+  @param Length       No. of bytes to be written.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Tx abort signaled in HW status register.
+  @retval EFI_DEVICE_ERROR      Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteMultipleByte (
+  IN  UINTN          I2CAddress,
+  IN  UINT8          *WriteBuffer,
+  IN  UINTN          Length
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Index;
+  UINTN       Addr;
+  UINT32      Data;
+  EFI_STATUS  Status;
+
+  if (Length > I2C_FIFO_SIZE) {
+    return EFI_UNSUPPORTED;  // Routine does not handle xfers > fifo size.
+  }
+
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Write to the IC_TAR register the address of the slave device to be addressed
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_TAR;
+  Data |= I2CAddress;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Enable the I2C Controller
+  //
+  EnableI2CController ();
+
+  //
+  // Write the data and transfer direction to the IC_DATA_CMD register.
+  // Also specify that transfer should be terminated by STOP condition.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+  for (Index = 0; Index < Length; Index++) {
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= 0xFFFFFF00;
+    Data |= (UINT8)WriteBuffer[Index];
+    Data &= ~B_I2C_REG_DATA_CMD_RW;
+    if (Index == (Length-1)) {
+      Data |= B_I2C_REG_DATA_CMD_STOP;
+    }
+    *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+  }
+
+  //
+  // Wait for transfer completion
+  //
+  Status = WaitForStopDet ();
+
+  //
+  // Ensure I2C Controller disabled.
+  //
+  DisableI2CController ();
+  return Status;
+}
+
+/**
+
+  The ReadMultipleByte() function provides a standard way to execute
+  multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+  when reading block of data), as defined in the I2C Specification (I2C combined
+  write/read protocol).
+
+  @param I2CAddress   The I2C slave address of the device
+                      with which to communicate.
+
+  @param Buffer       Contains the value of byte data written or read from the
+                      I2C slave device.
+
+  @param WriteLength  No. of bytes to be written. In this case data
+                      written typically contains sub-address or sub-addresses
+                      in Hi-Lo format, that need to be read (I2C combined
+                      write/read protocol).
+
+  @param ReadLength   No. of bytes to be read from I2C slave device.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Tx abort signaled in HW status register.
+  @retval EFI_DEVICE_ERROR      Rx underflow or Rx/Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadMultipleByte (
+  IN  UINTN          I2CAddress,
+  IN  OUT UINT8      *Buffer,
+  IN  UINTN          WriteLength,
+  IN  UINTN          ReadLength
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Index;
+  UINTN       Addr;
+  UINT32      Data;
+  UINT8       PollCount;
+  EFI_STATUS  Status;
+
+  if (WriteLength > I2C_FIFO_SIZE || ReadLength > I2C_FIFO_SIZE) {
+    return EFI_UNSUPPORTED;  // Routine does not handle xfers > fifo size.
+  }
+
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Write to the IC_TAR register the address of the slave device to be addressed
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_TAR;
+  Data |= I2CAddress;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Enable the I2C Controller
+  //
+  EnableI2CController ();
+
+  //
+  // Write the data (sub-addresses) to the IC_DATA_CMD register.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+  for (Index = 0; Index < WriteLength; Index++) {
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= 0xFFFFFF00;
+    Data |= (UINT8)Buffer[Index];
+    Data &= ~B_I2C_REG_DATA_CMD_RW;
+    *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+  }
+
+  //
+  // Issue Read Transfers for each byte (Restart issued when write/read bit changed).
+  //
+  for (Index = 0; Index < ReadLength; Index++) {
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data |= B_I2C_REG_DATA_CMD_RW;
+    // Issue a STOP for last read transfer.
+    if (Index == (ReadLength-1)) {
+      Data |= B_I2C_REG_DATA_CMD_STOP;
+    }
+    *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+  }
+
+  //
+  // Wait for STOP condition.
+  //
+  Status = WaitForStopDet ();
+  if (!EFI_ERROR(Status)) {
+
+    //
+    // Poll Receive FIFO Buffer Level register until valid (upto MAX_T_POLL_COUNT times).
+    //
+    Data = 0;
+    PollCount = 0;
+    Addr = I2CIoPortBaseAddress + I2C_REG_RXFLR;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    while ((Data != ReadLength) && (PollCount < MAX_T_POLL_COUNT)) {
+      MicroSecondDelay(TI2C_POLL);
+      PollCount++;
+      Data = *((volatile UINT32 *) (UINTN)(Addr));
+    }
+
+    Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+    //
+    // If no timeout or device error then read rx data.
+    //
+    if (PollCount == MAX_T_POLL_COUNT) {
+      Status = EFI_TIMEOUT;
+    } else if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
+      Status = EFI_DEVICE_ERROR;
+    } else {
+
+      //
+      // Clear RX underflow before reading IC_DATA_CMD.
+      //
+      Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
+      Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+      //
+      // Read data.
+      //
+      Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+      for (Index = 0; Index < ReadLength; Index++) {
+        Data = *((volatile UINT32 *) (UINTN)(Addr));
+        Data &= 0x000000FF;
+        *(Buffer+Index) = (UINT8)Data;
+      }
+      Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+      Data = *((volatile UINT32 *) (UINTN)(Addr));
+      Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
+      if (Data != 0) {
+        Status = EFI_DEVICE_ERROR;
+      } else {
+        Status = EFI_SUCCESS;
+      }
+    }
+  }
+
+  //
+  // Ensure I2C Controller disabled.
+  //
+  DisableI2CController ();
+
+  return Status;
+}
+
+/**
+
+  The I2cWriteByte() function is a wrapper function for the WriteByte function.
+  Provides a standard way to execute a standard single byte write to an IC2 device
+  (without accessing sub-addresses), as defined in the I2C Specification.
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param Buffer       Contains the value of byte data to execute to the
+                      I2C slave device.
+
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_INVALID_PARAMETER  This or Buffer pointers are invalid.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN OUT VOID                       *Buffer
+  )
+{
+  EFI_STATUS Status;
+  UINTN      I2CAddress;
+  UINT16            SaveCmd;
+  UINT32            SaveBar0;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  SaveCmd = 0;
+  SaveBar0 = 0;
+
+  I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+  Status = EFI_SUCCESS;
+
+  I2CAddress = SlaveAddress.I2CDeviceAddress;
+  Status = InitializeInternal (AddrMode);
+  if (!EFI_ERROR(Status)) {
+    Status = WriteByte (I2CAddress, *(UINT8 *) Buffer);
+  }
+
+  I2cCommonServiceExit (SaveCmd, SaveBar0);
+  return Status;
+}
+
+/**
+
+  The I2cReadByte() function is a wrapper function for the ReadByte function.
+  Provides a standard way to execute a standard single byte read to an I2C device
+  (without accessing sub-addresses), as defined in the I2C Specification.
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param Buffer       Contains the value of byte data read from the
+                      I2C slave device.
+
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN OUT    VOID                    *Buffer
+  )
+{
+  EFI_STATUS Status;
+  UINTN      I2CAddress;
+  UINT16     SaveCmd;
+  UINT32     SaveBar0;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  SaveCmd = 0;
+  SaveBar0 =0;
+
+  I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+  Status = EFI_SUCCESS;
+
+  I2CAddress = SlaveAddress.I2CDeviceAddress;
+
+  Status = InitializeInternal (AddrMode);
+  if (!EFI_ERROR(Status)) {
+    Status = ReadByte (I2CAddress, (UINT8 *) Buffer);
+  }
+  I2cCommonServiceExit (SaveCmd, SaveBar0);
+  return Status;
+}
+
+/**
+
+  The I2cWriteMultipleByte() function is a wrapper function for the
+  WriteMultipleByte() function. Provides a standard way to execute multiple
+  byte writes to an I2C device (e.g. when accessing sub-addresses or writing
+  block of data), as defined in the I2C Specification.
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param Length       No. of bytes to be written.
+
+  @param Buffer       Contains the value of byte to be written to the
+                      I2C slave device.
+
+  @retval EFI_SUCCESS            Transfer success.
+  @retval EFI_INVALID_PARAMETER  This, Length or Buffer pointers are invalid.
+  @retval EFI_UNSUPPORTED        Unsupported input param.
+  @retval EFI_TIMEOUT            Timeout while waiting xfer.
+  @retval EFI_ABORTED            Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR       Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteMultipleByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN UINTN                          *Length,
+  IN OUT    VOID                    *Buffer
+  )
+{
+  EFI_STATUS Status;
+  UINTN      I2CAddress;
+  UINT16     SaveCmd;
+  UINT32     SaveBar0;
+
+    if (Buffer == NULL || Length == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  SaveCmd = 0;
+  SaveBar0 =0;
+
+  I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+  Status = EFI_SUCCESS;
+
+  I2CAddress = SlaveAddress.I2CDeviceAddress;
+
+  Status = InitializeInternal (AddrMode);
+  if (!EFI_ERROR(Status)) {
+    Status = WriteMultipleByte (I2CAddress, Buffer, (*Length));
+  }
+
+  I2cCommonServiceExit (SaveCmd, SaveBar0);
+  return Status;
+}
+
+/**
+
+  The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte() function.
+  Provides a standard way to execute multiple byte writes to an I2C device
+  (e.g. when accessing sub-addresses or when reading block of data), as defined
+  in the I2C Specification (I2C combined write/read protocol).
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param WriteLength  No. of bytes to be written. In this case data
+                      written typically contains sub-address or sub-addresses
+                      in Hi-Lo format, that need to be read (I2C combined
+                      write/read protocol).
+
+  @param ReadLength   No. of bytes to be read from I2C slave device.
+
+  @param Buffer       Contains the value of byte data read from the
+                      I2C slave device.
+
+  @retval EFI_SUCCESS            Transfer success.
+  @retval EFI_INVALID_PARAMETER  This, WriteLength, ReadLength or Buffer
+                                 pointers are invalid.
+  @retval EFI_UNSUPPORTED        Unsupported input param.
+  @retval EFI_TIMEOUT            Timeout while waiting xfer.
+  @retval EFI_ABORTED            Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR       Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadMultipleByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN UINTN                          *WriteLength,
+  IN UINTN                          *ReadLength,
+  IN OUT    VOID                    *Buffer
+  )
+{
+  EFI_STATUS        Status;
+  UINTN             I2CAddress;
+  UINT16            SaveCmd;
+  UINT32            SaveBar0;
+
+  if (Buffer == NULL || WriteLength == NULL || ReadLength == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  SaveCmd = 0;
+  SaveBar0 =0;
+
+  I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+  Status = EFI_SUCCESS;
+
+  I2CAddress = SlaveAddress.I2CDeviceAddress;
+  Status = InitializeInternal (AddrMode);
+  if (!EFI_ERROR(Status)) {
+    Status = ReadMultipleByte (I2CAddress, Buffer, (*WriteLength), (*ReadLength));
+  }
+  I2cCommonServiceExit (SaveCmd, SaveBar0);
+  return Status;
+}
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf
new file mode 100644
index 0000000000..243582fcae
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf
@@ -0,0 +1,62 @@
+## @file
+# Component description file for Quark South Cluster I2C library.
+#
+# I2C library implement QuarkSCSocId related drivers, includes:
+# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver.
+#
+# This driver contains I2C bus access routines:
+# 1. I2C Read (byte, multi-byte)
+# 2. I2C Write (byte, multi-byte)
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = I2cLib
+  FILE_GUID                      = 462d127a-c143-469e-8449-b6e36beb04a8
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = I2cLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  CommonHeader.h
+  I2cLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelFrameworkPkg/IntelFrameworkPkg.dec
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  PcdLib
+  PciLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  DebugLib
+  BaseLib
+  TimerLib
+  IoLib
+  IohLib
+
+[FeaturePcd]
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdI2CFastModeEnabled
+
+[FixedPcd]
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohI2cMmioBase
+
+[Pcd]
+
+[Depex]
+  TRUE
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h
new file mode 100644
index 0000000000..bcb7f593a6
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h
@@ -0,0 +1,29 @@
+/** @file
+Common header file shared by all source files.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __COMMON_HEADER_H_
+#define __COMMON_HEADER_H_
+
+#include <PiPei.h>
+#include <Ioh.h>
+#include <IohCommonDefinitions.h>
+
+#include <Library/IohLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CpuLib.h>
+#include <Library/PciCf8Lib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Pci22.h>
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c
new file mode 100644
index 0000000000..9e7e6b7c35
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c
@@ -0,0 +1,99 @@
+/** @file
+Lib function for Pei Quark South Cluster.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "CommonHeader.h"
+
+/**
+  Program SVID/SID the same as VID/DID*
+**/
+EFI_STATUS
+EFIAPI
+InitializeIohSsvidSsid (
+   IN UINT8   Bus,
+   IN UINT8   Device,
+   IN UINT8   Func
+   )
+{
+  UINTN       Index;
+
+  for (Index = 0; Index <= IOH_PCI_IOSF2AHB_0_MAX_FUNCS; Index++) {
+    if (((Device == IOH_PCI_IOSF2AHB_1_DEV_NUM) && (Index >= IOH_PCI_IOSF2AHB_1_MAX_FUNCS))) {
+      continue;
+    }
+
+    IohMmPci32(0, Bus, Device, Index, PCI_REG_SVID0) = IohMmPci32(0, Bus, Device, Index, PCI_REG_VID);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/* Enable memory, io, and bus master for USB controller */
+VOID
+EFIAPI
+EnableUsbMemIoBusMaster (
+  IN UINT8   UsbBusNumber
+  )
+{
+  UINT16 CmdReg;
+
+  CmdReg = PciRead16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, PCI_REG_PCICMD));
+  CmdReg = (UINT16) (CmdReg | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_BUS_MASTER);
+  PciWrite16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, PCI_REG_PCICMD), CmdReg);
+
+  CmdReg = PciRead16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, PCI_REG_PCICMD));
+  CmdReg = (UINT16) (CmdReg | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_BUS_MASTER);
+  PciWrite16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, PCI_REG_PCICMD), CmdReg);
+}
+
+/**
+  Read south cluster GPIO input from Port A.
+
+**/
+UINT32
+EFIAPI
+ReadIohGpioValues (
+  VOID
+  )
+{
+  UINT32  GipData;
+  UINT32  GipAddr;
+  UINT32  TempBarAddr;
+  UINT16  SaveCmdReg;
+  UINT32  SaveBarReg;
+
+  TempBarAddr = (UINT32) PcdGet64(PcdIohGpioMmioBase);
+
+  GipAddr = PCI_LIB_ADDRESS(
+      PcdGet8 (PcdIohGpioBusNumber),
+      PcdGet8 (PcdIohGpioDevNumber),
+      PcdGet8 (PcdIohGpioFunctionNumber), 0);
+
+  //
+  // Save current settings for PCI CMD/BAR registers.
+  //
+  SaveCmdReg = PciRead16 (GipAddr + PCI_COMMAND_OFFSET);
+  SaveBarReg = PciRead32 (GipAddr + PcdGet8 (PcdIohGpioBarRegister));
+
+  DEBUG ((EFI_D_INFO, "SC GPIO temporary enable  at %08X\n", TempBarAddr));
+
+  // Use predefined temporary memory resource.
+  PciWrite32 ( GipAddr + PcdGet8 (PcdIohGpioBarRegister), TempBarAddr);
+  PciWrite8 ( GipAddr + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+
+  // Read GPIO configuration
+  GipData = MmioRead32(TempBarAddr + GPIO_EXT_PORTA);
+
+  //
+  // Restore settings for PCI CMD/BAR registers.
+  //
+  PciWrite32 ((GipAddr + PcdGet8 (PcdIohGpioBarRegister)), SaveBarReg);
+  PciWrite16 (GipAddr + PCI_COMMAND_OFFSET, SaveCmdReg);
+
+  // Only 8 bits valid.
+  return GipData & 0x000000FF;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf
new file mode 100644
index 0000000000..0fc506ba1e
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf
@@ -0,0 +1,49 @@
+## @file
+# Intel Soc Library Instance
+#
+# Intel Soc Library Instance
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = IohLib
+  FILE_GUID                      = B4C12297-7B19-4523-B165-81374D96716B
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = IohLib
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  IohLib.c
+  CommonHeader.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  PciLib
+  IoLib
+  PciCf8Lib
+  BaseLib
+  CpuLib
+
+[Pcd]
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioDevNumber
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioFunctionNumber
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBarRegister
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioMmioBase
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c
new file mode 100644
index 0000000000..85db4cd104
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c
@@ -0,0 +1,227 @@
+/** @file
+
+UEFI Component Name(2) protocol implementation for SD controller driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SDController.h"
+
+
+//
+// EFI Component Name Protocol
+//
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gSDControllerName = {
+  SDControllerGetDriverName,
+  SDControllerGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSDControllerName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SDControllerGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SDControllerGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSDControllerDriverNameTable[] = {
+  { "eng;en", L"EFI SD Host Controller Driver" },
+  { NULL, NULL }
+};
+
+
+//
+// EFI Component Name Functions
+//
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 3066 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mSDControllerDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gSDControllerName)
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 3066 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS           Status;
+  EFI_SD_HOST_IO_PROTOCOL  *SDHostIo;
+  SDHOST_DATA              *SDHostData;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Make sure this driver is currently managing ControllerHandle
+  //
+  Status = EfiTestManagedDevice (
+             ControllerHandle,
+             gSDControllerDriverBinding.DriverBindingHandle,
+             &gEfiPciIoProtocolGuid
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiSDHostIoProtocolGuid,
+                  (VOID **) &SDHostIo,
+                  gSDControllerDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SDHostData  = SDHOST_DATA_FROM_THIS(SDHostIo);
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           SDHostData->ControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gSDControllerName)
+           );
+
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h
new file mode 100644
index 0000000000..91cc4725ec
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h
@@ -0,0 +1,141 @@
+/** @file
+
+This file contains the delarations for componet name routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 3066 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 3066 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c
new file mode 100644
index 0000000000..7d97b90b92
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c
@@ -0,0 +1,1784 @@
+/** @file
+
+The SD host controller driver model and HC protocol routines.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#include "SDController.h"
+
+
+EFI_DRIVER_BINDING_PROTOCOL gSDControllerDriverBinding = {
+  SDControllerSupported,
+  SDControllerStart,
+  SDControllerStop,
+  0x20,
+  NULL,
+  NULL
+};
+
+
+EFI_SD_HOST_IO_PROTOCOL  mSDHostIo = {
+  EFI_SD_HOST_IO_PROTOCOL_REVISION_01,
+  {
+    0, // HighSpeedSupport
+    0, // V18Support
+    0, // V30Support
+    0, // V33Support
+    0, // Reserved0
+    0, // BusWidth4
+    0, // BusWidth8
+    0, // Reserved1
+    0, // Reserved1
+    (512 * 1024) //BoundarySize
+  },
+  SendCommand,
+  SetClockFrequency,
+  SetBusWidth,
+  SetHostVoltage,
+  ResetSDHost,
+  EnableAutoStopCmd,
+  DetectCardAndInitHost,
+  SetBlockLength,
+  SetHighSpeedMode,
+  SetDDRMode
+};
+
+/**
+  Find sdclk_freq_sel and upr_sdclk_freq_sel bits
+  for Clock Control Register (CLK_CTL)Offset 2Ch when using 8bit or 10bit
+  divided clock mode.
+
+  @param  BaseClockFreg        Base Clock Frequency in Hz For SD Clock in the
+                               Capabilities register.
+  @param  TargetFreq           Target Frequency in Hz to reach.
+  @param  Is8BitMode           True if 8-bit Divided Clock Mode else 10bit mode.
+  @param  Bits                 sdclk_freq_sel and upr_sdclk_freq_sel bits for
+                               TargetFreq.
+
+  @return EFI_SUCCESS          // Bits setup.
+  @return EFI_UNSUPPORTED      // Cannot divide base clock to reach target clock.
+**/
+EFI_STATUS
+DividedClockModeBits (
+  IN CONST UINTN                          BaseClockFreg,
+  IN CONST UINTN                          TargetFreq,
+  IN CONST BOOLEAN                        Is8BitMode,
+  OUT UINT16                              *Bits
+  )
+{
+  UINTN                             N;
+  UINTN                             CurrFreq;
+
+ *Bits = 0;
+  CurrFreq = BaseClockFreg;
+  N = 0;
+  //
+  // N == 0 same for 8bit & 10bit mode i.e. BaseClockFreg of controller.
+  //
+  if (TargetFreq < CurrFreq) {
+    if (Is8BitMode) {
+      N = 1;
+      do {
+        //
+        // N values for 8bit mode when N > 0.
+        //  Bit[15:8] SDCLK Frequency Select at offset 2Ch
+        //    80h - base clock divided by 256
+        //    40h - base clock divided by 128
+        //    20h - base clock divided by 64
+        //    10h - base clock divided by 32
+        //    08h - base clock divided by 16
+        //    04h - base clock divided by 8
+        //    02h - base clock divided by 4
+        //    01h - base clock divided by 2
+        //
+        CurrFreq = BaseClockFreg / (2 * N);
+        if (TargetFreq >= CurrFreq) {
+          break;
+        }
+        N *= 2;
+        if (N > V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL) {
+          return EFI_UNSUPPORTED;
+        }
+      } while (TRUE);
+    } else {
+      N = 1;
+      CurrFreq = BaseClockFreg / (2 * N);
+      //
+      // (try N = 0 or 1 first since don't want divide by 0).
+      //
+      if (TargetFreq < CurrFreq) {
+        //
+        // If still no match then calculate it for 10bit.
+        // N values for 10bit mode.
+        // N 1/2N Divided Clock (Duty 50%).
+        // from Spec "The length of divider is extended to 10 bits and all
+        // divider values shall be supported.
+        //
+        N = (BaseClockFreg / TargetFreq) / 2;
+
+        //
+        // Can only be N or N+1;
+        //
+        CurrFreq = BaseClockFreg / (2 * N);
+        if (TargetFreq < CurrFreq) {
+          N++;
+          CurrFreq = BaseClockFreg / (2 * N);
+        }
+
+        if (N > V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL) {
+          return EFI_UNSUPPORTED;
+        }
+
+        //
+        // Set upper bits of SDCLK Frequency Select (bits 7:6 of reg 0x2c).
+        //
+        *Bits |= ((UINT16) ((N >> 2) & B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK));
+      }
+    }
+  }
+
+  //
+  // Set lower bits of SDCLK Frequency Select (bits 15:8 of reg 0x2c).
+  //
+  *Bits |= ((UINT16) ((UINT8) N) << 8);
+  DEBUG (
+    (EFI_D_INFO,
+    "SDIO:DividedClockModeBits: %dbit mode Want %dHz Got %dHz bits = %04x\r\n",
+    (Is8BitMode) ? 8 : 10,
+    TargetFreq,
+    CurrFreq,
+    (UINTN) *Bits
+     ));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Print type of error and command index
+
+  @param  CommandIndex         Command index to set the command index field of command register.
+  @param  ErrorCode            Error interrupt status read from host controller
+
+  @return EFI_DEVICE_ERROR
+  @return EFI_TIMEOUT
+  @return EFI_CRC_ERROR
+
+**/
+EFI_STATUS
+GetErrorReason (
+  IN  UINT16    CommandIndex,
+  IN  UINT16    ErrorCode
+  )
+{
+  EFI_STATUS    Status;
+
+  Status = EFI_DEVICE_ERROR;
+
+  DEBUG((EFI_D_ERROR, "[%2d] -- ", CommandIndex));
+
+  if (ErrorCode & BIT0) {
+    Status = EFI_TIMEOUT;
+    DEBUG((EFI_D_ERROR, "Command Timeout Erro"));
+  }
+
+  if (ErrorCode & BIT1) {
+    Status = EFI_CRC_ERROR;
+    DEBUG((EFI_D_ERROR, "Command CRC Error"));
+  }
+
+  if (ErrorCode & BIT2) {
+    DEBUG((EFI_D_ERROR, "Command End Bit Error"));
+  }
+
+  if (ErrorCode & BIT3) {
+    DEBUG((EFI_D_ERROR, "Command Index Error"));
+  }
+  if (ErrorCode & BIT4) {
+    Status = EFI_TIMEOUT;
+    DEBUG((EFI_D_ERROR, "Data Timeout Error"));
+  }
+
+  if (ErrorCode & BIT5) {
+    Status = EFI_CRC_ERROR;
+    DEBUG((EFI_D_ERROR, "Data CRC Error"));
+  }
+
+  if (ErrorCode & BIT6) {
+    DEBUG((EFI_D_ERROR, "Data End Bit Error"));
+  }
+
+  if (ErrorCode & BIT7) {
+    DEBUG((EFI_D_ERROR, "Current Limit Error"));
+  }
+
+  if (ErrorCode & BIT8) {
+    DEBUG((EFI_D_ERROR, "Auto CMD12 Error"));
+  }
+
+  if (ErrorCode & BIT9) {
+    DEBUG((EFI_D_ERROR, "ADMA Error"));
+  }
+
+  DEBUG((EFI_D_ERROR, "\n"));
+
+  return Status;
+}
+/**
+  Enable/Disable High Speed transfer mode
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Enable                TRUE to Enable, FALSE to Disable
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+SetHighSpeedMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  UINT32                 Data;
+  SDHOST_DATA            *SDHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SDHostData->PciIo;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64)MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  if (Enable) {
+    if (PcdGetBool(PcdSdHciQuirkNoHiSpd)) {
+      DEBUG ((EFI_D_INFO, "SDIO: Quirk never set High Speed Enable bit\r\n"));
+      return EFI_SUCCESS;
+    }
+    DEBUG ((EFI_D_INFO, "Enable High Speed transfer mode ... \r\n"));
+    Data |= BIT2;
+  } else {
+    Data &= ~BIT2;
+  }
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+              (UINT64)MMIO_HOSTCTL,
+               1,
+               &Data
+              );
+  return EFI_SUCCESS;
+}
+EFI_STATUS
+EFIAPI
+SetDDRMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  UINT16                 Data;
+  SDHOST_DATA            *SDHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SDHostData->PciIo;
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_HOSTCTL2,
+               1,
+               &Data
+               );
+  Data &= 0xFFF0;
+  if (Enable) {
+    Data |= 0x0004; // Enable DDR50 by default, later should enable other mode like HS200/400
+    Data |= BIT3;   // Enable 1.8V Signaling
+  }
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+              (UINT64)MMIO_HOSTCTL2,
+               1,
+               &Data
+              );
+  return EFI_SUCCESS;
+}
+/**
+  Power on/off the LED associated with the slot
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Enable                TRUE to set LED on, FALSE to set LED off
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+HostLEDEnable (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  SDHOST_DATA            *SDHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 Data;
+
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SDHostData->PciIo;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64)MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  if (Enable) {
+    //
+    //LED On
+    //
+    Data |= BIT0;
+  } else {
+    //
+    //LED Off
+    //
+    Data &= ~BIT0;
+  }
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64)MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  The main function used to send the command to the card inserted into the SD host slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  CommandIndex          The command index to set the command index field of command register.
+  @param  Argument              Command argument to set the argument field of command register.
+  @param  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param  Buffer                Contains the data read from / write to the device.
+  @param  BufferSize            The size of the buffer.
+  @param  ResponseType          RESPONSE_TYPE.
+  @param  TimeOut               Time out value in 1 ms unit.
+  @param  ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_OUT_OF_RESOURCES
+  @retval EFI_TIMEOUT
+  @retval EFI_DEVICE_ERROR
+
+**/
+
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  )
+/*++
+
+  Routine Description:
+    The main function used to send the command to the card inserted into the SD host
+    slot.
+    It will assemble the arguments to set the command register and wait for the command
+    and transfer completed until timeout. Then it will read the response register to fill
+    the ResponseData
+
+  Arguments:
+    This           - Pointer to EFI_SD_HOST_IO_PROTOCOL
+    CommandIndex   - The command index to set the command index field of command register
+    Argument       - Command argument to set the argument field of command register
+    DataType       - TRANSFER_TYPE, indicates no data, data in or data out
+    Buffer         - Contains the data read from / write to the device
+    BufferSize     - The size of the buffer
+    ResponseType   - RESPONSE_TYPE
+    TimeOut        - Time out value in 1 ms unit
+    ResponseData   - Depending on the ResponseType, such as CSD or card status
+
+  Returns:
+    EFI_SUCCESS
+    EFI_INVALID_PARAMETER
+    EFI_OUT_OF_RESOURCES
+    EFI_TIMEOUT
+    EFI_DEVICE_ERROR
+
+--*/
+{
+  EFI_STATUS            Status;
+  SDHOST_DATA           *SDHostData;
+  EFI_PCI_IO_PROTOCOL   *PciIo;
+  UINT32                ResponseDataCount;
+  UINT32                Data;
+  UINT64                Data64;
+  UINT8                 Index;
+  INTN                  TimeOut2;
+  BOOLEAN               AutoCMD12Enable = FALSE;
+
+
+  Status             = EFI_SUCCESS;
+  ResponseDataCount  = 1;
+  SDHostData         = SDHOST_DATA_FROM_THIS (This);
+  PciIo              = SDHostData->PciIo;
+  AutoCMD12Enable    =  (CommandIndex & AUTO_CMD12_ENABLE) ? TRUE : FALSE;
+  CommandIndex       = CommandIndex & CMD_INDEX_MASK;
+
+  if (Buffer != NULL && DataType == NoData) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+    goto Exit;
+  }
+
+  if (((UINTN)Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN)NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+    goto Exit;
+  }
+
+  DEBUG ((EFI_D_INFO, "SendCommand: Command Index = %d \r\n", CommandIndex));
+  //
+  TimeOut2 = 1000; // 10 ms
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint32,
+                 0,
+                 (UINT64)MMIO_PSTATE,
+                 1,
+                 &Data
+                 );
+     gBS->Stall (10);
+  }while ((TimeOut2-- > 0) && (Data & BIT0));
+  TimeOut2 = 1000; // 10 ms
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint32,
+                 0,
+                 (UINT64)MMIO_PSTATE,
+                 1,
+                 &Data
+                 );
+    gBS->Stall (10);
+  }while ((TimeOut2-- > 0) && (Data & BIT1));
+  //Clear status bits
+  //
+  Data = 0xFFFF;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_NINTSTS,
+               1,
+               &Data
+               );
+
+  Data = 0xFFFF;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_ERINTSTS,
+               1,
+               &Data
+               );
+
+
+  if (Buffer != NULL) {
+     PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint32,
+                  0,
+                  (UINT64)MMIO_DMAADR,
+                  1,
+                  &Buffer
+                  );
+
+     PciIo->Mem.Read (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64)MMIO_BLKSZ,
+                  1,
+                  &Data
+                  );
+     Data &= ~(0xFFF);
+     if (BufferSize <= SDHostData->BlockLength) {
+       Data |= (BufferSize | 0x7000);
+     } else {
+       Data |= (SDHostData->BlockLength | 0x7000);
+     }
+
+
+     PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64)MMIO_BLKSZ,
+                  1,
+                  &Data
+                  );
+     if (BufferSize <= SDHostData->BlockLength) {
+       Data = 1;
+     } else {
+       Data = BufferSize / SDHostData->BlockLength;
+     }
+     PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64)MMIO_BLKCNT,
+                  1,
+                  &Data
+                  );
+
+  } else {
+    Data = 0;
+    PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64)MMIO_BLKSZ,
+                  1,
+                  &Data
+                  );
+    PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64)MMIO_BLKCNT,
+                  1,
+                  &Data
+                  );
+  }
+
+  //
+  //Argument
+  //
+  Data = Argument;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT64)MMIO_CMDARG,
+               1,
+               &Data
+               );
+
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_XFRMODE,
+               1,
+               &Data
+               );
+
+
+  DEBUG ((EFI_D_INFO, "Transfer mode read  = 0x%x \r\n", (Data & 0xFFFF)));
+  //
+  //BIT0 - DMA Enable
+  //BIT2 - Auto Cmd12
+  //
+  if (DataType == InData) {
+    Data |= BIT4 | BIT0;
+  } else if (DataType == OutData){
+    Data &= ~BIT4;
+    Data |= BIT0;
+  } else {
+    Data &= ~(BIT4 | BIT0);
+  }
+
+  if (BufferSize <= SDHostData->BlockLength) {
+    Data &= ~ (BIT5 | BIT1 | BIT2);
+    Data |= BIT1; // Enable block count always
+  } else {
+     if (SDHostData->IsAutoStopCmd && AutoCMD12Enable) {
+      Data |= (BIT5 | BIT1 | BIT2);
+     } else {
+      Data |= (BIT5 | BIT1);
+     }
+  }
+
+  DEBUG ((EFI_D_INFO, "Transfer mode write = 0x%x \r\n", (Data & 0xffff)));
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_XFRMODE,
+               1,
+               &Data
+               );
+  //
+  //Command
+  //
+  //ResponseTypeSelect    IndexCheck    CRCCheck    ResponseType
+  //  00                     0            0           NoResponse
+  //  01                     0            1           R2
+  //  10                     0            0           R3, R4
+  //  10                     1            1           R1, R5, R6, R7
+  //  11                     1            1           R1b, R5b
+  //
+  switch (ResponseType) {
+    case ResponseNo:
+      Data = (CommandIndex << 8);
+      ResponseDataCount = 0;
+      break;
+
+    case ResponseR1:
+    case ResponseR5:
+    case ResponseR6:
+    case ResponseR7:
+      Data = (CommandIndex << 8) | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR1b:
+    case ResponseR5b:
+      Data = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR2:
+      Data = (CommandIndex << 8) | BIT0 | BIT3;
+      ResponseDataCount = 4;
+      break;
+
+    case ResponseR3:
+    case ResponseR4:
+      Data = (CommandIndex << 8) | BIT1;
+      ResponseDataCount = 1;
+      break;
+
+    default:
+      ASSERT (0);
+      Status = EFI_INVALID_PARAMETER;
+      DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+      goto Exit;
+  }
+
+  if (DataType != NoData) {
+    Data |= BIT5;
+  }
+
+  HostLEDEnable (This, TRUE);
+
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_SDCMD,
+               1,
+               &Data
+               );
+
+
+  Data = 0;
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64)MMIO_ERINTSTS,
+                 1,
+                 &Data
+                 );
+
+    if ((Data & 0x07FF) != 0) {
+      Status = GetErrorReason (CommandIndex, (UINT16)Data);
+      DEBUG ((EFI_D_ERROR, "SendCommand: Error happens \r\n"));
+      goto Exit;
+    }
+
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64)MMIO_NINTSTS,
+                 1,
+                 &Data
+                 );
+
+    if ((Data & BIT0) == BIT0) {
+       //
+       //Command completed, can read response
+       //
+       if (DataType == NoData) {
+         break;
+       } else {
+         //
+         //Transfer completed
+         //
+         if ((Data & BIT1) == BIT1) {
+           break;
+         }
+       }
+    }
+
+    gBS->Stall (1 * 1000);
+
+    TimeOut --;
+
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((EFI_D_ERROR, "SendCommand: Time out \r\n"));
+    goto Exit;
+  }
+
+  if (ResponseData != NULL) {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint32,
+                 0,
+                 (UINT64)MMIO_RESP,
+                 ResponseDataCount,
+                 ResponseData
+                 );
+    if (ResponseType == ResponseR2) {
+      //
+      // Adjustment for R2 response
+      //
+      Data = 1;
+      for (Index = 0; Index < ResponseDataCount; Index++) {
+        Data64 = LShiftU64(*ResponseData, 8);
+        *ResponseData = (UINT32)((Data64 & 0xFFFFFFFF) | Data);
+        Data =  (UINT32)RShiftU64 (Data64, 32);
+        ResponseData++;
+      }
+    }
+  }
+
+Exit:
+  HostLEDEnable (This, FALSE);
+  return Status;
+}
+
+/**
+  Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+  It depends on the max frequency the host can support, divider, and host speed mode.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  MaxFrequency          Max frequency in HZ.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     MaxFrequency
+  )
+{
+  UINT32                 Data;
+  UINT16                 FreqSelBits;
+  EFI_STATUS             Status;
+  SDHOST_DATA            *SDHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 TimeOutCount;
+  UINT32                 Revision;
+
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SDHostData->PciIo;
+  Data = 0;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  PciIo->Mem.Read (
+                PciIo,
+                EfiPciIoWidthUint8,
+                0,
+                (UINT64)MMIO_CTRLRVER,
+                1,
+                &Revision
+                );
+  Revision &= 0x000000FF;
+
+  Status = DividedClockModeBits (
+             SDHostData->BaseClockInMHz * 1000 * 1000,
+             MaxFrequency,
+             (Revision < SDHCI_SPEC_300),
+             &FreqSelBits
+             );
+
+  if (EFI_ERROR (Status)) {
+    //
+    // Cannot reach MaxFrequency with SDHostData->BaseClockInMHz.
+    //
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Data = 0;
+
+  //
+  //Enable internal clock and Stop Clock Enable
+  //
+  Data = BIT0;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  TimeOutCount = TIME_OUT_1S;
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64)MMIO_CLKCTL,
+                 1,
+                 &Data
+                 );
+    gBS->Stall (1 * 1000);
+    TimeOutCount --;
+    if (TimeOutCount == 0) {
+      DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));
+      return EFI_TIMEOUT;
+    }
+  } while ((Data & BIT1) != BIT1);
+
+  DEBUG ((EFI_D_INFO, "Base Clock In MHz: %d\r\n", SDHostData->BaseClockInMHz));
+
+  Data = (BIT0 | ((UINT32) FreqSelBits));
+  DEBUG ((EFI_D_INFO, "Data write to MMIO_CLKCTL: 0x%04x \r\n", Data));
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  TimeOutCount = TIME_OUT_1S;
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64)MMIO_CLKCTL,
+                 1,
+                 &Data
+                 );
+    gBS->Stall (1 * 1000);
+    TimeOutCount --;
+    if (TimeOutCount == 0) {
+      DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));
+      return EFI_TIMEOUT;
+    }
+  } while ((Data & BIT1) != BIT1);
+  gBS->Stall (20 * 1000);
+  Data |= BIT2;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set bus width of the host controller
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  BusWidth              Bus width in 1, 4, 8 bits.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BusWidth
+  )
+{
+  SDHOST_DATA            *SDHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT8                  Data;
+
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+
+
+  if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {
+    DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((SDHostData->SDHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {
+     DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));
+     return EFI_INVALID_PARAMETER;
+  }
+
+  PciIo      = SDHostData->PciIo;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64)MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+  //
+  // BIT5 8-bit MMC Support (MMC8):
+  // If set, IOH supports 8-bit MMC. When cleared, IOH does not support this feature
+  //
+  if (BusWidth == 8) {
+    DEBUG ((EFI_D_INFO, "Bus Width is 8-bit ... \r\n"));
+    Data |= BIT5;
+  } else if (BusWidth == 4) {
+    DEBUG ((EFI_D_INFO, "Bus Width is 4-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data |= BIT1;
+  } else {
+    DEBUG ((EFI_D_INFO, "Bus Width is 1-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data &= ~BIT1;
+  }
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64)MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set voltage which could supported by the host controller.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Voltage               Units in 0.1 V.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     Voltage
+  )
+{
+  SDHOST_DATA            *SDHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT8                  Data;
+  EFI_STATUS             Status;
+
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SDHostData->PciIo;
+  Status     = EFI_SUCCESS;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64)MMIO_PWRCTL,
+               1,
+               &Data
+               );
+
+  if (Voltage == 0) {
+    //
+    //Power Off the host
+    //
+    Data &= ~BIT0;
+  } else if (Voltage <= 18 && This->HostCapability.V18Support) {
+     //
+     //1.8V
+     //
+     Data |= (BIT1 | BIT3 | BIT0);
+  } else if (Voltage > 18 &&  Voltage <= 30 && This->HostCapability.V30Support) {
+     //
+     //3.0V
+     //
+     Data |= (BIT2 | BIT3 | BIT0);
+  } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {
+     //
+     //3.3V
+     //
+     Data |= (BIT1 | BIT2 | BIT3 | BIT0);
+  } else {
+     Status = EFI_UNSUPPORTED;
+     goto Exit;
+  }
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64)MMIO_PWRCTL,
+               1,
+               &Data
+               );
+  gBS->Stall (10 * 1000);
+
+Exit:
+  return Status;
+}
+
+
+
+/**
+  Reset the host controller.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  ResetAll              TRUE to reset all.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+ResetSDHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  RESET_TYPE                 ResetType
+  )
+{
+  SDHOST_DATA            *SDHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 Data;
+  UINT16                 ErrStatus;
+  UINT32                 Mask;
+  UINT32                 TimeOutCount;
+  UINT16                 SaveClkCtl;
+  UINT16                 ZeroClkCtl;
+
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SDHostData->PciIo;
+  Mask       = 0;
+  ErrStatus  = 0;
+
+  if (ResetType == Reset_Auto) {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64)MMIO_ERINTSTS,
+                 1,
+                 &ErrStatus
+                 );
+    if ((ErrStatus & 0xF) != 0) {
+      //
+      //Command Line
+      //
+      Mask |= BIT1;
+    }
+    if ((ErrStatus & 0x70) != 0) {
+      //
+      //Data Line
+      //
+      Mask |= BIT2;
+    }
+  }
+
+
+  if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT2;
+  }
+  if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT1;
+  }
+  if (ResetType == Reset_All) {
+    Mask = BIT0;
+  }
+
+  if (Mask == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // To improve SD stability, we zero the MMIO_CLKCTL register and
+  // stall for 50 microseconds before resetting the controller.  We
+  // restore the register setting following the reset operation.
+  //
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_CLKCTL,
+               1,
+               &SaveClkCtl
+               );
+
+  ZeroClkCtl = (UINT16) 0;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_CLKCTL,
+               1,
+               &ZeroClkCtl
+               );
+
+  gBS->Stall (50);
+
+  //
+  // Reset the SD host controller
+  //
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64)MMIO_SWRST,
+               1,
+               &Mask
+               );
+
+  Data          = 0;
+  TimeOutCount  = TIME_OUT_1S;
+  do {
+
+    gBS->Stall (1 * 1000);
+
+    TimeOutCount --;
+
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint8,
+                 0,
+                 (UINT64)MMIO_SWRST,
+                 1,
+                 &Data
+                 );
+    if ((Data & Mask) == 0) {
+      break;
+    }
+  } while (TimeOutCount > 0);
+
+  //
+  // We now restore the MMIO_CLKCTL register which we set to 0 above.
+  //
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_CLKCTL,
+               1,
+               &SaveClkCtl
+               );
+
+  if (TimeOutCount == 0) {
+    DEBUG ((EFI_D_ERROR, "ResetSDHost: Time out \r\n"));
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Enable auto stop on the host controller.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Enable                TRUE to enable, FALSE to disable.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  SDHOST_DATA            *SDHostData;
+
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+
+  SDHostData->IsAutoStopCmd = Enable;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set the Block length on the host controller.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  BlockLength           card supportes block length.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BlockLength
+  )
+{
+  SDHOST_DATA            *SDHostData;
+
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+
+  DEBUG ((EFI_D_INFO, "Block length on the host controller: %d \r\n", BlockLength));
+  SDHostData->BlockLength = BlockLength;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Find whether these is a card inserted into the slot. If so init the host.
+  If not, return EFI_NOT_FOUND.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+  @retval EFI_SUCCESS
+  @retval EFI_NOT_FOUND
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This
+  )
+{
+  SDHOST_DATA            *SDHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 Data;
+  EFI_STATUS             Status;
+  UINT8                  Voltages[] = { 33, 30, 18 };
+  UINTN                  Loop;
+
+  SDHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SDHostData->PciIo;
+  Status     = EFI_NOT_FOUND;
+
+  Data = 0;
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT64)MMIO_PSTATE,
+               1,
+               &Data
+               );
+
+  if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {
+    //
+    // Has no card inserted
+    //
+    DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: No Cards \r\n"));
+    Status =  EFI_NOT_FOUND;
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: Find Cards \r\n"));
+
+  Status =  EFI_NOT_FOUND;
+  for (Loop = 0; Loop < sizeof (Voltages); Loop++) {
+    DEBUG ((
+      EFI_D_INFO,
+      "DetectCardAndInitHost: SetHostVoltage %d.%dV \r\n",
+      Voltages[Loop] / 10,
+      Voltages[Loop] % 10
+      ));
+    Status = SetHostVoltage (This, Voltages[Loop]);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [failed]\n"));
+    } else {
+      DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [success]\n"));
+      break;
+    }
+  }
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set voltage \r\n"));
+    goto Exit;
+  }
+
+  Status = SetClockFrequency (This, FREQUENCY_OD);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set frequency \r\n"));
+    goto Exit;
+  }
+  SetBusWidth (This, 1);
+
+  //
+  //Enable normal status change
+  //
+
+  Data = (BIT0 | BIT1);
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_NINTEN,
+               1,
+               &Data
+               );
+
+  //
+  //Enable error status change
+  //
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_ERINTEN,
+               1,
+               &Data
+               );
+
+  Data |= (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64)MMIO_ERINTEN,
+               1,
+               &Data
+               );
+
+  //
+  //Data transfer Timeout control
+  //
+  Data = 0x0E;
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64)MMIO_TOCTL,
+               1,
+               &Data
+               );
+  //
+  //Set Default Bus width as 1 bit
+  //
+
+Exit:
+  return Status;
+
+}
+
+/**
+  Entry point for EFI drivers.
+
+  @param  ImageHandle      EFI_HANDLE.
+  @param  SystemTable      EFI_SYSTEM_TABLE.
+
+  @retval EFI_SUCCESS      Driver is successfully loaded.
+  @return Others           Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSDController (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &gSDControllerDriverBinding,
+           ImageHandle,
+           &gSDControllerName,
+           &gSDControllerName2
+           );
+}
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has SDHostIoProtocol installed will be supported.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @return EFI_SUCCESS          This driver supports this device.
+  @return EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS            OpenStatus;
+  EFI_STATUS            Status;
+  EFI_PCI_IO_PROTOCOL   *PciIo;
+  PCI_CLASSC            PciClass;
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSDHostIoProtocolGuid,
+                  (VOID **)&SdHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (!EFI_ERROR (Status)) {
+    DEBUG (( DEBUG_INFO, "SdHost controller is already started\n"));
+    return EFI_ALREADY_STARTED;
+  }
+
+  //
+  // Test whether there is PCI IO Protocol attached on the controller handle.
+  //
+  OpenStatus = gBS->OpenProtocol (
+                      Controller,
+                      &gEfiPciIoProtocolGuid,
+                      (VOID **) &PciIo,
+                      This->DriverBindingHandle,
+                      Controller,
+                      EFI_OPEN_PROTOCOL_BY_DRIVER
+                      );
+
+  if (EFI_ERROR (OpenStatus)) {
+    return OpenStatus;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint8,
+                        PCI_CLASSCODE_OFFSET,
+                        sizeof (PCI_CLASSC) / sizeof (UINT8),
+                        &PciClass
+                        );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+
+  //
+  // Test whether the controller belongs to SD type
+  //
+  if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||
+      (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||
+      ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))
+      ) {
+
+    Status = EFI_UNSUPPORTED;
+  }
+
+ON_EXIT:
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return Status;
+}
+/**
+  Starting the SD Host Controller Driver.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @retval EFI_SUCCESS          This driver supports this device.
+  @retval EFI_UNSUPPORTED      This driver does not support this device.
+  @retval EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                               EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PCI_IO_PROTOCOL   *PciIo;
+  SDHOST_DATA           *SDHostData;
+  UINT32                Data;
+
+
+  SDHostData = NULL;
+  Data       = 0;
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Enable the SD Host Controller MMIO space
+  //
+  Status = PciIo->Attributes (
+                    PciIo,
+                    EfiPciIoAttributeOperationEnable,
+                    EFI_PCI_DEVICE_ENABLE,
+                    NULL
+                    );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+
+  SDHostData = (SDHOST_DATA*)AllocateZeroPool(sizeof (SDHOST_DATA));
+  if (SDHostData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  SDHostData->Signature   = SDHOST_DATA_SIGNATURE;
+  SDHostData->PciIo       = PciIo;
+
+  CopyMem (&SDHostData->SDHostIo, &mSDHostIo, sizeof (EFI_SD_HOST_IO_PROTOCOL));
+
+  ResetSDHost (&SDHostData->SDHostIo, Reset_All);
+
+  PciIo->Mem.Read (
+              PciIo,
+              EfiPciIoWidthUint16,
+              0,
+              (UINT64)MMIO_CTRLRVER,
+              1,
+              &Data
+              );
+  SDHostData->SDHostIo.HostCapability.HostVersion = Data & 0xFF;
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: HostVersion 0x%x \r\n", SDHostData->SDHostIo.HostCapability.HostVersion));
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT64)MMIO_CAP,
+               1,
+               &Data
+               );
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: MMIO_CAP 0x%x \r\n", Data));
+  if ((Data & BIT18) != 0) {
+    SDHostData->SDHostIo.HostCapability.BusWidth8 = TRUE;
+  }
+
+  if ((Data & BIT21) != 0) {
+    SDHostData->SDHostIo.HostCapability.HighSpeedSupport = TRUE;
+  }
+
+  if ((Data & BIT24) != 0) {
+    SDHostData->SDHostIo.HostCapability.V33Support = TRUE;
+  }
+
+  if ((Data & BIT25) != 0) {
+    SDHostData->SDHostIo.HostCapability.V30Support = TRUE;
+  }
+
+  if ((Data & BIT26) != 0) {
+    SDHostData->SDHostIo.HostCapability.V18Support = TRUE;
+  }
+
+  SDHostData->SDHostIo.HostCapability.BusWidth4 = TRUE;
+
+  if(SDHostData->SDHostIo.HostCapability.HostVersion < SDHCI_SPEC_300) {
+
+
+
+      SDHostData->BaseClockInMHz = (Data >> 8) & 0x3F;
+   }
+   else {
+      SDHostData->BaseClockInMHz = (Data >> 8) & 0xFF;
+
+   }
+
+  SDHostData->BlockLength = 512 << ((Data >> 16) & 0x03);
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: BlockLength 0x%x \r\n", SDHostData->BlockLength));
+  SDHostData->IsAutoStopCmd  = TRUE;
+
+  Status = gBS->InstallProtocolInterface (
+                  &Controller,
+                  &gEfiSDHostIoProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &SDHostData->SDHostIo
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Install the component name protocol
+  //
+  SDHostData->ControllerNameTable = NULL;
+
+  AddUnicodeString2 (
+    "eng",
+    gSDControllerName.SupportedLanguages,
+    &SDHostData->ControllerNameTable,
+    L"SD Host Controller",
+    TRUE
+    );
+  AddUnicodeString2 (
+    "en",
+    gSDControllerName2.SupportedLanguages,
+    &SDHostData->ControllerNameTable,
+    L"SD Host Controller",
+    FALSE
+    );
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    if (SDHostData != NULL) {
+      FreePool (SDHostData);
+    }
+  }
+
+  return Status;
+}
+
+
+/**
+  Stop this driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to stop driver on.
+  @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS               Status;
+  EFI_SD_HOST_IO_PROTOCOL  *SDHostIo;
+  SDHOST_DATA              *SDHostData;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSDHostIoProtocolGuid,
+                  (VOID **) &SDHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  //
+  // Test whether the Controller handler passed in is a valid
+  // Usb controller handle that should be supported, if not,
+  // return the error status directly
+  //
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SetHostVoltage (SDHostIo, 0);
+
+  SDHostData  = SDHOST_DATA_FROM_THIS(SDHostIo);
+
+  //
+  // Uninstall Block I/O protocol from the device handle
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  Controller,
+                  &gEfiSDHostIoProtocolGuid,
+                  SDHostIo
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  FreeUnicodeStringTable (SDHostData->ControllerNameTable);
+
+  FreePool (SDHostData);
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return EFI_SUCCESS;
+}
+
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h
new file mode 100644
index 0000000000..025c80c263
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h
@@ -0,0 +1,316 @@
+/** @file
+
+The definition for SD host controller driver model and HC protocol routines.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_CONTROLLER_H_
+#define _SD_CONTROLLER_H_
+
+
+#include <Uefi.h>
+
+
+#include <Protocol/PciIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Pci22.h>
+
+
+#include "ComponentName.h"
+#include "SDHostIo.h"
+
+
+extern EFI_DRIVER_BINDING_PROTOCOL   gSDControllerDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gSDControllerName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gSDControllerName2;
+
+
+#define SDHOST_DATA_SIGNATURE  SIGNATURE_32 ('s', 'd', 'h', 's')
+
+#define BLOCK_SIZE   0x200
+#define TIME_OUT_1S  1000
+
+#pragma pack(1)
+//
+// PCI Class Code structure
+//
+typedef struct {
+  UINT8 PI;
+  UINT8 SubClassCode;
+  UINT8 BaseCode;
+} PCI_CLASSC;
+
+#pragma pack()
+
+
+typedef struct {
+  UINTN                      Signature;
+  EFI_SD_HOST_IO_PROTOCOL    SDHostIo;
+  EFI_PCI_IO_PROTOCOL        *PciIo;
+  BOOLEAN                    IsAutoStopCmd;
+  UINT32                     BaseClockInMHz;
+  UINT32                     CurrentClockInKHz;
+  UINT32                     BlockLength;
+  EFI_UNICODE_STRING_TABLE   *ControllerNameTable;
+}SDHOST_DATA;
+
+#define SDHOST_DATA_FROM_THIS(a) \
+    CR(a, SDHOST_DATA, SDHostIo, SDHOST_DATA_SIGNATURE)
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has SDHostIoProtocol installed will be supported.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @return EFI_SUCCESS          This driver supports this device.
+  @return EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Starting the SD Host Controller Driver.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @retval EFI_SUCCESS          This driver supports this device.
+  @retval EFI_UNSUPPORTED      This driver does not support this device.
+  @retval EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                               EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Stop this driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to stop driver on.
+  @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  );
+
+/**
+  The main function used to send the command to the card inserted into the SD host slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  CommandIndex          The command index to set the command index field of command register.
+  @param  Argument              Command argument to set the argument field of command register.
+  @param  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param  Buffer                Contains the data read from / write to the device.
+  @param  BufferSize            The size of the buffer.
+  @param  ResponseType          RESPONSE_TYPE.
+  @param  TimeOut               Time out value in 1 ms unit.
+  @param  ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_OUT_OF_RESOURCES
+  @retval EFI_TIMEOUT
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  );
+
+/**
+  Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+  It depends on the max frequency the host can support, divider, and host speed mode.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  MaxFrequency          Max frequency in HZ.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     MaxFrequencyInKHz
+  );
+
+/**
+  Set bus width of the host controller
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  BusWidth              Bus width in 1, 4, 8 bits.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BusWidth
+  );
+
+
+/**
+  Set voltage which could supported by the host controller.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Voltage               Units in 0.1 V.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     Voltage
+  );
+
+
+/**
+  Reset the host controller.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  ResetAll              TRUE to reset all.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+ResetSDHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  RESET_TYPE                 ResetType
+  );
+
+
+/**
+  Enable auto stop on the host controller.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Enable                TRUE to enable, FALSE to disable.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+/**
+  Find whether these is a card inserted into the slot. If so init the host.
+  If not, return EFI_NOT_FOUND.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+  @retval EFI_SUCCESS
+  @retval EFI_NOT_FOUND
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This
+  );
+
+/**
+  Set the Block length on the host controller.
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  BlockLength           card supportes block length.
+
+  @retval EFI_SUCCESS
+  @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BlockLength
+  );
+
+/**
+  Enable/Disable High Speed transfer mode
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  Enable                TRUE to Enable, FALSE to Disable
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+SetHighSpeedMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+EFI_STATUS
+EFIAPI
+SetDDRMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf
new file mode 100644
index 0000000000..c5fb51d006
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf
@@ -0,0 +1,56 @@
+## @file
+#
+#  Component Description File For SDControllerDxe Module.
+#
+#  Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SDController
+  FILE_GUID                      = 90A330BD-6F89-4900-933A-C25EB4356348
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeSDController
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+#  DRIVER_BINDING                =  gSDControllerDriverBinding
+#  COMPONENT_NAME                =  gSDControllerName
+#  COMPONENT_NAME2               =  gSDControllerName2
+#
+
+[Sources]
+  SDController.c
+  SDController.h
+  ComponentName.c
+  ComponentName.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gEfiSDHostIoProtocolGuid                      ## BY_START
+
+[FeaturePcd]
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdSdHciQuirkNoHiSpd
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c
new file mode 100644
index 0000000000..41a3065b5c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c
@@ -0,0 +1,647 @@
+/** @file
+
+CEATA specific functions implementation
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SDMediaDevice.h"
+
+/**
+  Send RW_MULTIPLE_REGISTER command
+
+  @param  CardData             Pointer to CARD_DATA.
+  @param  Address              Register address.
+  @param  ByteCount            Buffer size.
+  @param  Write                TRUE means write, FALSE means read.
+  @param  Buffer               Buffer pointer.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadWriteMultipleRegister (
+  IN  CARD_DATA   *CardData,
+  IN  UINT16      Address,
+  IN  UINT8       ByteCount,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT32                     Argument;
+
+  Status   = EFI_SUCCESS;
+
+  if ((Address % 4 != 0) || (ByteCount % 4 != 0)) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  Argument = (Address << 16) | ByteCount;
+  if (Write) {
+    Argument |= BIT31;
+  }
+
+
+  if (Write) {
+    CopyMem (CardData->AlignedBuffer, Buffer, ByteCount);
+
+    Status = SendCommand (
+               CardData,
+               RW_MULTIPLE_REGISTER,
+               Argument,
+               OutData,
+               CardData->AlignedBuffer,
+               ByteCount,
+               ResponseR1b,
+               TIMEOUT_DATA,
+               (UINT32*)&(CardData->CardStatus)
+               );
+  } else {
+    Status = SendCommand (
+               CardData,
+               RW_MULTIPLE_REGISTER,
+               Argument,
+               InData,
+               CardData->AlignedBuffer,
+               ByteCount,
+               ResponseR1,
+               TIMEOUT_DATA,
+               (UINT32*)&(CardData->CardStatus)
+               );
+    if (!EFI_ERROR (Status)) {
+      CopyMem (Buffer, CardData->AlignedBuffer, ByteCount);
+    }
+
+  }
+Exit:
+  return Status;
+}
+
+/**
+  Send ReadWriteMultipleBlock command with RW_MULTIPLE_REGISTER command
+
+  @param  CardData             Pointer to CARD_DATA.
+  @param  DataUnitCount        Buffer size in 512 bytes unit.
+  @param  Write                TRUE means write, FALSE means read.
+  @param  Buffer               Buffer pointer.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadWriteMultipleBlock (
+  IN  CARD_DATA   *CardData,
+  IN  UINT16      DataUnitCount,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
+  UINT32                     TransferLength;
+
+  Status   = EFI_SUCCESS;
+  SDHostIo = CardData->SDHostIo;
+
+  TransferLength = DataUnitCount * DATA_UNIT_SIZE;
+  if (TransferLength > SDHostIo->HostCapability.BoundarySize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Write) {
+    CopyMem (CardData->AlignedBuffer, Buffer, TransferLength);
+
+    Status = SendCommand (
+               CardData,
+               RW_MULTIPLE_BLOCK,
+               (DataUnitCount | BIT31),
+               OutData,
+               CardData->AlignedBuffer,
+               TransferLength,
+               ResponseR1b,
+               TIMEOUT_DATA,
+               (UINT32*)&(CardData->CardStatus)
+               );
+   } else {
+      Status = SendCommand (
+                 CardData,
+                 RW_MULTIPLE_BLOCK,
+                 DataUnitCount,
+                 InData,
+                 CardData->AlignedBuffer,
+                 TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32*)&(CardData->CardStatus)
+                 );
+      if (!EFI_ERROR (Status)) {
+        CopyMem (Buffer, CardData->AlignedBuffer, TransferLength);
+      }
+  }
+
+  return Status;
+}
+
+/**
+  Send software reset
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SoftwareReset (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS    Status;
+  UINT8         Data;
+  UINT32        TimeOut;
+
+  Data = BIT2;
+
+  Status = FastIO (CardData, Reg_Control, &Data, TRUE);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  TimeOut = 5 * 1000;
+
+  do {
+    gBS->Stall (1 * 1000);
+    Status = FastIO (CardData, Reg_Control, &Data, FALSE);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+    if ((Data & BIT2) == BIT2) {
+      break;
+    }
+
+    TimeOut--;
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+   Status = EFI_TIMEOUT;
+   goto Exit;
+  }
+
+  Data &= ~BIT2;
+  Status = FastIO (CardData, Reg_Control, &Data, TRUE);
+
+  TimeOut = 5 * 1000;
+
+  do {
+    gBS->Stall (1 * 1000);
+    Status = FastIO (CardData, Reg_Control, &Data, FALSE);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+    if ((Data & BIT2) != BIT2) {
+      break;
+    }
+
+    TimeOut--;
+  } while (TimeOut > 0);
+
+
+  if (TimeOut == 0) {
+   Status = EFI_TIMEOUT;
+   goto Exit;
+  }
+
+
+Exit:
+  return Status;
+}
+
+
+/**
+  SendATACommand specificed in Taskfile
+
+  @param  CardData             Pointer to CARD_DATA.
+  @param  TaskFile             Pointer to TASK_FILE.
+  @param  Write                TRUE means write, FALSE means read.
+  @param  Buffer               If NULL, means no data transfer, neither read nor write.
+  @param  SectorCount          Buffer size in 512 bytes unit.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SendATACommand (
+  IN  CARD_DATA   *CardData,
+  IN  TASK_FILE   *TaskFile,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      Data;
+  UINT32                     TimeOut;
+
+  //
+  //Write register
+  //
+  Status = ReadWriteMultipleRegister (
+             CardData,
+             0,
+             sizeof (TASK_FILE),
+             TRUE,
+             (UINT8*)TaskFile
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister 0x%x\n", Status));
+    goto Exit;
+  }
+
+  TimeOut = 5000;
+  do {
+    gBS->Stall (1 * 1000);
+    Data = 0;
+    Status = FastIO (
+               CardData,
+               Reg_Command_Status,
+               &Data,
+               FALSE
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    if (((Data & BIT7) == 0) && ((Data & BIT6) == BIT6)) {
+      break;
+    }
+
+    TimeOut --;
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+    DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister FastIO EFI_TIMEOUT 0x%x\n", Data));
+    Status = EFI_TIMEOUT;
+    goto Exit;
+  }
+
+
+  if (Buffer != NULL) {
+    Status = ReadWriteMultipleBlock (
+               CardData,
+               SectorCount,
+               Write,
+               (UINT8*)Buffer
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock EFI_TIMEOUT 0x%x\n", Status));
+      goto Exit;
+    }
+
+    TimeOut = 5 * 1000;
+    do {
+      gBS->Stall (1 * 1000);
+
+      Data = 0;
+      Status = FastIO (
+                 CardData,
+                 Reg_Command_Status,
+                 &Data,
+                 FALSE
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      if (((Data & BIT7) == 0) && ((Data & BIT3) == 0)) {
+        break;
+      }
+
+      TimeOut --;
+    } while (TimeOut > 0);
+    if (TimeOut == 0) {
+      DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock FastIO EFI_TIMEOUT 0x%x\n", Data));
+      Status = EFI_TIMEOUT;
+      goto Exit;
+    }
+
+
+    if (((Data & BIT6) == BIT6) && (Data & BIT0) == 0) {
+      Status = EFI_SUCCESS;
+    } else {
+      Status = EFI_DEVICE_ERROR;
+    }
+  }
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    SoftwareReset (CardData);
+  }
+
+  return Status;
+}
+
+/**
+  IDENTIFY_DEVICE command
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+IndentifyDevice (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS                 Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+  //
+  //The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = IDENTIFY_DEVICE;
+
+
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             (UINT8*)&(CardData->IndentifyDeviceData),
+             1
+             );
+
+
+  return Status;
+}
+
+/**
+  FLUSH_CACHE_EXT command
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+FlushCache (
+  IN  CARD_DATA    *CardData
+  )
+{
+
+  //
+  //Hitachi CE-ATA will always make the busy high after
+  //receving this command
+  //
+/*
+  EFI_STATUS  Status;
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+  //
+  //The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = FLUSH_CACHE_EXT;
+
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             NULL,
+             0
+             );
+*/
+  return EFI_SUCCESS;
+}
+
+/**
+  STANDBY_IMMEDIATE command
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+StandByImmediate (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS  Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+  //
+  //The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = STANDBY_IMMEDIATE;
+
+
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             NULL,
+             0
+             );
+  return Status;
+}
+
+/**
+  READ_DMA_EXT command
+
+  @param  CardData             Pointer to CARD_DATA.
+  @param  LBA                  The starting logical block address to read from on the device.
+  @param  Buffer               A pointer to the destination buffer for the data. The caller
+                               is responsible for either having implicit or explicit ownership
+                               of the buffer.
+  @param  SectorCount          Size in 512 bytes unit.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  )
+{
+
+  EFI_STATUS  Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+  //
+  //The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = READ_DMA_EXT;
+
+  CardData->TaskFile.SectorCount     = (UINT8)SectorCount;
+  CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);
+
+  CardData->TaskFile.LBALow          = (UINT8)LBA;
+  CardData->TaskFile.LBAMid          = (UINT8)RShiftU64(LBA, 8);
+  CardData->TaskFile.LBAHigh         = (UINT8)RShiftU64(LBA, 16);
+
+  CardData->TaskFile.LBALow_Exp      = (UINT8)RShiftU64(LBA, 24);
+  CardData->TaskFile.LBAMid_Exp      = (UINT8)RShiftU64(LBA, 32);
+  CardData->TaskFile.LBAHigh_Exp     = (UINT8)RShiftU64(LBA, 40);
+
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             Buffer,
+             SectorCount
+             );
+  return Status;
+
+}
+
+/**
+  WRITE_DMA_EXT command
+
+  @param  CardData             Pointer to CARD_DATA.
+  @param  LBA                  The starting logical block address to read from on the device.
+  @param  Buffer               A pointer to the destination buffer for the data. The caller
+                               is responsible for either having implicit or explicit ownership
+                               of the buffer.
+  @param  SectorCount          Size in 512 bytes unit.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+WriteDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  )
+{
+
+  EFI_STATUS  Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+  //
+  //The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = WRITE_DMA_EXT;
+
+  CardData->TaskFile.SectorCount     = (UINT8)SectorCount;
+  CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);
+
+  CardData->TaskFile.LBALow          = (UINT8)LBA;
+  CardData->TaskFile.LBAMid          = (UINT8)RShiftU64(LBA, 8);
+  CardData->TaskFile.LBAHigh         = (UINT8)RShiftU64(LBA, 16);
+
+  CardData->TaskFile.LBALow_Exp      = (UINT8)RShiftU64(LBA, 24);
+  CardData->TaskFile.LBAMid_Exp      = (UINT8)RShiftU64(LBA, 32);
+  CardData->TaskFile.LBAHigh_Exp     = (UINT8)RShiftU64(LBA, 40);
+
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             TRUE,
+             Buffer,
+             SectorCount
+             );
+  return Status;
+
+}
+
+
+/**
+  Judge whether it is CE-ATA device or not.
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval TRUE
+  @retval FALSE
+
+**/
+BOOLEAN
+IsCEATADevice (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS                 Status;
+
+  Status = ReadWriteMultipleRegister (
+             CardData,
+             0,
+             sizeof (TASK_FILE),
+             FALSE,
+             (UINT8*)&CardData->TaskFile
+             );
+  if (EFI_ERROR (Status)) {
+    //
+    //To bring back the normal MMC card to work
+    //
+    CardData->SDHostIo->ResetSDHost (CardData->SDHostIo, Reset_DAT_CMD);
+    return FALSE;
+  }
+
+  if (CardData->TaskFile.LBAMid == CE_ATA_SIG_CE &&
+      CardData->TaskFile.LBAHigh == CE_ATA_SIG_AA
+    ) {
+    //
+    //Disable Auto CMD for CE-ATA
+    //
+    CardData->SDHostIo->EnableAutoStopCmd (CardData->SDHostIo, FALSE);
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c
new file mode 100644
index 0000000000..eb48baa75c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c
@@ -0,0 +1,389 @@
+/** @file
+
+Block I/O protocol for CE-ATA device
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SDMediaDevice.h"
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param  ExtendedVerification   Indicates that the driver may perform a more exhaustive.
+                                 verification operation of the device during reset.
+                                 (This parameter is ingored in this driver.)
+
+  @retval EFI_SUCCESS                Success
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockReset (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  BOOLEAN                 ExtendedVerification
+  )
+{
+  EFI_STATUS                 Status;
+  CARD_DATA                  *CardData;
+  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
+
+  CardData  = CARD_DATA_FROM_THIS(This);
+  SDHostIo = CardData->SDHostIo;
+
+  if (!ExtendedVerification) {
+    Status = SoftwareReset (CardData);
+  } else {
+    Status = SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
+    if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" ));
+      return Status;
+    }
+    Status = MMCSDCardInit (CardData);
+  }
+
+
+  return Status;
+
+ }
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param  MediaId                The media id that the write request is for.
+  @param  LBA                    The starting logical block address to read from on the device.
+                                 The caller is responsible for writing to only legitimate locations.
+  @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
+                                 intrinsic block size of the device.
+  @param  Buffer                 A pointer to the destination buffer for the data. The caller
+                                 is responsible for either having implicit or explicit ownership
+                                 of the buffer.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  OUT VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  CARD_DATA                   *CardData;
+  UINT32                      TransferSize;
+  UINT8                       *pBuf;
+  UINT32                      Index;
+  UINT64                      Address;
+  UINT32                      Remainder;
+  UINT64                      CEATALBA;
+  UINT32                      BoundarySize;
+
+  Status       = EFI_SUCCESS;
+  CardData     = CARD_DATA_FROM_THIS(This);
+  pBuf         = Buffer;
+  Index        = 0;
+  Address      = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
+  BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
+    goto Exit;
+  }
+
+  if (MediaId != CardData->BlockIoMedia.MediaId) {
+    Status = EFI_MEDIA_CHANGED;
+  DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" ));
+    goto Exit;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+  DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" ));
+    goto Exit;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Exit;
+  }
+
+  if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
+    goto Exit;
+  }
+
+
+  do {
+    if (BufferSize < BoundarySize) {
+      TransferSize = (UINT32)BufferSize;
+    } else {
+      TransferSize = BoundarySize;
+    }
+
+    Address += Index * TransferSize;
+    CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
+    ASSERT(Remainder == 0);
+
+    Status = ReadDMAExt (
+               CardData,
+               CEATALBA,
+               pBuf,
+               (UINT16)(TransferSize / DATA_UNIT_SIZE)
+               );
+    if (EFI_ERROR (Status)) {
+     DEBUG((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
+     This->Reset (This, TRUE);
+     goto Exit;
+    }
+    BufferSize -= TransferSize;
+    pBuf       += TransferSize;
+    Index ++;
+  } while (BufferSize != 0);
+
+
+Exit:
+  return Status;
+}
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param  MediaId                The media id that the write request is for.
+  @param  LBA                    The starting logical block address to read from on the device.
+                                 The caller is responsible for writing to only legitimate locations.
+  @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
+                                 intrinsic block size of the device.
+  @param  Buffer                 A pointer to the destination buffer for the data. The caller
+                                 is responsible for either having implicit or explicit ownership
+                                 of the buffer.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  IN  VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  CARD_DATA                   *CardData;
+  UINT32                      TransferSize;
+  UINT8                       *pBuf;
+  UINT32                      Index;
+  UINT64                      Address;
+  UINT32                      Remainder;
+  UINT64                      CEATALBA;
+  UINT32                      BoundarySize;
+
+
+  Status       = EFI_SUCCESS;
+  CardData     = CARD_DATA_FROM_THIS(This);
+  pBuf         = Buffer;
+  Index        = 0;
+  Address      = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
+  BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
+
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  if (MediaId != CardData->BlockIoMedia.MediaId) {
+    Status = EFI_MEDIA_CHANGED;
+    goto Exit;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    goto Exit;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Exit;
+  }
+
+  if (CardData->BlockIoMedia.ReadOnly) {
+    Status = EFI_WRITE_PROTECTED;
+    goto Exit;
+  }
+
+  if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  CardData->NeedFlush = TRUE;
+
+  do {
+    if (BufferSize < BoundarySize) {
+      TransferSize = (UINT32)BufferSize;
+    } else {
+      TransferSize = BoundarySize;
+    }
+
+    Address += Index * TransferSize;
+    CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
+    ASSERT(Remainder == 0);
+
+    Status = WriteDMAExt (
+               CardData,
+               CEATALBA,
+               pBuf,
+               (UINT16)(TransferSize / DATA_UNIT_SIZE)
+               );
+    if (EFI_ERROR (Status)) {
+     DEBUG((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
+     This->Reset (This, TRUE);
+     goto Exit;
+    }
+    BufferSize -= TransferSize;
+    pBuf       += TransferSize;
+    Index ++;
+  } while (BufferSize != 0);
+
+
+Exit:
+  return Status;
+}
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+    (In this driver, this function just returns EFI_SUCCESS.)
+
+  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+
+  @retval EFI_SUCCESS
+  @retval Others
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This
+  )
+{
+
+  CARD_DATA                   *CardData;
+
+  CardData  = CARD_DATA_FROM_THIS(This);
+
+  if (CardData->NeedFlush) {
+    CardData->NeedFlush = FALSE;
+    FlushCache (CardData);
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  CEATA card BlockIo init function.
+
+  @param  CardData               Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS
+  @retval Others
+**/
+EFI_STATUS
+CEATABlockIoInit (
+  IN  CARD_DATA    *CardData
+  )
+/*++
+
+  Routine Description:
+    CEATA card BlockIo init function
+
+  Arguments:
+    CardData  -   Pointer to CARD_DATA
+
+  Returns:
+    EFI_SUCCESS - Success
+--*/
+{
+  EFI_STATUS   Status;
+  UINT64       MaxSize;
+  UINT32       Remainder;
+  //
+  //BlockIO protocol
+  //
+  CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
+  CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
+  CardData->BlockIo.Reset       = CEATABlockReset;
+  CardData->BlockIo.ReadBlocks  = CEATABlockReadBlocks ;
+  CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks;
+  CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks;
+
+  CardData->BlockIoMedia.MediaId          = 0;
+  CardData->BlockIoMedia.RemovableMedia   = FALSE;
+  CardData->BlockIoMedia.MediaPresent     = TRUE;
+  CardData->BlockIoMedia.LogicalPartition = FALSE;
+
+  if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) {
+    CardData->BlockIoMedia.ReadOnly       = TRUE;
+  } else {
+    CardData->BlockIoMedia.ReadOnly       = FALSE;
+  }
+
+
+  CardData->BlockIoMedia.WriteCaching     = FALSE;
+  CardData->BlockIoMedia.IoAlign          = 1;
+
+  Status = IndentifyDevice (CardData);
+  if (EFI_ERROR (Status)) {
+   goto Exit;
+  }
+
+  //
+  //Some device does not support this feature
+  //
+
+  if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) {
+    CardData->BlockIoMedia.ReadOnly       = TRUE;
+  }
+
+  CardData->BlockIoMedia.BlockSize        = (1 << CardData->IndentifyDeviceData.Sectorsize);
+  ASSERT(CardData->BlockIoMedia.BlockSize >= 12);
+
+
+  MaxSize = *(UINT64*)(CardData->IndentifyDeviceData.MaximumLBA);
+  MaxSize = MultU64x32 (MaxSize, 512);
+
+  Remainder = 0;
+  CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder);
+  ASSERT(Remainder == 0);
+
+  CardData->BlockIoMedia.LastBlock        = (EFI_LBA)(CardData->BlockNumber - 1);
+
+
+Exit:
+  return Status;
+
+}
+
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c
new file mode 100644
index 0000000000..0f95968406
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c
@@ -0,0 +1,215 @@
+/** @file
+
+UEFI Component Name(2) protocol implementation for SD media device driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SDMediaDevice.h"
+
+
+//
+// EFI Component Name Protocol
+//
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gSDMediaDeviceName = {
+  SDMediaDeviceGetDriverName,
+  SDMediaDeviceGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSDMediaDeviceName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SDMediaDeviceGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SDMediaDeviceGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSDMediaDeviceDriverNameTable[] = {
+  { "eng;en", L"UEFI MMC/SD Media Device Driver" },
+  { NULL, NULL }
+};
+
+
+//
+// EFI Component Name Functions
+//
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 3066 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mSDMediaDeviceDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gSDMediaDeviceName)
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 3066 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS           Status;
+  EFI_BLOCK_IO_PROTOCOL    *BlockIo;
+  CARD_DATA                *CardData;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  gSDMediaDeviceDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardData  = CARD_DATA_FROM_THIS (BlockIo);
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           CardData->ControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gSDMediaDeviceName)
+           );
+
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h
new file mode 100644
index 0000000000..69eb4d7a73
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h
@@ -0,0 +1,139 @@
+/** @file
+
+This file contains the delarations for componet name routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 3066 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 3066 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  );
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c
new file mode 100644
index 0000000000..da6202983b
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c
@@ -0,0 +1,538 @@
+/** @file
+
+Block I/O protocol for MMC/SD device
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SDMediaDevice.h"
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param  ExtendedVerification   Indicates that the driver may perform a more exhaustive.
+                                 verification operation of the device during reset.
+                                 (This parameter is ingored in this driver.)
+
+  @retval EFI_SUCCESS                Success
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReset (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  BOOLEAN                 ExtendedVerification
+  )
+{
+  CARD_DATA                  *CardData;
+  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
+
+  CardData  = CARD_DATA_FROM_THIS(This);
+  SDHostIo = CardData->SDHostIo;
+
+  return SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
+ }
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param  MediaId                The media id that the write request is for.
+  @param  LBA                    The starting logical block address to read from on the device.
+                                 The caller is responsible for writing to only legitimate locations.
+  @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
+                                 intrinsic block size of the device.
+  @param  Buffer                 A pointer to the destination buffer for the data. The caller
+                                 is responsible for either having implicit or explicit ownership
+                                 of the buffer.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  OUT VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_SD_HOST_IO_PROTOCOL     *SDHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+  UINTN                       TotalBlock;
+
+  DEBUG((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
+  Status   = EFI_SUCCESS;
+  CardData  = CARD_DATA_FROM_THIS(This);
+  SDHostIo = CardData->SDHostIo;
+  if (MediaId != CardData->BlockIoMedia.MediaId) {
+    return EFI_MEDIA_CHANGED;
+  }
+
+  if (ModU64x32 (BufferSize,CardData->BlockIoMedia.BlockSize) != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+  if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+  if (SectorAddressing) {
+    //
+    //Block Address
+    //
+    Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    //Byte Address
+    //
+    Address  = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  }
+  TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);
+  if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));
+    goto Done;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+
+
+
+    BufferPointer   = Buffer;
+    RemainingLength = (UINT32)BufferSize;
+
+    while (RemainingLength > 0) {
+    if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {
+      if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
+        TransferLength = SDHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
+      Status = SendCommand (
+                     CardData,
+                     SET_BLOCKLEN,
+                     CardData->BlockIoMedia.BlockSize,
+                     NoData,
+                     NULL,
+                     0,
+                     ResponseR1,
+                     TIMEOUT_COMMAND,
+                     (UINT32*)&(CardData->CardStatus)
+                     );
+          if (EFI_ERROR (Status)) {
+            break;
+          }
+        }
+        Status = SendCommand (
+                   CardData,
+                   SET_BLOCK_COUNT,
+                   TransferLength / CardData->BlockIoMedia.BlockSize,
+                   NoData,
+                   NULL,
+                   0,
+                   ResponseR1,
+                   TIMEOUT_COMMAND,
+                   (UINT32*)&(CardData->CardStatus)
+                   );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+      Status = SendCommand (
+                 CardData,
+                 READ_MULTIPLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32*)&(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
+        TransferLength = CardData->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      Status = SendCommand (
+                 CardData,
+                 READ_SINGLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 (UINT32)TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32*)&(CardData->CardStatus)
+                 );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
+        break;
+      }
+    }
+      CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
+
+    if (SectorAddressing) {
+        //
+        //Block Address
+        //
+        Address += TransferLength / 512;
+      } else {
+        //
+        //Byte Address
+        //
+        Address += TransferLength;
+      }
+      BufferPointer   += TransferLength;
+      RemainingLength -= TransferLength;
+   }
+
+
+  if (EFI_ERROR (Status)) {
+    if ((CardData->CardType == SDMemoryCard) ||
+        (CardData->CardType == SDMemoryCard2)||
+        (CardData->CardType == SDMemoryCard2High)) {
+         SendCommand (
+           CardData,
+           STOP_TRANSMISSION,
+           0,
+           NoData,
+           NULL,
+           0,
+           ResponseR1b,
+           TIMEOUT_COMMAND,
+           (UINT32*)&(CardData->CardStatus)
+           );
+    } else {
+       SendCommand (
+         CardData,
+         STOP_TRANSMISSION,
+         0,
+         NoData,
+         NULL,
+         0,
+         ResponseR1,
+         TIMEOUT_COMMAND,
+         (UINT32*)&(CardData->CardStatus)
+         );
+    }
+
+  }
+
+
+Done:
+  DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));
+  return Status;
+}
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param  MediaId                The media id that the write request is for.
+  @param  LBA                    The starting logical block address to read from on the device.
+                                 The caller is responsible for writing to only legitimate locations.
+  @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
+                                 intrinsic block size of the device.
+  @param  Buffer                 A pointer to the destination buffer for the data. The caller
+                                 is responsible for either having implicit or explicit ownership
+                                 of the buffer.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  IN  VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_SD_HOST_IO_PROTOCOL     *SDHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+
+  DEBUG((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
+  Status   = EFI_SUCCESS;
+  CardData  = CARD_DATA_FROM_THIS(This);
+  SDHostIo = CardData->SDHostIo;
+  if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+  if (SectorAddressing) {
+    //
+    //Block Address
+    //
+    Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    //Byte Address
+    //
+    Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  }
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n"));
+    goto Done;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+  if (This->Media->ReadOnly == TRUE) {
+    Status = EFI_WRITE_PROTECTED;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n"));
+    goto Done;
+  }
+
+
+
+    BufferPointer   = Buffer;
+    RemainingLength = (UINT32)BufferSize;
+
+    while (RemainingLength > 0) {
+    if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) {
+      if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
+        TransferLength = SDHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3)))  {
+            Status = SendCommand (
+                       CardData,
+                       SET_BLOCKLEN,
+                       CardData->BlockIoMedia.BlockSize,
+                       NoData,
+                       NULL,
+                       0,
+                       ResponseR1,
+                       TIMEOUT_COMMAND,
+                       (UINT32*)&(CardData->CardStatus)
+                       );
+            if (EFI_ERROR (Status)) {
+              break;
+            }
+        }
+        Status = SendCommand (
+                      CardData,
+                   SET_BLOCK_COUNT,
+                   TransferLength / CardData->BlockIoMedia.BlockSize,
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32*)&(CardData->CardStatus)
+                      );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 CardData,
+                 WRITE_MULTIPLE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32)TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32*)&(CardData->CardStatus)
+                 );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
+        TransferLength = CardData->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 CardData,
+                 WRITE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32)TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32*)&(CardData->CardStatus)
+                 );
+    }
+    if (SectorAddressing) {
+        //
+        //Block Address
+        //
+        Address += TransferLength / 512;
+      } else {
+        //
+        //Byte Address
+        //
+        Address += TransferLength;
+      }
+      BufferPointer   += TransferLength;
+      RemainingLength -= TransferLength;
+
+  }
+
+  if (EFI_ERROR (Status)) {
+    SendCommand (
+      CardData,
+      STOP_TRANSMISSION,
+      0,
+      NoData,
+      NULL,
+      0,
+      ResponseR1b,
+      TIMEOUT_COMMAND,
+      (UINT32*)&(CardData->CardStatus)
+      );
+
+  }
+
+
+Done:
+  return EFI_SUCCESS;
+}
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+    (In this driver, this function just returns EFI_SUCCESS.)
+
+  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+
+  @retval EFI_SUCCESS
+  @retval Others
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This
+  )
+{
+  return EFI_SUCCESS;
+}
+
+
+/**
+  MMC/SD card BlockIo init function.
+
+  @param  CardData               Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS
+  @retval Others
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+  IN  CARD_DATA    *CardData
+  )
+{
+  //
+  //BlockIO protocol
+  //
+  CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
+  CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
+  CardData->BlockIo.Reset       = MMCSDBlockReset;
+  CardData->BlockIo.ReadBlocks  = MMCSDBlockReadBlocks ;
+  CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
+  CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
+
+  CardData->BlockIoMedia.MediaId          = 0;
+  CardData->BlockIoMedia.RemovableMedia   = FALSE;
+  CardData->BlockIoMedia.MediaPresent     = TRUE;
+  CardData->BlockIoMedia.LogicalPartition = FALSE;
+
+  if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
+    CardData->BlockIoMedia.ReadOnly         = TRUE;
+  } else {
+    CardData->BlockIoMedia.ReadOnly         = FALSE;
+  }
+
+
+  CardData->BlockIoMedia.WriteCaching     = FALSE;
+  CardData->BlockIoMedia.BlockSize        = CardData->BlockLen;
+  CardData->BlockIoMedia.IoAlign          = 1;
+  CardData->BlockIoMedia.LastBlock        = (EFI_LBA)(CardData->BlockNumber - 1);
+
+
+  return EFI_SUCCESS;
+
+}
+
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c
new file mode 100644
index 0000000000..65b71a008c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c
@@ -0,0 +1,1708 @@
+/** @file
+
+MMC/SD transfer specific functions
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SDMediaDevice.h"
+
+/**
+  Check card status, print the debug info and check the error
+
+  @param  Status                Status got from card status register.
+
+  @retval EFI_SUCCESS
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+CheckCardStatus (
+  IN  UINT32    Status
+  )
+{
+  CARD_STATUS    *CardStatus;
+  CardStatus = (CARD_STATUS*)(&Status);
+
+  if (CardStatus->ADDRESS_OUT_OF_RANGE) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n"));
+  }
+
+  if (CardStatus->ADDRESS_MISALIGN) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n"));
+  }
+
+  if (CardStatus->BLOCK_LEN_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_SEQ_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_PARAM) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n"));
+  }
+
+  if (CardStatus->WP_VIOLATION) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n"));
+  }
+
+  if (CardStatus->CARD_IS_LOCKED) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n"));
+  }
+
+  if (CardStatus->LOCK_UNLOCK_FAILED) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n"));
+  }
+
+  if (CardStatus->COM_CRC_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n"));
+  }
+
+  if (CardStatus->ILLEGAL_COMMAND) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n"));
+  }
+
+  if (CardStatus->CARD_ECC_FAILED) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n"));
+  }
+
+  if (CardStatus->CC_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n"));
+  }
+
+  if (CardStatus->ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n"));
+  }
+
+  if (CardStatus->UNDERRUN) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n"));
+  }
+
+  if (CardStatus->OVERRUN) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n"));
+  }
+
+  if (CardStatus->CID_CSD_OVERWRITE) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n"));
+  }
+
+  if (CardStatus->WP_ERASE_SKIP) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n"));
+  }
+
+  if (CardStatus->ERASE_RESET) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n"));
+  }
+
+  if (CardStatus->SWITCH_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n"));
+  }
+
+  if ((Status & 0xFCFFA080) != 0) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Send command by using Host IO protocol
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  CommandIndex          The command index to set the command index field of command register.
+  @param  Argument              Command argument to set the argument field of command register.
+  @param  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param  Buffer                Contains the data read from / write to the device.
+  @param  BufferSize            The size of the buffer.
+  @param  ResponseType          RESPONSE_TYPE.
+  @param  TimeOut               Time out value in 1 ms unit.
+  @param  ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_UNSUPPORTED
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS    Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
+  SDHostIo = CardData->SDHostIo;
+  if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {
+    CommandIndex |= AUTO_CMD12_ENABLE;
+  }
+
+  Status = SDHostIo->SendCommand (
+                   SDHostIo,
+                   CommandIndex,
+                   Argument,
+                   DataType,
+                   Buffer,
+                   BufferSize,
+                   ResponseType,
+                   TimeOut,
+                   ResponseData
+                   );
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+      ASSERT(ResponseData != NULL);
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
+  }
+
+  return Status;
+}
+
+/**
+  Send the card APP_CMD command with the following command indicated by CommandIndex
+
+  @param  CardData              Pointer to CARD_DATA.
+  @param  CommandIndex          The command index to set the command index field of command register.
+  @param  Argument              Command argument to set the argument field of command register.
+  @param  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param  Buffer                Contains the data read from / write to the device.
+  @param  BufferSize            The size of the buffer.
+  @param  ResponseType          RESPONSE_TYPE.
+  @param  TimeOut               Time out value in 1 ms unit.
+  @param  ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_UNSUPPORTED
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendAppCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
+  UINT8                      Index;
+
+  SDHostIo = CardData->SDHostIo;
+  Status = EFI_SUCCESS;
+
+  for (Index = 0; Index < 2; Index++) {
+    Status = SDHostIo->SendCommand (
+                         SDHostIo,
+                         APP_CMD,
+                         (CardData->Address << 16),
+                         NoData,
+                         NULL,
+                         0,
+                         ResponseR1,
+                         TIMEOUT_COMMAND,
+                         (UINT32*)&(CardData->CardStatus)
+                         );
+    if (!EFI_ERROR (Status)) {
+        Status = CheckCardStatus (*(UINT32*)&(CardData->CardStatus));
+        if (CardData->CardStatus.SAPP_CMD != 1) {
+          Status = EFI_DEVICE_ERROR;
+        }
+        if (!EFI_ERROR (Status)) {
+           break;
+        }
+    } else {
+       SDHostIo->ResetSDHost (SDHostIo, Reset_Auto);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {
+    CommandIndex |= AUTO_CMD12_ENABLE;
+  }
+
+  Status = SDHostIo->SendCommand (
+                       SDHostIo,
+                       CommandIndex,
+                       Argument,
+                       DataType,
+                       Buffer,
+                       BufferSize,
+                       ResponseType,
+                       TimeOut,
+                       ResponseData
+                       );
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+      ASSERT(ResponseData != NULL);
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    SDHostIo->ResetSDHost (SDHostIo, Reset_Auto);
+  }
+
+  return Status;
+}
+
+
+/**
+  Send the card FAST_IO command
+
+  @param  CardData               Pointer to CARD_DATA.
+  @param  RegisterAddress        Register Address.
+  @param  RegisterData           Pointer to register Data.
+  @param  Write                  TRUE for write, FALSE for read.
+
+  @retval EFI_SUCCESS
+  @retval EFI_UNSUPPORTED
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+FastIO (
+  IN      CARD_DATA   *CardData,
+  IN      UINT8       RegisterAddress,
+  IN  OUT UINT8       *RegisterData,
+  IN      BOOLEAN     Write
+  )
+{
+  EFI_STATUS                 Status;
+  UINT32                     Argument;
+  UINT32                     Data;
+
+  Status   = EFI_SUCCESS;
+
+  if (RegisterData == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  Argument = (CardData->Address << 16) | (RegisterAddress << 8);
+  if (Write) {
+    Argument |= BIT15 | (*RegisterData);
+  }
+
+  Status = SendCommand (
+             CardData,
+             FAST_IO,
+             Argument,
+             NoData,
+             NULL,
+             0,
+             ResponseR4,
+             TIMEOUT_COMMAND,
+             &Data
+             );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  if ((Data & BIT15) == 0) {
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  }
+
+  if (!Write) {
+   *RegisterData = (UINT8)Data;
+  }
+
+Exit:
+  return Status;
+}
+
+/**
+  Send the card GO_INACTIVE_STATE command.
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+PutCardInactive (
+  IN  CARD_DATA   *CardData
+  )
+{
+  EFI_STATUS                 Status;
+
+
+  Status = SendCommand (
+             CardData,
+             GO_INACTIVE_STATE,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseNo,
+             TIMEOUT_COMMAND,
+             NULL
+             );
+
+  return Status;
+
+}
+
+/**
+  Get card interested information for CSD rergister
+
+  @param  CardData               Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS
+  @retval EFI_UNSUPPORTED
+  @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+CaculateCardParameter (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Frequency;
+  UINT32         Multiple;
+  UINT32         CSize;
+  CSD_SDV2       *CsdSDV2;
+
+  Status = EFI_SUCCESS;
+
+  switch (CardData->CSDRegister.TRAN_SPEED & 0x7) {
+    case 0:
+      Frequency = 100 * 1000;
+      break;
+
+    case 1:
+      Frequency = 1 * 1000 * 1000;
+      break;
+
+    case 2:
+      Frequency = 10 * 1000 * 1000;
+      break;
+
+    case 3:
+      Frequency = 100 * 1000 * 1000;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) {
+    case 1:
+      Multiple = 10;
+      break;
+
+    case 2:
+      Multiple = 12;
+      break;
+
+    case 3:
+      Multiple = 13;
+      break;
+
+    case 4:
+      Multiple = 15;
+      break;
+
+    case 5:
+      Multiple = 20;
+      break;
+
+    case 6:
+      if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+        Multiple = 26;
+      } else {
+        Multiple = 25;
+      }
+      break;
+
+    case 7:
+      Multiple = 30;
+      break;
+
+    case 8:
+      Multiple = 35;
+      break;
+
+    case 9:
+      Multiple = 40;
+      break;
+
+    case 10:
+      Multiple = 45;
+      break;
+
+    case 11:
+      if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+        Multiple = 52;
+      } else {
+        Multiple = 50;
+      }
+      break;
+
+    case 12:
+      Multiple = 55;
+      break;
+
+    case 13:
+      Multiple = 60;
+      break;
+
+    case 14:
+      Multiple = 70;
+      break;
+
+    case 15:
+      Multiple = 80;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  Frequency = Frequency * Multiple / 10;
+  CardData->MaxFrequency = Frequency;
+
+  CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN;
+
+  if (CardData->CardType == SDMemoryCard2High) {
+    ASSERT(CardData->CSDRegister.CSD_STRUCTURE == 1);
+    CsdSDV2 = (CSD_SDV2*)&CardData->CSDRegister;
+    //
+    // The SD Spec 2.0 says (CSize + 1) * 512K is the total size, so block numbber is (CSize + 1) * 1K
+    // the K here means 1024 not 1000
+    //
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen);
+  } else {
+    //
+    // For MMC card > 2G, the block number will be recaculate later
+    //
+    CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2);
+    CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1);
+  }
+
+  //
+  //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes
+  //
+  if (CardData->BlockLen > 512) {
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512);
+    CardData->BlockLen    = 512;
+  }
+
+  DEBUG((
+    EFI_D_INFO,
+          "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen)
+    ));
+
+Exit:
+  return Status;
+}
+
+/**
+  Test the bus width setting for MMC card.It is used only for verification purpose.
+
+  @param  CardData               Pointer to CARD_DATA.
+  @param  Width                  1, 4, 8 bits.
+
+  @retval EFI_SUCCESS
+  @retval EFI_UNSUPPORTED
+  @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+MMCCardBusWidthTest (
+  IN  CARD_DATA             *CardData,
+  IN  UINT32                Width
+  )
+{
+  EFI_STATUS                 Status;
+  UINT64                     Data;
+  UINT64                     Value;
+
+  ASSERT(CardData != NULL);
+
+
+  Value = 0;
+
+  switch (Width) {
+    case 1:
+      Data = 0x80;
+      break;
+
+    case 4:
+      Data = 0x5A;
+      break;
+
+    case 8:
+      Data = 0xAA55;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  CopyMem (CardData->AlignedBuffer, &Data, Width);
+  Status  = SendCommand (
+              CardData,
+              BUSTEST_W,
+              0,
+              OutData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32*)&(CardData->CardStatus)
+              );
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_W 0x%x\n", *(UINT32*)&(CardData->CardStatus)));
+    goto Exit;
+  }
+
+  gBS->Stall (10 * 1000);
+
+  Data = 0;
+
+  Status  = SendCommand (
+              CardData,
+              BUSTEST_R,
+              0,
+              InData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32*)&(CardData->CardStatus)
+              );
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_R 0x%x\n", *(UINT32*)&(CardData->CardStatus)));
+    goto Exit;
+  }
+  CopyMem (&Data, CardData->AlignedBuffer, Width);
+
+  switch (Width) {
+    case 1:
+      Value = (~(Data ^ 0x80)) & 0xC0;
+      break;
+    case 4:
+      Value = (~(Data ^ 0x5A)) & 0xFF;
+      break;
+    case 8:
+      Value = (~(Data ^ 0xAA55)) & 0xFFFF;
+      break;
+  }
+
+  if (Value == 0) {
+    Status = EFI_SUCCESS;
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+
+Exit:
+  return Status;
+}
+
+/**
+  This function can detect these card types:
+    1. MMC card
+    2. SD 1.1 card
+    3. SD 2.0 standard card
+    3. SD 2.0 high capacity card
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+GetCardType (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
+  UINT32                     Argument;
+  UINT32                     ResponseData;
+  UINT32                     Count;
+  BOOLEAN                    SDCommand8Support;
+
+
+  SDHostIo = CardData->SDHostIo;
+
+  //
+  // Reset the card
+  //
+  Status  = SendCommand (
+              CardData,
+              GO_IDLE_STATE,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseNo,
+              TIMEOUT_COMMAND,
+              NULL
+              );
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+
+  //
+  //No spec requirment, can be adjusted
+  //
+  gBS->Stall (10 * 1000);
+
+
+  //
+  // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass
+  // MMC and SD1.1 card will fail this command
+  //
+  Argument          = (VOLTAGE_27_36 << 8) | CHECK_PATTERN;
+  ResponseData      = 0;
+  SDCommand8Support = FALSE;
+
+  Status  = SendCommand (
+              CardData,
+              SEND_IF_COND,
+              Argument,
+              NoData,
+              NULL,
+              0,
+              ResponseR7,
+              TIMEOUT_COMMAND,
+              &ResponseData
+              );
+
+  if (EFI_ERROR (Status)) {
+    if (Status != EFI_TIMEOUT) {
+       DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, none time out error\n"));
+       goto Exit;
+    }
+  } else {
+     if (ResponseData != Argument) {
+       DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n"));
+       Status = EFI_DEVICE_ERROR;
+       goto Exit;
+    }
+    SDCommand8Support = TRUE;
+  }
+
+
+  Argument = 0;
+  if (SDHostIo->HostCapability.V30Support == TRUE) {
+    Argument |= BIT17 | BIT18;
+  } else if (SDHostIo->HostCapability.V33Support == TRUE) {
+    Argument |= BIT20 | BIT21;
+  }
+
+  if (SDCommand8Support) {
+    //
+    //If command SD_SEND_OP_COND sucessed, it should be set.
+    // SD 1.1 card will ignore it
+    // SD 2.0 standard card will repsond with CCS 0, SD high capacity card will respond with CCS 1
+    // CCS is BIT30 of OCR
+    Argument |= BIT30;
+  }
+
+
+  Count        = 20;
+  //
+  //Only SD card will respond to this command, and spec says the card only checks condition at first ACMD41 command
+  //
+  do {
+    Status  = SendAppCommand (
+                CardData,
+                SD_SEND_OP_COND,
+                Argument,
+                NoData,
+                NULL,
+                0,
+                ResponseR3,
+                TIMEOUT_COMMAND,
+                (UINT32*)&(CardData->OCRRegister)
+                );
+    if (EFI_ERROR (Status)) {
+      if ((Status == EFI_TIMEOUT) && (!SDCommand8Support)) {
+        CardData->CardType = MMCCard;
+        Status = EFI_SUCCESS;
+        DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, MMC card was identified\n"));
+      } else {
+        //
+        // Not as expected, MMC card should has no response, which means timeout.
+        // SD card should pass this command
+        //
+        DEBUG((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n"));
+      }
+      goto Exit;
+    }
+    //
+    //Avoid waiting if sucess. Busy bit 0 means not ready
+    //
+    if (CardData->OCRRegister.Busy == 1) {
+      break;
+    }
+
+    gBS->Stall (50 * 1000);
+    Count--;
+    if (Count == 0) {
+      DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));
+      Status = EFI_TIMEOUT;
+      goto Exit;
+    }
+  } while (1);
+
+  //
+  //Check supported voltage
+  //
+  Argument = 0;
+  if (SDHostIo->HostCapability.V30Support == TRUE) {
+    if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) {
+      Argument |= BIT17;
+    } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) {
+      Argument |= BIT18;
+    }
+  } else if (SDHostIo->HostCapability.V33Support == TRUE) {
+     if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) {
+       Argument |= BIT20;
+     } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) {
+       Argument |= BIT21;
+     }
+  }
+
+  if (Argument == 0) {
+     //
+     //No matched support voltage
+     //
+     PutCardInactive (CardData);
+     DEBUG((EFI_D_ERROR, "No matched voltage for this card\n"));
+     Status = EFI_UNSUPPORTED;
+     goto Exit;
+  }
+
+  CardData->CardType = SDMemoryCard;
+  if (SDCommand8Support == TRUE) {
+   CardData->CardType = SDMemoryCard2;
+   DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above standard card was identified\n"));
+  }
+
+  if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) {
+    CardData->CardType = SDMemoryCard2High;
+    DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above high capacity card was identified\n"));
+  }
+
+
+
+Exit:
+  return Status;
+}
+
+/**
+  MMC card high/low voltage selection function
+
+  @param  CardData               Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_UNSUPPORTED
+  @retval EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCCardVoltageSelection (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      Retry;
+  UINT32                     TimeOut;
+
+  Status   = EFI_SUCCESS;
+  //
+  //First try the high voltage, then if supported choose the low voltage
+  //
+
+    for (Retry = 0; Retry < 3; Retry++) {
+      //
+      // To bring back the normal MMC card to work
+      // after sending the SD command. Otherwise some
+      // card could not work
+
+      Status  = SendCommand (
+                CardData,
+                  GO_IDLE_STATE,
+                  0,
+                  NoData,
+                  NULL,
+                  0,
+                  ResponseNo,
+                  TIMEOUT_COMMAND,
+                  NULL
+                  );
+      if (EFI_ERROR (Status)) {
+        DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+        continue;
+      }
+      //
+      //CE-ATA device needs long delay
+      //
+      gBS->Stall ((Retry + 1) * 50 * 1000);
+
+      //
+      //Get OCR register to check voltage support, first time the OCR is 0
+      //
+      Status  = SendCommand (
+                CardData,
+                  SEND_OP_COND,
+                  0,
+                  NoData,
+                  NULL,
+                  0,
+                  ResponseR3,
+                  TIMEOUT_COMMAND,
+                  (UINT32*)&(CardData->OCRRegister)
+                  );
+      if (!EFI_ERROR (Status)) {
+        break;
+      }
+    }
+
+    if (Retry == 3) {
+      DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+      Status = EFI_DEVICE_ERROR;
+      goto Exit;
+    }
+
+    //
+    //TimeOut Value, 5000 * 100 * 1000 = 5 s
+    //
+    TimeOut = 5000;
+
+    do {
+      Status  = SendCommand (
+                CardData,
+                  SEND_OP_COND,
+                  0x40300000,
+                  NoData,
+                  NULL,
+                  0,
+                  ResponseR3,
+                  TIMEOUT_COMMAND,
+                  (UINT32*)&(CardData->OCRRegister)
+                  );
+      if (EFI_ERROR (Status)) {
+        DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      gBS->Stall (1 * 1000);
+      TimeOut--;
+      if (TimeOut == 0) {
+        Status = EFI_TIMEOUT;
+      DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));
+        goto Exit;
+      }
+    } while (CardData->OCRRegister.Busy != 1);
+
+  if (CardData->OCRRegister.AccessMode == 2) // eMMC Card uses Sector Addressing - High Capacity
+    {
+    DEBUG((EFI_D_INFO, "eMMC Card is High Capacity\n"));
+    CardData->CardType = MMCCardHighCap;
+  }
+
+Exit:
+  return Status;
+
+}
+
+/**
+  This function set the bus and device width for MMC card
+
+  @param  CardData               Pointer to CARD_DATA.
+  @param  Width                  1, 4, 8 bits.
+
+  @retval EFI_SUCCESS
+  @retval EFI_UNSUPPORTED
+  @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+MMCCardSetBusWidth (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  BusWidth,
+  IN  BOOLEAN                EnableDDRMode
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT8                      Value;
+
+  SDHostIo = CardData->SDHostIo;
+  Value = 0;
+  switch (BusWidth) {
+    case 8:
+      if (EnableDDRMode)
+        Value = 6;
+      else
+      Value = 2;
+      break;
+
+    case 4:
+      if (EnableDDRMode)
+        Value = 5;
+      else
+      Value = 1;
+      break;
+
+    case 1:
+      if (EnableDDRMode)    // Bus width 1 is not supported in ddr mode
+        return EFI_UNSUPPORTED;
+      Value = 0;
+      break;
+
+    default:
+     ASSERT(0);
+  }
+
+
+  ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+  SwitchArgument.CmdSet = 0;
+  SwitchArgument.Value  = Value;
+  SwitchArgument.Index  = (UINT32)((UINTN)
+  (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN)(&(CardData->ExtCSDRegister)));
+  SwitchArgument.Access = WriteByte_Mode;
+  Status  = SendCommand (
+              CardData,
+              SWITCH,
+              *(UINT32*)&SwitchArgument,
+              NoData,
+              NULL,
+              0,
+              ResponseR1b,
+              TIMEOUT_COMMAND,
+              (UINT32*)&(CardData->CardStatus)
+              );
+  if (!EFI_ERROR (Status)) {
+     Status  = SendCommand (
+                 CardData,
+                 SEND_STATUS,
+                 (CardData->Address << 16),
+                 NoData,
+                 NULL,
+                 0,
+                 ResponseR1,
+                 TIMEOUT_COMMAND,
+                 (UINT32*)&(CardData->CardStatus)
+                 );
+    if (EFI_ERROR (Status)) {
+      DEBUG((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));
+      goto Exit;
+    } else {
+      DEBUG((EFI_D_ERROR, "MMCCardSetBusWidth:SWITCH Card Status:0x%x\n", *(UINT32*)&(CardData->CardStatus)));
+      Status = SDHostIo->SetBusWidth (SDHostIo, BusWidth);
+      if (EFI_ERROR (Status)) {
+         DEBUG((EFI_D_ERROR, "SWITCH set %d bits Fail\n", BusWidth));
+         goto Exit;
+      }
+      gBS->Stall (5 * 1000);
+    }
+  }
+
+  if (!EnableDDRMode) {     // CMD19 and CMD14 are illegal commands in ddr mode
+  //if (EFI_ERROR (Status)) {
+  //  DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest: Fail to enable high speed mode\n"));
+  //  goto Exit;
+  //}
+
+  Status = MMCCardBusWidthTest (CardData, BusWidth);
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));
+    goto Exit;
+    }
+  }
+
+  CardData->CurrentBusWidth = BusWidth;
+
+Exit:
+  return Status;
+}
+
+
+/**
+  MMC/SD card init function
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT32                     Data;
+  UINT32                     Argument;
+  UINT32                     nIndex;
+  UINT8                      PowerValue;
+  BOOLEAN                    EnableDDRMode;
+
+  ASSERT(CardData != NULL);
+  SDHostIo                  = CardData->SDHostIo;
+  EnableDDRMode             = FALSE;
+
+  CardData->CardType = UnknownCard;
+  Status = GetCardType (CardData);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+  DEBUG((DEBUG_INFO, "CardData->CardType  0x%x\n", CardData->CardType));
+
+  ASSERT (CardData->CardType != UnknownCard);
+  //
+  //MMC, SD card need host auto stop command support
+  //
+  SDHostIo->EnableAutoStopCmd (SDHostIo, TRUE);
+
+  if (CardData->CardType == MMCCard) {
+    Status = MMCCardVoltageSelection (CardData);
+    if (EFI_ERROR(Status)) {
+      goto Exit;
+    }
+  }
+
+  //
+  // Get CID Register
+  //
+  Status  = SendCommand (
+              CardData,
+              ALL_SEND_CID,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32*)&(CardData->CIDRegister)
+              );
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "ALL_SEND_CID Fail Status = 0x%x\n", Status));
+    goto Exit;
+  } else {
+    // Dump out the Card ID data
+    DEBUG((EFI_D_INFO, "Product Name: "));
+    for ( nIndex=0; nIndex<6; nIndex++ ) {
+      DEBUG((EFI_D_INFO, "%c", CardData->CIDRegister.PNM[nIndex]));
+    }
+    DEBUG((EFI_D_INFO, "\nApplication ID : %d\n", CardData->CIDRegister.OID));
+    DEBUG((EFI_D_INFO, "Manufacturer ID: %d\n", CardData->CIDRegister.MID));
+    DEBUG((EFI_D_INFO, "Revision ID    : %d\n", CardData->CIDRegister.PRV));
+    DEBUG((EFI_D_INFO, "Serial Number  : %d\n", CardData->CIDRegister.PSN));
+  }
+
+  //
+  //SET_RELATIVE_ADDR
+  //
+  if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+    //
+    //Hard code the RCA address
+    //
+    CardData->Address = 1;
+
+    //
+    // Set RCA Register
+    //
+    Status  = SendCommand (
+                CardData,
+                SET_RELATIVE_ADDR,
+                (CardData->Address << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32*)&(CardData->CardStatus)
+                );
+    if (EFI_ERROR (Status)) {
+      DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+  } else {
+    Data = 0;
+    Status  = SendCommand (
+                CardData,
+                SET_RELATIVE_ADDR,
+                0,
+                NoData,
+                NULL,
+                0,
+                ResponseR6,
+                TIMEOUT_COMMAND,
+                &Data
+                );
+    if (EFI_ERROR (Status)) {
+      DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+
+    CardData->Address = (UINT16)(Data >> 16);
+    *(UINT32*)&CardData->CardStatus      = Data & 0x1FFF;
+    CardData->CardStatus.ERROR           = (Data >> 13) & 0x1;
+    CardData->CardStatus.ILLEGAL_COMMAND = (Data >> 14) & 0x1;
+    CardData->CardStatus.COM_CRC_ERROR   = (Data >> 15) & 0x1;
+    Status = CheckCardStatus (*(UINT32*)&CardData->CardStatus);
+    if (EFI_ERROR (Status)) {
+      DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+  }
+
+  //
+  // Get CSD Register
+  //
+  Status  = SendCommand (
+              CardData,
+              SEND_CSD,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32*)&(CardData->CSDRegister)
+              );
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "SEND_CSD Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+
+  DEBUG((EFI_D_INFO, "CardData->CSDRegister.SPEC_VERS = 0x%x\n", CardData->CSDRegister.SPEC_VERS));
+  DEBUG((EFI_D_INFO, "CardData->CSDRegister.CSD_STRUCTURE = 0x%x\n", CardData->CSDRegister.CSD_STRUCTURE));
+
+  Status = CaculateCardParameter (CardData);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+
+  //
+  // It is platform and hardware specific, need hadrware engineer input
+  //
+  if (CardData->CSDRegister.DSR_IMP == 1) {
+    //
+    // Default is 0x404
+    //
+    Status  = SendCommand (
+                CardData,
+                SET_DSR,
+                (DEFAULT_DSR_VALUE << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseNo,
+                TIMEOUT_COMMAND,
+                NULL
+                );
+    if (EFI_ERROR (Status)) {
+      DEBUG((EFI_D_ERROR, "SET_DSR Fail Status = 0x%x\n", Status));
+      //
+      // Assume can operate even fail
+      //
+    }
+  }
+  //
+  //Change clock frequency from 400KHz to max supported when not in high speed mode
+  //
+  Status = SDHostIo->SetClockFrequency (SDHostIo, CardData->MaxFrequency);
+  if (EFI_ERROR (Status)) {
+  DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
+  goto Exit;
+  }
+
+  //
+  //Put the card into tran state
+  //
+  Status = SendCommand (
+             CardData,
+             SELECT_DESELECT_CARD,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseR1,
+             TIMEOUT_COMMAND,
+             (UINT32*)&(CardData->CardStatus)
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+
+  //
+  // No spec requirment, can be adjusted
+  //
+  gBS->Stall (5 * 1000);
+  //
+  // No need to do so
+  //
+  //
+  Status  = SendCommand (
+              CardData,
+              SEND_STATUS,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32*)&(CardData->CardStatus)
+              );
+  if (EFI_ERROR (Status)) {
+     DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));
+     goto Exit;
+  }
+  //
+  //if the SPEC_VERS indicates a version 4.0 or higher
+  //The card is a high speed card and support Switch
+  //and Send_ext_csd command
+  //otherwise it is an old card
+  //
+
+  if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+    //
+    //Only V4.0 and above supports more than 1 bits and high speed
+    //
+    if (CardData->CSDRegister.SPEC_VERS >= 4) {
+    //
+      //Get ExtCSDRegister
+      //
+      Status  = SendCommand (
+                  CardData,
+                  SEND_EXT_CSD,
+                  0x0,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (EXT_CSD),
+                  ResponseR1,
+                  TIMEOUT_DATA,
+                  (UINT32*)&(CardData->CardStatus)
+                  );
+      if (EFI_ERROR (Status)) {
+        DEBUG((EFI_D_ERROR, "SEND_EXT_CSD Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));
+
+      //
+      // Recaculate the block number for >2G MMC card
+      //
+      Data  = (CardData->ExtCSDRegister.SEC_COUNT[0]) |
+              (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) |
+              (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |
+              (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);
+
+      if (Data != 0) {
+        CardData->BlockNumber = Data;
+      }
+      DEBUG((DEBUG_INFO, "CardData->BlockNumber  %d\n", Data));
+      DEBUG((EFI_D_ERROR, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN)CardData->ExtCSDRegister.CARD_TYPE));
+      if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2)||
+          (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+          //DEBUG((DEBUG_INFO, "To enable DDR mode\n"));
+          //EnableDDRMode = TRUE;
+      }
+      //
+      // Check current chipset capability and the plugged-in card
+      // whether supports HighSpeed
+      //
+      if (SDHostIo->HostCapability.HighSpeedSupport) {
+
+        //
+        //Change card timing to high speed interface timing
+        //
+        ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = 1;
+        SwitchArgument.Index  = (UINT32)((UINTN)
+        (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN)(&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    CardData,
+                    SWITCH,
+                    *(UINT32*)&SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32*)&(CardData->CardStatus)
+                    );
+        if (EFI_ERROR (Status)) {
+          DEBUG((EFI_D_ERROR, "MMCSDCardInit:SWITCH frequency Fail Status = 0x%x\n", Status));
+        }
+
+        gBS->Stall (5 * 1000);
+
+
+        if (!EFI_ERROR (Status)) {
+          Status  = SendCommand (
+                      CardData,
+                      SEND_STATUS,
+                      (CardData->Address << 16),
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32*)&(CardData->CardStatus)
+                      );
+          if (!EFI_ERROR (Status)) {
+            if (EnableDDRMode) {
+              DEBUG((EFI_D_ERROR, "Enable ddr mode on host controller\n"));
+              SDHostIo->SetDDRMode (SDHostIo, TRUE);
+            } else  {
+              DEBUG((EFI_D_ERROR, "Enable high speed mode on host controller\n"));
+              SDHostIo->SetHighSpeedMode (SDHostIo, TRUE);
+            }
+          //
+          // Change host clock to support high speed and enable chispet to
+          // support speed
+          //
+            if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+              Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP_HIGH);
+            } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+              Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP);
+            } else {
+              Status = EFI_UNSUPPORTED;
+            }
+            if (EFI_ERROR (Status)) {
+              DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
+              goto Exit;
+            }
+            //
+            // It seems no need to stall after changing bus freqeuncy.
+            // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.
+            // But SetClock alreay has delay.
+            //
+          }
+        }
+
+      }
+
+
+
+      //
+      // Prefer wide bus width for performance
+      //
+      //
+      // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits
+      //
+      if (SDHostIo->HostCapability.BusWidth8 == TRUE) {
+         Status = MMCCardSetBusWidth (CardData, 8, EnableDDRMode);
+         if (EFI_ERROR (Status)) {
+            //
+            // CE-ATA may support 8 bits and 4 bits, but has no software method for detection
+            //
+            Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);
+            if (EFI_ERROR (Status)) {
+              goto Exit;
+            }
+         }
+      } else if (SDHostIo->HostCapability.BusWidth4 == TRUE) {
+         Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);
+         if (EFI_ERROR (Status)) {
+           goto Exit;
+         }
+      }
+
+      PowerValue = 0;
+
+      if (CardData->CurrentBusWidth == 8) {
+        if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue >> 4;
+        } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+          PowerValue = PowerValue >> 4;
+        }
+      } else if (CardData->CurrentBusWidth == 4) {
+         if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue & 0xF;
+         } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+           PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+           PowerValue = PowerValue & 0xF;
+         }
+      }
+
+      if (PowerValue != 0) {
+        //
+        //Update Power Class
+        //
+        ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = PowerValue;
+        SwitchArgument.Index  = (UINT32)((UINTN)
+        (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN)(&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    CardData,
+                    SWITCH,
+                    *(UINT32*)&SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32*)&(CardData->CardStatus)
+                    );
+         if (!EFI_ERROR (Status)) {
+           Status  = SendCommand (
+                       CardData,
+                       SEND_STATUS,
+                       (CardData->Address << 16),
+                       NoData,
+                       NULL,
+                       0,
+                       ResponseR1,
+                       TIMEOUT_COMMAND,
+                       (UINT32*)&(CardData->CardStatus)
+                       );
+           if (EFI_ERROR (Status)) {
+             DEBUG((EFI_D_ERROR, "SWITCH Power Class Fail Status = 0x%x\n", Status));
+           }
+           //gBS->Stall (10 * 1000);
+         }
+      }
+
+
+
+    } else {
+
+
+      DEBUG((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n",CardData->CSDRegister.SPEC_VERS));
+    }
+  } else {
+      //
+      // Pin 1, at power up this line has a 50KOhm pull up enabled in the card.
+      // This pull-up should be disconnected by the user, during regular data transfer,
+      // with SET_CLR_CARD_DETECT (ACMD42) command
+      //
+      Status  = SendAppCommand (
+                  CardData,
+                  SET_CLR_CARD_DETECT,
+                  0,
+                  NoData,
+                  NULL,
+                  0,
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32*)&(CardData->CardStatus)
+                  );
+      if (EFI_ERROR (Status)) {
+        DEBUG((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      /*
+      //
+      // Don't rely on SCR and SD status, some cards have unexpected SCR.
+      // It only sets private section, the other bits are 0
+      // such as Sandisk Ultra II 4.0G, KinSton mini SD 128M, Toshiba 2.0GB
+      // Some card even fail this command, KinSton SD 4GB
+      //
+      Status  = SendAppCommand (
+                  CardData,
+                  SEND_SCR,
+                  0,
+                  InData,
+                  (UINT8*)&(CardData->SCRRegister),
+                  sizeof(SCR),
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32*)&(CardData->CardStatus)
+                  );
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+
+      //
+      // SD memory card at least supports 1 and 4 bits.
+      //
+      // ASSERT ((CardData->SCRRegister.SD_BUS_WIDTH & (BIT0 | BIT2)) == (BIT0 | BIT2));
+      */
+
+      //
+      // Set Bus Width to 4
+      //
+      Status  = SendAppCommand (
+                  CardData,
+                  SET_BUS_WIDTH,
+                  SD_BUS_WIDTH_4,
+                  NoData,
+                  NULL,
+                  0,
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32*)&(CardData->CardStatus)
+                  );
+      if (EFI_ERROR (Status)) {
+        DEBUG((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      Status = SDHostIo->SetBusWidth (SDHostIo, 4);
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+      CardData->CurrentBusWidth = 4;
+
+
+      if ((SDHostIo->HostCapability.HighSpeedSupport == FALSE) ||
+          ((CardData->CSDRegister.CCC & BIT10) != BIT10)) {
+        //
+        // Host must support high speed
+        // Card must support Switch function
+        //
+        goto Exit;
+      }
+
+      //
+      //Mode = 0, group 1, function 1, check operation
+      //
+      Argument    = 0xFFFF01;
+      ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+      Status  = SendCommand (
+                  CardData,
+                  SWITCH_FUNC,
+                  Argument,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (SWITCH_STATUS),
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32*)&(CardData->CardStatus)
+                  );
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+      CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+      if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+          ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+        //
+        // 1. SD 1.1 card does not suppport busy bit
+        // 2. Ready state
+        //
+        //
+
+        //
+        //Mode = 1, group 1, function 1, BIT31 set means set mode
+        //
+        Argument = 0xFFFF01 | BIT31;
+        ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+        Status  = SendCommand (
+                    CardData,
+                    SWITCH_FUNC,
+                    Argument,
+                    InData,
+                    CardData->AlignedBuffer,
+                    sizeof (SWITCH_STATUS),
+                    ResponseR1,
+                    TIMEOUT_COMMAND,
+                   (UINT32*)&(CardData->CardStatus)
+                   );
+         if (EFI_ERROR (Status)) {
+            goto Exit;
+         }
+         CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+         if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+            ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+          //
+          // 1. SD 1.1 card does not suppport busy bit
+          // 2. Ready state
+          //
+
+          //
+          // 8 clocks, (1/ 25M) * 8 ==> 320 us, so 1ms > 0.32 ms
+          //
+          gBS->Stall (1000);
+
+          //
+          //Change host clock
+          //
+          Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_SD_PP_HIGH);
+          if (EFI_ERROR (Status)) {
+            goto Exit;
+          }
+
+         }
+      }
+  }
+  if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+      (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) {
+
+  //
+  // Set Block Length, to improve compatibility in case of some cards
+  //
+  Status  = SendCommand (
+                CardData,
+              SET_BLOCKLEN,
+              512,
+              NoData,
+              NULL,
+              0,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32*)&(CardData->CardStatus)
+              );
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "SET_BLOCKLEN Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+  }
+  SDHostIo->SetBlockLength (SDHostIo, 512);
+
+
+Exit:
+  return Status;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c
new file mode 100644
index 0000000000..400f041526
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c
@@ -0,0 +1,317 @@
+/** @file
+
+The definition for SD media device driver model and blkio protocol routines.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "SDMediaDevice.h"
+
+
+EFI_DRIVER_BINDING_PROTOCOL gSDMediaDeviceDriverBinding = {
+  SDMediaDeviceSupported,
+  SDMediaDeviceStart,
+  SDMediaDeviceStop,
+  0x20,
+  NULL,
+  NULL
+};
+
+/**
+  Entry point for EFI drivers.
+
+  @param  ImageHandle      EFI_HANDLE.
+  @param  SystemTable      EFI_SYSTEM_TABLE.
+
+  @retval EFI_SUCCESS      Driver is successfully loaded.
+  @return Others           Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSDMediaDevice (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &gSDMediaDeviceDriverBinding,
+           ImageHandle,
+           &gSDMediaDeviceName,
+           &gSDMediaDeviceName2
+           );
+}
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has BlockIoProtocol installed will be supported.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @return EFI_SUCCESS          This driver supports this device.
+  @return EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  EFI_SD_HOST_IO_PROTOCOL   *SDHostIo;
+
+  //
+  // Test whether there is PCI IO Protocol attached on the controller handle.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSDHostIoProtocolGuid,
+                  (VOID **)&SDHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiSDHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+Exit:
+  return Status;
+}
+
+/**
+  Starting the SD Media Device Driver.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @retval EFI_SUCCESS          This driver supports this device.
+  @retval EFI_UNSUPPORTED      This driver does not support this device.
+  @retval EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                               EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  EFI_SD_HOST_IO_PROTOCOL   *SDHostIo;
+  CARD_DATA                 *CardData;
+
+  CardData = NULL;
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSDHostIoProtocolGuid,
+                  (VOID **) &SDHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to open gEfiSDHostIoProtocolGuid \r\n"));
+    goto Exit;
+  }
+
+  Status = SDHostIo->DetectCardAndInitHost (SDHostIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: Fail to DetectCardAndInitHost \r\n"));
+    goto Exit;
+  }
+
+  CardData = (CARD_DATA*)AllocateZeroPool(sizeof (CARD_DATA));
+  if (CardData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to AllocateZeroPool(CARD_DATA) \r\n"));
+    goto Exit;
+  }
+
+  ASSERT (SDHostIo->HostCapability.BoundarySize >= 4 * 1024);
+  CardData->RawBufferPointer = (UINT8*)((UINTN)DMA_MEMORY_TOP);
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiBootServicesData,
+                  EFI_SIZE_TO_PAGES (2 * SDHostIo->HostCapability.BoundarySize),
+                  (EFI_PHYSICAL_ADDRESS *)(&CardData->RawBufferPointer)
+                  );
+
+  if (CardData->RawBufferPointer == NULL) {
+    DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to AllocateZeroPool(2*x) \r\n"));
+    Status =  EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+  CardData->AlignedBuffer = CardData->RawBufferPointer - ((UINTN)(CardData->RawBufferPointer) & (SDHostIo->HostCapability.BoundarySize - 1)) + SDHostIo->HostCapability.BoundarySize;
+
+  CardData->Signature = CARD_DATA_SIGNATURE;
+  CardData->SDHostIo  = SDHostIo;
+
+  Status = MMCSDCardInit (CardData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to MMCSDCardInit \r\n"));
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: MMCSDCardInit SuccessFul\n"));
+
+  if (CardData->CardType == CEATACard) {
+    Status = CEATABlockIoInit (CardData);
+  } else {
+    Status = MMCSDBlockIoInit (CardData);
+  }
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to BlockIoInit \r\n"));
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: BlockIo is successfully installed\n"));
+
+
+  Status = gBS->InstallProtocolInterface (
+                  &Controller,
+                  &gEfiBlockIoProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &CardData->BlockIo
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to install gEfiBlockIoProtocolGuid \r\n"));
+    goto Exit;
+  }
+
+  //
+  // Install the component name protocol
+  //
+  CardData->ControllerNameTable = NULL;
+
+  AddUnicodeString2 (
+    "eng",
+    gSDMediaDeviceName.SupportedLanguages,
+    &CardData->ControllerNameTable,
+    L"MMC/SD Media Device",
+    TRUE
+    );
+  AddUnicodeString2 (
+    "en",
+    gSDMediaDeviceName2.SupportedLanguages,
+    &CardData->ControllerNameTable,
+    L"MMC/SD Media Device",
+    FALSE
+    );
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: End with failure\r\n"));
+    if (CardData != NULL) {
+      if (CardData->RawBufferPointer != NULL) {
+        gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * SDHostIo->HostCapability.BoundarySize));
+      }
+      FreePool (CardData);
+    }
+  }
+
+  return Status;
+}
+
+
+/**
+  Stop this driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to stop driver on.
+  @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                Status;
+  CARD_DATA                 *CardData;
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;
+
+  //
+  // First find BlockIo Protocol
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **)&BlockIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardData  = CARD_DATA_FROM_THIS(BlockIo);
+
+  //
+  // Uninstall Block I/O protocol from the device handle
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  Controller,
+                  &gEfiBlockIoProtocolGuid,
+                  BlockIo
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (CardData != NULL) {
+    if (CardData->RawBufferPointer != NULL) {
+      gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * CardData->SDHostIo->HostCapability.BoundarySize));
+    }
+    FreeUnicodeStringTable (CardData->ControllerNameTable);
+    FreePool (CardData);
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiSDHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return EFI_SUCCESS;
+}
+
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h
new file mode 100644
index 0000000000..ac70f5a8bf
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h
@@ -0,0 +1,462 @@
+/** @file
+
+The definition for SD media device driver model and blkio protocol routines.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_MEDIA_DEVICE_H_
+#define _SD_MEDIA_DEVICE_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/BlockIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Pci22.h>
+
+#include "ComponentName.h"
+#include "SDHostIo.h"
+
+
+extern EFI_DRIVER_BINDING_PROTOCOL   gSDMediaDeviceDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gSDMediaDeviceName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gSDMediaDeviceName2;
+
+//
+// Define the region of memory used for DMA memory
+//
+#define DMA_MEMORY_TOP          0x0000000001FFFFFFULL
+
+#define CARD_DATA_SIGNATURE  SIGNATURE_32 ('c', 'a', 'r', 'd')
+
+//
+// Command timeout will be max 100 ms
+//
+#define  TIMEOUT_COMMAND     100
+#define  TIMEOUT_DATA        5000
+
+typedef enum{
+  UnknownCard = 0,
+  MMCCard,                // MMC card
+  MMCCardHighCap,          // MMC Card High Capacity
+  CEATACard,              // CE-ATA device
+  SDMemoryCard,           // SD 1.1 card
+  SDMemoryCard2,          // SD 2.0 or above standard card
+  SDMemoryCard2High       // SD 2.0 or above high capacity card
+}CARD_TYPE;
+
+
+typedef struct {
+  //
+  //BlockIO
+  //
+  UINTN                     Signature;
+  EFI_BLOCK_IO_PROTOCOL     BlockIo;
+
+  EFI_BLOCK_IO_MEDIA        BlockIoMedia;
+
+  EFI_SD_HOST_IO_PROTOCOL   *SDHostIo;
+  EFI_UNICODE_STRING_TABLE  *ControllerNameTable;
+  CARD_TYPE                 CardType;
+
+  UINT8                     CurrentBusWidth;
+  BOOLEAN                   DualVoltage;
+  BOOLEAN                   NeedFlush;
+  UINT8                     Reserved[3];
+
+  UINT16                    Address;
+  UINT32                    BlockLen;
+  UINT32                    MaxFrequency;
+  UINT64                    BlockNumber;
+  //
+  //Common used
+  //
+  CARD_STATUS               CardStatus;
+  OCR                       OCRRegister;
+  CID                       CIDRegister;
+  CSD                       CSDRegister;
+  EXT_CSD                   ExtCSDRegister;
+  UINT8                     *RawBufferPointer;
+  UINT8                     *AlignedBuffer;
+  //
+  //CE-ATA specific
+  //
+  TASK_FILE                 TaskFile;
+  IDENTIFY_DEVICE_DATA      IndentifyDeviceData;
+  //
+  //SD specific
+  //
+  SCR                       SCRRegister;
+  SD_STATUS_REG             SDSattus;
+  SWITCH_STATUS             SwitchStatus;
+}CARD_DATA;
+
+#define CARD_DATA_FROM_THIS(a) \
+    CR(a, CARD_DATA, BlockIo, CARD_DATA_SIGNATURE)
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has BlockIoProtocol installed will be supported.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @return EFI_SUCCESS          This driver supports this device.
+  @return EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Starting the SD Media Device Driver.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @retval EFI_SUCCESS          This driver supports this device.
+  @retval EFI_UNSUPPORTED      This driver does not support this device.
+  @retval EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                               EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Stop this driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to stop driver on.
+  @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  );
+
+/**
+  MMC/SD card init function
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  Send command by using Host IO protocol
+
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param  CommandIndex          The command index to set the command index field of command register.
+  @param  Argument              Command argument to set the argument field of command register.
+  @param  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param  Buffer                Contains the data read from / write to the device.
+  @param  BufferSize            The size of the buffer.
+  @param  ResponseType          RESPONSE_TYPE.
+  @param  TimeOut               Time out value in 1 ms unit.
+  @param  ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_UNSUPPORTED
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  );
+
+/**
+  Send the card APP_CMD command with the following command indicated by CommandIndex
+
+  @param  CardData              Pointer to CARD_DATA.
+  @param  CommandIndex          The command index to set the command index field of command register.
+  @param  Argument              Command argument to set the argument field of command register.
+  @param  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param  Buffer                Contains the data read from / write to the device.
+  @param  BufferSize            The size of the buffer.
+  @param  ResponseType          RESPONSE_TYPE.
+  @param  TimeOut               Time out value in 1 ms unit.
+  @param  ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval EFI_SUCCESS
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_UNSUPPORTED
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendAppCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  );
+
+/**
+  Send the card FAST_IO command
+
+  @param  CardData               Pointer to CARD_DATA.
+  @param  RegisterAddress        Register Address.
+  @param  RegisterData           Pointer to register Data.
+  @param  Write                  TRUE for write, FALSE for read.
+
+  @retval EFI_SUCCESS
+  @retval EFI_UNSUPPORTED
+  @retval EFI_INVALID_PARAMETER
+  @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+FastIO (
+  IN      CARD_DATA   *CardData,
+  IN      UINT8       RegisterAddress,
+  IN  OUT UINT8       *RegisterData,
+  IN      BOOLEAN     Write
+  );
+
+/**
+  Judge whether it is CE-ATA device or not.
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval TRUE
+  @retval FALSE
+
+**/
+BOOLEAN
+IsCEATADevice (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  Send software reset
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SoftwareReset (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  SendATACommand specificed in Taskfile
+
+  @param  CardData             Pointer to CARD_DATA.
+  @param  TaskFile             Pointer to TASK_FILE.
+  @param  Write                TRUE means write, FALSE means read.
+  @param  Buffer               If NULL, means no data transfer, neither read nor write.
+  @param  SectorCount          Buffer size in 512 bytes unit.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SendATACommand (
+  IN  CARD_DATA   *CardData,
+  IN  TASK_FILE   *TaskFile,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  );
+
+/**
+  IDENTIFY_DEVICE command
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+IndentifyDevice (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  FLUSH_CACHE_EXT command
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+FlushCache (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  STANDBY_IMMEDIATE command
+
+  @param  CardData             Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+StandByImmediate (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  READ_DMA_EXT command
+
+  @param  CardData             Pointer to CARD_DATA.
+  @param  LBA                  The starting logical block address to read from on the device.
+  @param  Buffer               A pointer to the destination buffer for the data. The caller
+                               is responsible for either having implicit or explicit ownership
+                               of the buffer.
+  @param  SectorCount          Size in 512 bytes unit.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  );
+
+/**
+  WRITE_DMA_EXT command
+
+  @param  CardData             Pointer to CARD_DATA.
+  @param  LBA                  The starting logical block address to read from on the device.
+  @param  Buffer               A pointer to the destination buffer for the data. The caller
+                               is responsible for either having implicit or explicit ownership
+                               of the buffer.
+  @param  SectorCount          Size in 512 bytes unit.
+
+  @retval EFI_SUCCESS                Success
+  @retval EFI_DEVICE_ERROR           Hardware Error
+  @retval EFI_INVALID_PARAMETER      Parameter is error
+  @retval EFI_NO_MEDIA               No media
+  @retval EFI_MEDIA_CHANGED          Media Change
+  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+WriteDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  );
+
+/**
+  CEATA card BlockIo init function.
+
+  @param  CardData               Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS
+  @retval Others
+**/
+EFI_STATUS
+CEATABlockIoInit (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  MMC/SD card BlockIo init function.
+
+  @param  CardData               Pointer to CARD_DATA.
+
+  @retval EFI_SUCCESS
+  @retval Others
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+  IN  CARD_DATA    *CardData
+  );
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf
new file mode 100644
index 0000000000..eb85b9c0a6
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf
@@ -0,0 +1,60 @@
+## @file
+#
+#  Component Description File For SDMediaDeviceDxe Module.
+#
+#  Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SDMediaDevice
+  FILE_GUID                      = 80897901-91F6-4efe-9579-3353A0C02DAB
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeSDMediaDevice
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+#  DRIVER_BINDING                =  gSDMediaDeviceDriverBinding
+#  COMPONENT_NAME                =  gSDMediaDeviceName
+#  COMPONENT_NAME2               =  gSDMediaDeviceName2
+#
+
+[Sources]
+  SDMediaDevice.c
+  SDMediaDevice.h
+  MMCSDTransfer.c
+  CEATA.c
+  CEATABlockIo.c
+  MMCSDBlockIo.c
+  ComponentName.c
+  ComponentName.h
+
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gEfiSDHostIoProtocolGuid                      ## TO_START
+  gEfiBlockIoProtocolGuid                       ## BY_START
+
+[Pcd.common]
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c
new file mode 100644
index 0000000000..f393aa8643
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c
@@ -0,0 +1,320 @@
+/** @file
+Implementation of Usb Controller PPI.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Ppi/UsbController.h>
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/IoLib.h>
+
+#include "UsbPei.h"
+
+//
+// Globals
+//
+//
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gPeiUsbControllerPpiGuid,
+  NULL
+};
+
+UINTN mIohOhciPciReg[IOH_MAX_OHCI_USB_CONTROLLERS] = {
+  PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, 0)
+};
+
+UINTN mIohEhciPciReg[IOH_MAX_EHCI_USB_CONTROLLERS] = {
+  PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, 0),
+};
+
+/**
+  When EHCI get started in DXE, OHCI couldn't get the ownership
+  of roothub after warm reset because CF at EHCI hasn't been cleared.
+  We should clear that reg before UpdateBootMode. But Reg at EHCI is
+  memory-mapped, so need assume a range of space without conflict
+  in PCI memory space.
+
+  @param[in]  PeiServices     The pointer of EFI_PEI_SERVICES
+
+**/
+
+VOID
+SwitchConfigFlag (
+  IN EFI_PEI_SERVICES          **PeiServices
+  )
+{
+  UINT32             SavBaseAddr;
+  UINT32             UsbBaseAddr;
+  UINT16             SaveCmdData;
+  UINT8              EhciCapLen;
+  UINT8              Index;
+  UsbBaseAddr = 0;
+
+  for (Index = 0; Index < IOH_MAX_EHCI_USB_CONTROLLERS; Index++) {
+    UsbBaseAddr = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress);
+    //
+    // Manage EHCI on IOH, set UsbBaseAddr
+    //
+    SavBaseAddr = PciRead32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR);
+    PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, UsbBaseAddr);
+    //
+    // Save Cmd register
+    //
+    SaveCmdData = PciRead16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND);
+    //
+    // Enable EHCI on IOH
+    //
+    PciOr16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, B_IOH_USB_COMMAND_BME | B_IOH_USB_COMMAND_MSE );
+    //
+    // Clear CF register on EHCI
+    //
+    EhciCapLen = MmioRead8 (UsbBaseAddr + R_IOH_EHCI_CAPLENGTH);
+    MmioWrite32 (UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS, 0);
+
+    DEBUG ((EFI_D_INFO, "CF at EHCI = %x \n", UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS));
+    //
+    // Restore EHCI UsbBaseAddr in PCI space
+    //
+    PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, SavBaseAddr);
+    //
+    // Restore EHCI Command register in PCI space
+    //
+    PciWrite16(mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, SaveCmdData);
+  }
+}
+/**
+  Retrieved specified the USB controller information.
+
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.
+  @param  This                  This PEI_USB_CONTROLLER_PPI instance.
+  @param  UsbControllerId       Indicate which usb controller information will be retrieved.
+  @param  ControllerType        Indicate the controller is Ehci, Ohci, OHCI
+  @param  BaseAddress           Indicate the memory bar of the controller
+
+  @retval EFI_SUCCESS           The reset operation succeeded.
+  @retval EFI_INVALID_PARAMETER Attributes is not valid.
+
+**/
+
+EFI_STATUS
+GetOhciController (
+  IN EFI_PEI_SERVICES               **PeiServices,
+  IN PEI_USB_CONTROLLER_PPI         *This,
+  IN UINT8                          UsbControllerId,
+  IN UINTN                          *ControllerType,
+  IN UINTN                          *BaseAddress
+  )
+{
+  IOH_OHCI_DEVICE         *PeiIohOhciDev;
+
+  PeiIohOhciDev = IOH_OHCI_DEVICE_FROM_THIS (This);
+
+  if (UsbControllerId >= IOH_MAX_OHCI_USB_CONTROLLERS) {
+    return EFI_INVALID_PARAMETER;
+  }
+  *ControllerType = PEI_OHCI_CONTROLLER;
+  *BaseAddress = PeiIohOhciDev->MmioBase[UsbControllerId];
+
+  return EFI_SUCCESS;
+}
+/**
+  Retrieved specified the USB controller information.
+
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.
+  @param  This                  This PEI_USB_CONTROLLER_PPI instance.
+  @param  UsbControllerId       Indicate which usb controller information will be retrieved.
+  @param  ControllerType        Indicate the controller is Ehci, Ohci, OHCI
+  @param  BaseAddress           Indicate the memory bar of the controller
+
+  @retval EFI_SUCCESS           The reset operation succeeded.
+  @retval EFI_INVALID_PARAMETER Attributes is not valid.
+
+**/
+
+EFI_STATUS
+GetEhciController (
+  IN EFI_PEI_SERVICES               **PeiServices,
+  IN PEI_USB_CONTROLLER_PPI         *This,
+  IN UINT8                          UsbControllerId,
+  IN UINTN                          *ControllerType,
+  IN UINTN                          *BaseAddress
+  )
+{
+  IOH_EHCI_DEVICE         *PeiIohEhciDev;
+
+  PeiIohEhciDev = IOH_EHCI_DEVICE_FROM_THIS (This);
+
+  if (UsbControllerId >= IOH_MAX_EHCI_USB_CONTROLLERS) {
+    return EFI_INVALID_PARAMETER;
+  }
+  *ControllerType = PEI_EHCI_CONTROLLER;
+  *BaseAddress = PeiIohEhciDev->MmioBase[UsbControllerId];
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Retrieved specified the USB controller information.
+
+  @param  IohOhciPciReg         Ohci device address list.
+  @param  OhciCount             The count of the OHCI
+  @param  IohEhciPciReg         Ehci device address list.
+  @param  EhciCount             The count of the EHCI
+
+**/
+
+VOID
+EnableBusMaster (
+  IN UINTN IohOhciPciReg[],
+  IN UINT8 OhciCount,
+  IN UINTN IohEhciPciReg[],
+  IN UINT8 EhciCount
+  )
+{
+  UINT8  Index;
+  UINT16 CmdReg;
+  for (Index = 0; Index < OhciCount; Index ++) {
+    CmdReg = PciRead16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND);
+    CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );
+    PciWrite16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);
+  }
+  for (Index = 0; Index < EhciCount; Index ++) {
+    CmdReg = PciRead16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND);
+    CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );
+    PciWrite16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);
+  }
+}
+
+PEI_USB_CONTROLLER_PPI mUsbControllerPpi[2] = { {GetOhciController}, {GetEhciController}};
+
+/**
+  @param  FileHandle  Handle of the file being invoked.
+  @param  PeiServices Describes the list of possible PEI Services.
+
+  @retval EFI_SUCCESS            PPI successfully installed
+
+**/
+EFI_STATUS
+PeimInitializeIchUsb (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  EFI_STATUS              Status;
+  UINTN                   i;
+  EFI_PHYSICAL_ADDRESS    AllocateAddress;
+  IOH_OHCI_DEVICE         *PeiIohOhciDev;
+  IOH_EHCI_DEVICE         *PeiIohEhciDev;
+  UINT16                  CmdReg;
+
+  Status = PeiServicesAllocatePages (
+             EfiBootServicesCode,
+             1,
+             &AllocateAddress
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  EnableBusMaster (
+    mIohOhciPciReg,
+    IOH_MAX_OHCI_USB_CONTROLLERS,
+    mIohEhciPciReg,
+    IOH_MAX_EHCI_USB_CONTROLLERS
+    );
+
+  if (FeaturePcdGet (PcdEhciRecoveryEnabled)) {
+    DEBUG ((EFI_D_INFO, "UsbPei:EHCI is used for recovery\n"));
+    //
+    // EHCI recovery is enabled
+    //
+    PeiIohEhciDev = (IOH_EHCI_DEVICE *)((UINTN)AllocateAddress);
+    ZeroMem (PeiIohEhciDev, sizeof(IOH_EHCI_DEVICE));
+
+    PeiIohEhciDev->Signature            = PEI_IOH_EHCI_SIGNATURE;
+    CopyMem(&(PeiIohEhciDev->UsbControllerPpi), &mUsbControllerPpi[1], sizeof(PEI_USB_CONTROLLER_PPI));
+    CopyMem(&(PeiIohEhciDev->PpiList), &mPpiList, sizeof(mPpiList));
+    PeiIohEhciDev->PpiList.Ppi          = &PeiIohEhciDev->UsbControllerPpi;
+
+    //
+    // Assign resources and enable Ehci controllers
+    //
+    for (i = 0; i < IOH_MAX_EHCI_USB_CONTROLLERS; i++) {
+      DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth EHCI controller for recovery\n", i));
+      PeiIohEhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;
+      //
+      // Assign base address register, Enable Bus Master and Memory Io
+      //
+      PciWrite32 (mIohEhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohEhciDev->MmioBase[i]);
+      CmdReg = PciRead16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND);
+      CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );
+      PciWrite16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);
+    }
+    //
+    // Install USB Controller PPI
+    //
+    Status = (**PeiServices).InstallPpi (
+                               PeiServices,
+                               &PeiIohEhciDev->PpiList
+                               );
+
+    ASSERT_EFI_ERROR (Status);
+  } else {
+    DEBUG ((EFI_D_INFO, "UsbPei:OHCI is used for recovery\n"));
+    //
+    // OHCI recovery is enabled
+    //
+    SwitchConfigFlag ((EFI_PEI_SERVICES**)PeiServices);
+    PeiIohOhciDev = (IOH_OHCI_DEVICE *)((UINTN)AllocateAddress);
+    ZeroMem (PeiIohOhciDev, sizeof(IOH_OHCI_DEVICE));
+
+    PeiIohOhciDev->Signature            = PEI_IOH_OHCI_SIGNATURE;
+    CopyMem(&(PeiIohOhciDev->UsbControllerPpi), &mUsbControllerPpi[0], sizeof(PEI_USB_CONTROLLER_PPI));
+    CopyMem(&(PeiIohOhciDev->PpiList), &mPpiList, sizeof(mPpiList));
+    PeiIohOhciDev->PpiList.Ppi          = &PeiIohOhciDev->UsbControllerPpi;
+    //
+    // Assign resources and enable OHCI controllers
+    //
+    for (i = 0; i < IOH_MAX_OHCI_USB_CONTROLLERS; i++) {
+      DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth OHCI controller for recovery\n", i));
+      PeiIohOhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;
+      //
+      // Assign base address register, Enable Bus Master and Memory Io
+      //
+      PciWrite32 (mIohOhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohOhciDev->MmioBase[i]);
+
+      Status = PeiServicesAllocatePages (
+                 EfiBootServicesCode,
+                 1,
+                 &AllocateAddress
+                 );
+      ASSERT_EFI_ERROR (Status);
+      MmioWrite32(PeiIohOhciDev->MmioBase[i] + R_IOH_USB_OHCI_HCCABAR, (UINT32)AllocateAddress);
+
+      CmdReg = PciRead16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND);
+      CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );
+      PciWrite16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);
+    }
+    //
+    // Install USB Controller PPI
+    //
+    Status = (**PeiServices).InstallPpi (
+                               PeiServices,
+                               &PeiIohOhciDev->PpiList
+                               );
+
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return Status;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h
new file mode 100644
index 0000000000..c270fea46e
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h
@@ -0,0 +1,38 @@
+/** @file
+Define private data structure for UHCI and EHCI.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _USB_PEI_H
+#define _USB_PEI_H
+
+#include "Ioh.h"
+
+#define PEI_IOH_OHCI_SIGNATURE          SIGNATURE_32 ('O', 'H', 'C', 'I')
+#define PEI_IOH_EHCI_SIGNATURE          SIGNATURE_32 ('E', 'H', 'C', 'I')
+
+typedef struct {
+  UINTN                   Signature;
+  PEI_USB_CONTROLLER_PPI  UsbControllerPpi;
+  EFI_PEI_PPI_DESCRIPTOR  PpiList;
+  UINTN                   MmioBase[IOH_MAX_OHCI_USB_CONTROLLERS];
+} IOH_OHCI_DEVICE;
+
+typedef struct {
+  UINTN                   Signature;
+  PEI_USB_CONTROLLER_PPI  UsbControllerPpi;
+  EFI_PEI_PPI_DESCRIPTOR  PpiList;
+  UINTN                   MmioBase[IOH_MAX_EHCI_USB_CONTROLLERS];
+} IOH_EHCI_DEVICE;
+
+#define IOH_OHCI_DEVICE_FROM_THIS(a) \
+  CR(a, IOH_OHCI_DEVICE, UsbControllerPpi, PEI_IOH_OHCI_SIGNATURE)
+
+#define IOH_EHCI_DEVICE_FROM_THIS(a) \
+  CR (a, IOH_EHCI_DEVICE, UsbControllerPpi, PEI_IOH_EHCI_SIGNATURE)
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf
new file mode 100644
index 0000000000..ab57ff87d3
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf
@@ -0,0 +1,53 @@
+## @file
+# Component description file for UsbPei module.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = UsbPei
+  FILE_GUID                      = 73E6F6B4-D029-4e87-8405-6067C8BD02A6
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = PeimInitializeIchUsb
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  UsbPei.c
+  UsbPei.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  IoLib
+  PciLib
+  PcdLib
+  BaseMemoryLib
+  PeimEntryPoint
+  DebugLib
+
+[Ppis]
+  gPeiUsbControllerPpiGuid                      # PPI ALWAYS_PRODUCED
+
+[FeaturePcd]
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdEhciRecoveryEnabled
+
+[Pcd]
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiQNCUsbControllerMemoryBaseAddress
+  gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiP2PMemoryBaseAddress
+
+[Depex]
+  gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c
new file mode 100644
index 0000000000..3c2ba51ad4
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c
@@ -0,0 +1,219 @@
+/** @file
+UEFI Component Name and Name2 protocol for OHCI driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ohci.h"
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gOhciComponentName = {
+  OhciComponentNameGetDriverName,
+  OhciComponentNameGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) OhciComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) OhciComponentNameGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOhciDriverNameTable[] = {
+  { "eng;en", L"Usb Ohci Driver" },
+  { NULL, NULL }
+};
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 4646 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mOhciDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gOhciComponentName)
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 4646 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS           Status;
+  USB_OHCI_HC_DEV      *OhciDev;
+  EFI_USB_HC_PROTOCOL  *UsbHc;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Make sure this driver is currently managing ControllerHandle
+  //
+  Status = EfiTestManagedDevice (
+             ControllerHandle,
+             gOhciDriverBinding.DriverBindingHandle,
+             &gEfiPciIoProtocolGuid
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiUsbHcProtocolGuid,
+                  (VOID **) &UsbHc,
+                  gOhciDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  OhciDev = USB_OHCI_HC_DEV_FROM_THIS (UsbHc);
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           OhciDev->ControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gOhciComponentName)
+           );
+
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h
new file mode 100644
index 0000000000..c54cd6356c
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h
@@ -0,0 +1,141 @@
+/** @file
+This file contains the delarations for componet name routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 4646 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 4646 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  );
+
+#endif
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h
new file mode 100644
index 0000000000..14a619bb3f
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h
@@ -0,0 +1,132 @@
+/** @file
+This file contains the descriptor definination of OHCI spec
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#ifndef _DESCRIPTOR_H
+#define _DESCRIPTOR_H
+
+#define ED_FUNC_ADD     0x0001
+#define ED_ENDPT_NUM    0x0002
+#define ED_DIR          0x0004
+#define ED_SPEED        0x0008
+#define ED_SKIP         0x0010
+#define ED_FORMAT       0x0020
+#define ED_MAX_PACKET   0x0040
+#define ED_TDTAIL_PTR   0x0080
+#define ED_HALTED       0x0100
+#define ED_DTTOGGLE     0x0200
+#define ED_TDHEAD_PTR   0x0400
+#define ED_NEXT_EDPTR   0x0800
+#define ED_PDATA        0x1000
+#define ED_ZERO         0x2000
+
+#define TD_BUFFER_ROUND     0x0001
+#define TD_DIR_PID          0x0002
+#define TD_DELAY_INT        0x0004
+#define TD_DT_TOGGLE        0x0008
+#define TD_ERROR_CNT        0x0010
+#define TD_COND_CODE        0x0020
+#define TD_CURR_BUFFER_PTR  0x0040
+#define TD_NEXT_PTR         0x0080
+#define TD_BUFFER_END_PTR   0x0100
+#define TD_PDATA            0x0200
+
+#define ED_FROM_TD_DIR        0x0
+#define ED_OUT_DIR            0x1
+#define ED_IN_DIR             0x2
+#define ED_FROM_TD_ALSO_DIR   0x3
+
+#define TD_SETUP_PID          0x00
+#define TD_OUT_PID            0x01
+#define TD_IN_PID             0x02
+#define TD_NODATA_PID         0x03
+
+#define HI_SPEED              0
+#define LO_SPEED              1
+
+#define TD_NO_ERROR           0x00
+#define TD_CRC_ERROR          0x01
+#define TD_BITSTUFFING_ERROR  0x02
+#define TD_TOGGLE_ERROR       0x03
+#define TD_DEVICE_STALL       0x04
+#define TD_NO_RESPONSE        0x05
+#define TD_PIDCHK_FAIL        0x06
+#define TD_PID_UNEXPECTED     0x07
+#define TD_DATA_OVERRUN       0x08
+#define TD_DATA_UNDERRUN      0x09
+#define TD_BUFFER_OVERRUN     0x0C
+#define TD_BUFFER_UNDERRUN    0x0D
+#define TD_TOBE_PROCESSED     0x0E
+#define TD_TOBE_PROCESSED_2   0x0F
+
+#define TD_NO_DELAY           0x7
+
+#define TD_INT                0x1
+#define TD_CTL                0x2
+#define TD_BLK                0x3
+
+typedef struct {
+  UINT32 Reserved:18;
+  UINT32 BufferRounding:1;
+  UINT32 DirPID:2;
+  UINT32 DelayInterrupt:3;
+  UINT32 DataToggle:2;
+  UINT32 ErrorCount:2;
+  UINT32 ConditionCode:4;
+} TD_DESCRIPTOR_WORD0;
+
+typedef struct _TD_DESCRIPTOR {
+  TD_DESCRIPTOR_WORD0     Word0;
+  UINT32                  CurrBufferPointer;          // 32-bit Physical Address of buffer
+  UINT32                  NextTD;                     // 32-bit Physical Address of TD_DESCRIPTOR
+  UINT32                  BufferEndPointer;           // 32-bit Physical Address of buffer
+  UINT32                  NextTDPointer;              // 32-bit Physical Address of TD_DESCRIPTOR
+  UINT32                  DataBuffer;                 // 32-bit Physical Address of buffer
+  UINT32                  ActualSendLength;
+  UINT32                  Reserved;
+} TD_DESCRIPTOR;
+
+typedef struct {
+  UINT32 FunctionAddress:7;
+  UINT32 EndPointNum:4;
+  UINT32 Direction:2;
+  UINT32 Speed:1;
+  UINT32 Skip:1;
+  UINT32 Format:1;
+  UINT32 MaxPacketSize:11;
+  UINT32 FreeSpace:5;
+} ED_DESCRIPTOR_WORD0;
+
+typedef struct {
+  UINT32 Halted:1;
+  UINT32 ToggleCarry:1;
+  UINT32 Zero:2;
+  UINT32 TdHeadPointer:28;
+} ED_DESCRIPTOR_WORD2;
+
+typedef struct _ED_DESCRIPTOR {
+  ED_DESCRIPTOR_WORD0     Word0;
+  UINT32                  TdTailPointer;    // 32-bit Physical Address of TD_DESCRIPTOR
+  ED_DESCRIPTOR_WORD2     Word2;
+  UINT32                  NextED;           // 32-bit Physical Address of ED_DESCRIPTOR
+} ED_DESCRIPTOR;
+
+#define TD_PTR(p)            ((TD_DESCRIPTOR *)(UINTN)((p) << 4))
+#define ED_PTR(p)            ((ED_DESCRIPTOR *)(UINTN)((p) << 4))
+#define RIGHT_SHIFT_4(p)     ((UINT32)(p) >> 4)
+
+typedef enum {
+  CONTROL_LIST,
+  BULK_LIST,
+  INTERRUPT_LIST,
+  ISOCHRONOUS_LIST
+} DESCRIPTOR_LIST_TYPE;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c
new file mode 100644
index 0000000000..dbff8f1fcb
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c
@@ -0,0 +1,2473 @@
+/** @file
+This file contains the implementation of Usb Hc Protocol.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ohci.h"
+
+/**
+  Provides software reset for the USB host controller.
+
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.
+  @param  Attributes            A bit mask of the reset operation to perform.
+
+  @retval EFI_SUCCESS           The reset operation succeeded.
+  @retval EFI_INVALID_PARAMETER Attributes is not valid.
+  @retval EFI_UNSUPPOURTED      The type of reset specified by Attributes is
+                                not currently supported by the host controller.
+  @retval EFI_DEVICE_ERROR      Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciReset (
+  IN EFI_USB_HC_PROTOCOL  *This,
+  IN UINT16               Attributes
+  )
+{
+  EFI_STATUS              Status;
+  USB_OHCI_HC_DEV         *Ohc;
+  UINT8                   Index;
+  UINT8                   NumOfPorts;
+  UINT32                  PowerOnGoodTime;
+  UINT32                  Data32;
+  BOOLEAN                 Flag = FALSE;
+
+  if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = EFI_SUCCESS;
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+  if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {
+    gBS->Stall (50 * 1000);
+    Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+    gBS->Stall (50 * 1000);
+    //
+    // Wait for host controller reset.
+    //
+    PowerOnGoodTime = 50;
+    do {
+      gBS->Stall (1 * 1000);
+      Data32 = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS );
+      if (EFI_ERROR (Status)) {
+        return EFI_DEVICE_ERROR;
+      }
+      if ((Data32 & HC_RESET) == 0) {
+        Flag = TRUE;
+        break;
+      }
+    }while(PowerOnGoodTime--);
+    if (!Flag){
+      return EFI_DEVICE_ERROR;
+    }
+  }
+  OhciFreeIntTransferMemory (Ohc);
+  Status = OhciInitializeInterruptList (Ohc);
+  OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);
+  if ((Attributes &  EFI_USB_HC_RESET_GLOBAL) != 0) {
+    Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+    gBS->Stall (50 * 1000);
+  }
+  //
+  // Initialize host controller operational registers
+  //
+  OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778);
+  OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);
+  OhciSetPeriodicStart (Ohc, 0x2a2f);
+  OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x3);
+  OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0);
+  OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0);
+  OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1);
+  //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);
+  //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);
+
+  OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0);
+  OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff);
+  OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE);
+  OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER);
+  OhciGetRootHubNumOfPorts (This, &NumOfPorts);
+  for (Index = 0; Index < NumOfPorts; Index++) {
+    if (!EFI_ERROR (OhciSetRootHubPortFeature (This, Index, EfiUsbPortReset))) {
+      gBS->Stall (200 * 1000);
+      OhciClearRootHubPortFeature (This, Index, EfiUsbPortReset);
+      gBS->Stall (1000);
+      OhciSetRootHubPortFeature (This, Index, EfiUsbPortEnable);
+      gBS->Stall (1000);
+    }
+  }
+  OhciSetMemoryPointer (Ohc, HC_HCCA, Ohc->HccaMemoryBlock);
+  OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+  OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+  OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | BULK_ENABLE, 1); /*ISOCHRONOUS_ENABLE*/
+  OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);
+  gBS->Stall (50*1000);
+  //
+  // Wait till first SOF occurs, and then clear it
+  //
+  while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0);
+  OhciClearInterruptStatus (Ohc, START_OF_FRAME);
+  gBS->Stall (1000);
+
+  return Status;
+}
+
+/**
+  Retrieve the current state of the USB host controller.
+
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.
+  @param  State                 Variable to return the current host controller
+                                state.
+
+  @retval EFI_SUCCESS           Host controller state was returned in State.
+  @retval EFI_INVALID_PARAMETER State is NULL.
+  @retval EFI_DEVICE_ERROR      An error was encountered while attempting to
+                                retrieve the host controller's current state.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetState (
+  IN  EFI_USB_HC_PROTOCOL  *This,
+  OUT EFI_USB_HC_STATE     *State
+  )
+{
+  USB_OHCI_HC_DEV         *Ohc;
+  UINT32                  FuncState;
+
+  if (State == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+  FuncState = OhciGetHcControl (Ohc, HC_FUNCTIONAL_STATE);
+
+  switch (FuncState) {
+    case HC_STATE_RESET:
+    case HC_STATE_RESUME:
+      *State = EfiUsbHcStateHalt;
+      break;
+
+    case HC_STATE_OPERATIONAL:
+      *State = EfiUsbHcStateOperational;
+      break;
+
+    case HC_STATE_SUSPEND:
+      *State = EfiUsbHcStateSuspend;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Sets the USB host controller to a specific state.
+
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.
+  @param  State                 The state of the host controller that will be set.
+
+  @retval EFI_SUCCESS           The USB host controller was successfully placed
+                                in the state specified by State.
+  @retval EFI_INVALID_PARAMETER State is invalid.
+  @retval EFI_DEVICE_ERROR      Failed to set the state due to device error.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciSetState(
+  IN EFI_USB_HC_PROTOCOL  *This,
+  IN EFI_USB_HC_STATE     State
+  )
+{
+  EFI_STATUS              Status;
+  USB_OHCI_HC_DEV         *Ohc;
+
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);
+
+  switch (State) {
+    case EfiUsbHcStateHalt:
+      Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);
+      break;
+
+    case EfiUsbHcStateOperational:
+      Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);
+      break;
+
+    case EfiUsbHcStateSuspend:
+      Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_SUSPEND);
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+  }
+
+  gBS->Stall (1000);
+
+  return Status;
+}
+
+/**
+
+  Submits control transfer to a target USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  IsSlowDevice          Indicates whether the target device is slow device
+                                or full-speed device.
+  @param  MaxPaketLength        Indicates the maximum packet size that the
+                                default control transfer endpoint is capable of
+                                sending or receiving.
+  @param  Request               A pointer to the USB device request that will be sent
+                                to the USB device.
+  @param  TransferDirection     Specifies the data direction for the transfer.
+                                There are three values available, DataIn, DataOut
+                                and NoData.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  DataLength            Indicates the size, in bytes, of the data buffer
+                                specified by Data.
+  @param  TimeOut               Indicates the maximum time, in microseconds,
+                                which the transfer is allowed to complete.
+  @param  TransferResult        A pointer to the detailed result information generated
+                                by this control transfer.
+
+  @retval EFI_SUCCESS           The control transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The control transfer could not be completed due to a lack of resources.
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+  @retval EFI_TIMEOUT           The control transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR      The control transfer failed due to host controller or device error.
+                                Caller should check TranferResult for detailed error information.
+
+--*/
+
+
+EFI_STATUS
+EFIAPI
+OhciControlTransfer (
+  IN     EFI_USB_HC_PROTOCOL     *This,
+  IN     UINT8                   DeviceAddress,
+  IN     BOOLEAN                 IsSlowDevice,
+  IN     UINT8                   MaxPacketLength,
+  IN     EFI_USB_DEVICE_REQUEST  *Request,
+  IN     EFI_USB_DATA_DIRECTION  TransferDirection,
+  IN OUT VOID                    *Data                 OPTIONAL,
+  IN OUT UINTN                   *DataLength           OPTIONAL,
+  IN     UINTN                   TimeOut,
+  OUT    UINT32                  *TransferResult
+  )
+{
+  USB_OHCI_HC_DEV                *Ohc;
+  ED_DESCRIPTOR                  *HeadEd;
+  ED_DESCRIPTOR                  *Ed;
+  TD_DESCRIPTOR                  *HeadTd;
+  TD_DESCRIPTOR                  *SetupTd;
+  TD_DESCRIPTOR                  *DataTd;
+  TD_DESCRIPTOR                  *StatusTd;
+  TD_DESCRIPTOR                  *EmptyTd;
+  EFI_STATUS                     Status;
+  UINT32                         DataPidDir;
+  UINT32                         StatusPidDir;
+  UINTN                          TimeCount;
+  OHCI_ED_RESULT                 EdResult;
+
+  EFI_PCI_IO_PROTOCOL_OPERATION  MapOp;
+
+  UINTN                          ActualSendLength;
+  UINTN                          LeftLength;
+  UINT8                          DataToggle;
+
+  VOID                           *ReqMapping = NULL;
+  UINTN                          ReqMapLength = 0;
+  EFI_PHYSICAL_ADDRESS           ReqMapPhyAddr = 0;
+
+  VOID                           *DataMapping = NULL;
+  UINTN                          DataMapLength = 0;
+  EFI_PHYSICAL_ADDRESS           DataMapPhyAddr = 0;
+
+  HeadTd = NULL;
+  DataTd = NULL;
+
+  if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn &&
+       TransferDirection != EfiUsbNoData) ||
+      Request == NULL || DataLength == NULL || TransferResult == NULL ||
+      (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) ||
+      (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) ||
+      (IsSlowDevice && MaxPacketLength != 8) ||
+      (MaxPacketLength != 8 && MaxPacketLength != 16 &&
+       MaxPacketLength != 32 && MaxPacketLength != 64)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (*DataLength > MAX_BYTES_PER_TD) {
+    DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\r\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);
+
+  if (TransferDirection == EfiUsbDataIn) {
+    DataPidDir = TD_IN_PID;
+    StatusPidDir = TD_OUT_PID;
+  } else {
+    DataPidDir = TD_OUT_PID;
+    StatusPidDir = TD_IN_PID;
+  }
+
+  Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);
+  if (EFI_ERROR(Status)) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n"));
+    *TransferResult = EFI_USB_ERR_SYSTEM;
+    return EFI_DEVICE_ERROR;
+  }
+  Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 0);
+  if (EFI_ERROR(Status)) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n"));
+    *TransferResult = EFI_USB_ERR_SYSTEM;
+    return EFI_DEVICE_ERROR;
+  }
+  gBS->Stall(20 * 1000);
+
+  OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+  Ed = OhciCreateED (Ohc);
+  if (Ed == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\r\n"));
+    goto CTRL_EXIT;
+  }
+  OhciSetEDField (Ed, ED_SKIP, 1);
+  OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+  OhciSetEDField (Ed, ED_ENDPT_NUM, 0);
+  OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+  OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);
+  OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);
+  OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+  OhciSetEDField (Ed, ED_PDATA, 0);
+  OhciSetEDField (Ed, ED_ZERO, 0);
+  OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);
+  OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);
+  OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);
+  HeadEd = OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL);
+  //
+  // Setup Stage
+  //
+  if(Request != NULL) {
+    ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST);
+    MapOp = EfiPciIoOperationBusMasterRead;
+    Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Request, &ReqMapLength, &ReqMapPhyAddr, &ReqMapping);
+    if (EFI_ERROR(Status)) {
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to Map Request Buffer\r\n"));
+      goto FREE_ED_BUFF;
+    }
+  }
+  SetupTd = OhciCreateTD (Ohc);
+  if (SetupTd == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n"));
+    goto UNMAP_SETUP_BUFF;
+  }
+  HeadTd = SetupTd;
+  OhciSetTDField (SetupTd, TD_PDATA, 0);
+  OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1);
+  OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID);
+  OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY);
+  OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2);
+  OhciSetTDField (SetupTd, TD_ERROR_CNT, 0);
+  OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+  OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINT32)ReqMapPhyAddr);
+  OhciSetTDField (SetupTd, TD_NEXT_PTR, 0);
+  OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINT32)(ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1));
+  SetupTd->ActualSendLength = sizeof (EFI_USB_DEVICE_REQUEST);
+  SetupTd->DataBuffer = (UINT32)ReqMapPhyAddr;
+  SetupTd->NextTDPointer = 0;
+
+  if (TransferDirection == EfiUsbDataIn) {
+    MapOp = EfiPciIoOperationBusMasterWrite;
+  } else {
+    MapOp = EfiPciIoOperationBusMasterRead;
+  }
+  DataMapLength = *DataLength;
+  if ((Data != NULL) && (DataMapLength != 0)) {
+    Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, Data, &DataMapLength, &DataMapPhyAddr, &DataMapping);
+    if (EFI_ERROR(Status)) {
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail To Map Data Buffer\r\n"));
+      goto FREE_TD_BUFF;
+    }
+  }
+  //
+  //Data Stage
+  //
+  LeftLength = DataMapLength;
+  ActualSendLength = DataMapLength;
+  DataToggle = 1;
+  while (LeftLength > 0) {
+    ActualSendLength = LeftLength;
+    if (LeftLength > MaxPacketLength) {
+      ActualSendLength = MaxPacketLength;
+    }
+    DataTd = OhciCreateTD (Ohc);
+    if (DataTd == NULL) {
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto UNMAP_DATA_BUFF;
+    }
+    OhciSetTDField (DataTd, TD_PDATA, 0);
+    OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+    OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+    OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+    OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle);
+    OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+    OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+    OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr);
+    OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(DataMapPhyAddr + ActualSendLength - 1));
+    OhciSetTDField (DataTd, TD_NEXT_PTR, 0);
+    DataTd->ActualSendLength = (UINT32)ActualSendLength;
+    DataTd->DataBuffer = (UINT32)DataMapPhyAddr;
+    DataTd->NextTDPointer = 0;
+    OhciLinkTD (HeadTd, DataTd);
+    DataToggle ^= 1;
+    DataMapPhyAddr += ActualSendLength;
+    LeftLength -= ActualSendLength;
+  }
+  //
+  // Status Stage
+  //
+  StatusTd = OhciCreateTD (Ohc);
+  if (StatusTd == NULL) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto UNMAP_DATA_BUFF;
+  }
+  OhciSetTDField (StatusTd, TD_PDATA, 0);
+  OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1);
+  OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir);
+  OhciSetTDField (StatusTd, TD_DELAY_INT, 7);
+  OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3);
+  OhciSetTDField (StatusTd, TD_ERROR_CNT, 0);
+  OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+  OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, 0);
+  OhciSetTDField (StatusTd, TD_NEXT_PTR, 0);
+  OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, 0);
+  StatusTd->ActualSendLength = 0;
+  StatusTd->DataBuffer = 0;
+  StatusTd->NextTDPointer = 0;
+  OhciLinkTD (HeadTd, StatusTd);
+  //
+  // Empty Stage
+  //
+  EmptyTd = OhciCreateTD (Ohc);
+  if (EmptyTd == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto UNMAP_DATA_BUFF;
+  }
+  OhciSetTDField (EmptyTd, TD_PDATA, 0);
+  OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);
+  OhciSetTDField (EmptyTd, TD_DIR_PID, 0);
+  OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);
+  //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
+  EmptyTd->Word0.DataToggle = 0;
+  OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);
+  OhciSetTDField (EmptyTd, TD_COND_CODE, 0);
+  OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);
+  OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);
+  OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);
+  EmptyTd->ActualSendLength = 0;
+  EmptyTd->DataBuffer = 0;
+  EmptyTd->NextTDPointer = 0;
+  OhciLinkTD (HeadTd, EmptyTd);
+  Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;
+  OhciAttachTDListToED (Ed, HeadTd);
+  //
+  // For debugging,  dump ED & TD buffer befor transferring
+  //
+  //
+  //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE);
+  //
+  OhciSetEDField (Ed, ED_SKIP, 0);
+  Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 1);
+  if (EFI_ERROR(Status)) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n"));
+    *TransferResult = EFI_USB_ERR_SYSTEM;
+    Status = EFI_DEVICE_ERROR;
+    goto UNMAP_DATA_BUFF;
+  }
+  Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1);
+  if (EFI_ERROR(Status)) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n"));
+    *TransferResult = EFI_USB_ERR_SYSTEM;
+    Status = EFI_DEVICE_ERROR;
+    goto UNMAP_DATA_BUFF;
+  }
+  gBS->Stall(20 * 1000);
+
+
+  TimeCount = 0;
+  Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);
+
+  while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {
+    gBS->Stall (1000);
+    TimeCount++;
+    Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);
+  }
+  //
+  // For debugging, dump ED & TD buffer after transferring
+  //
+  //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE);
+  //
+  *TransferResult = ConvertErrorCode (EdResult.ErrorCode);
+
+  if (EdResult.ErrorCode != TD_NO_ERROR) {
+    if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {
+      DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut));
+    } else {
+      DEBUG ((EFI_D_INFO, "Control pipe broken\r\n"));
+    }
+    *DataLength = 0;
+  } else {
+    DEBUG ((EFI_D_INFO, "Control transfer successed\r\n"));
+  }
+
+UNMAP_DATA_BUFF:
+  OhciSetEDField (Ed, ED_SKIP, 1);
+  if (HeadEd == Ed) {
+    OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+  } else {
+    HeadEd->NextED = Ed->NextED;
+  }
+  if(DataMapping != NULL) {
+    Ohc->PciIo->Unmap(Ohc->PciIo, DataMapping);
+  }
+
+FREE_TD_BUFF:
+  while (HeadTd) {
+    DataTd = HeadTd;
+    HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);
+    UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+  }
+
+UNMAP_SETUP_BUFF:
+  if(ReqMapping != NULL) {
+    Ohc->PciIo->Unmap(Ohc->PciIo, ReqMapping);
+  }
+
+FREE_ED_BUFF:
+  UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+CTRL_EXIT:
+  return Status;
+}
+
+/**
+
+  Submits bulk transfer to a bulk endpoint of a USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       The combination of an endpoint number and an
+                                endpoint direction of the target USB device.
+                                Each endpoint address supports data transfer in
+                                one direction except the control endpoint
+                                (whose default endpoint address is 0).
+                                It is the caller's responsibility to make sure that
+                                the EndPointAddress represents a bulk endpoint.
+  @param  MaximumPacketLength   Indicates the maximum packet size the target endpoint
+                                is capable of sending or receiving.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  DataLength            When input, indicates the size, in bytes, of the data buffer
+                                specified by Data. When output, indicates the actually
+                                transferred data size.
+  @param  DataToggle            A pointer to the data toggle value. On input, it indicates
+                                the initial data toggle value the bulk transfer should adopt;
+                                on output, it is updated to indicate the data toggle value
+                                of the subsequent bulk transfer.
+  @param  TimeOut               Indicates the maximum time, in microseconds, which the
+                                transfer is allowed to complete.
+  TransferResult                A pointer to the detailed result information of the
+                                bulk transfer.
+
+  @retval EFI_SUCCESS           The bulk transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The bulk transfer could not be submitted due to lack of resource.
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+  @retval EFI_TIMEOUT           The bulk transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR      The bulk transfer failed due to host controller or device error.
+                                Caller should check TranferResult for detailed error information.
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciBulkTransfer(
+  IN     EFI_USB_HC_PROTOCOL  *This,
+  IN     UINT8                DeviceAddress,
+  IN     UINT8                EndPointAddress,
+  IN     UINT8                MaxPacketLength,
+  IN OUT VOID                 *Data,
+  IN OUT UINTN                *DataLength,
+  IN OUT UINT8                *DataToggle,
+  IN     UINTN                TimeOut,
+  OUT    UINT32               *TransferResult
+  )
+{
+  USB_OHCI_HC_DEV                *Ohc;
+  ED_DESCRIPTOR                  *HeadEd;
+  ED_DESCRIPTOR                  *Ed;
+  UINT32                         DataPidDir;
+  TD_DESCRIPTOR                  *HeadTd;
+  TD_DESCRIPTOR                  *DataTd;
+  TD_DESCRIPTOR                  *EmptyTd;
+  EFI_STATUS                     Status;
+  UINT8                          EndPointNum;
+  UINTN                          TimeCount;
+  OHCI_ED_RESULT                 EdResult;
+
+  EFI_PCI_IO_PROTOCOL_OPERATION  MapOp;
+  VOID                           *Mapping;
+  UINTN                          MapLength;
+  EFI_PHYSICAL_ADDRESS           MapPyhAddr;
+  UINTN                          LeftLength;
+  UINTN                          ActualSendLength;
+  BOOLEAN                        FirstTD;
+
+  Mapping = NULL;
+  MapLength = 0;
+  MapPyhAddr = 0;
+  LeftLength = 0;
+  Status = EFI_SUCCESS;
+
+  if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||
+      *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||
+      (MaxPacketLength != 8 && MaxPacketLength != 16 &&
+       MaxPacketLength != 32 && MaxPacketLength != 64)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+  if ((EndPointAddress & 0x80) != 0) {
+    DataPidDir = TD_IN_PID;
+    MapOp = EfiPciIoOperationBusMasterWrite;
+  } else {
+    DataPidDir = TD_OUT_PID;
+    MapOp = EfiPciIoOperationBusMasterRead;
+  }
+
+  EndPointNum = (EndPointAddress & 0xF);
+  EdResult.NextToggle = *DataToggle;
+
+  Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0);
+  if (EFI_ERROR(Status)) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n"));
+    *TransferResult = EFI_USB_ERR_SYSTEM;
+    return EFI_DEVICE_ERROR;
+  }
+  Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0);
+  if (EFI_ERROR(Status)) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n"));
+    *TransferResult = EFI_USB_ERR_SYSTEM;
+    return EFI_DEVICE_ERROR;
+  }
+  gBS->Stall(20 * 1000);
+
+  OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+
+  Ed = OhciCreateED (Ohc);
+  if (Ed == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  OhciSetEDField (Ed, ED_SKIP, 1);
+  OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+  OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);
+  OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+  OhciSetEDField (Ed, ED_SPEED, HI_SPEED);
+  OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);
+  OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+  OhciSetEDField (Ed, ED_PDATA, 0);
+  OhciSetEDField (Ed, ED_ZERO, 0);
+  OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);
+  OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);
+  OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);
+  HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);
+
+  if(Data != NULL) {
+    MapLength = *DataLength;
+    Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping);
+    if (EFI_ERROR(Status)) {
+      DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n"));
+      goto FREE_ED_BUFF;
+    }
+  }
+  //
+  //Data Stage
+  //
+  LeftLength = MapLength;
+  ActualSendLength = MapLength;
+  HeadTd = NULL;
+  FirstTD = TRUE;
+  while (LeftLength > 0) {
+    ActualSendLength = LeftLength;
+    if (LeftLength > MaxPacketLength) {
+      ActualSendLength = MaxPacketLength;
+    }
+    DataTd = OhciCreateTD (Ohc);
+    if (DataTd == NULL) {
+      DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto FREE_OHCI_TDBUFF;
+    }
+    OhciSetTDField (DataTd, TD_PDATA, 0);
+    OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+    OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+    OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+    OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);
+    OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+    OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+    OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);
+    OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));
+    OhciSetTDField (DataTd, TD_NEXT_PTR, 0);
+    DataTd->ActualSendLength = (UINT32)ActualSendLength;
+    DataTd->DataBuffer = (UINT32)MapPyhAddr;
+    DataTd->NextTDPointer = 0;
+    if (FirstTD) {
+      HeadTd = DataTd;
+      FirstTD = FALSE;
+    } else {
+      OhciLinkTD (HeadTd, DataTd);
+    }
+    *DataToggle ^= 1;
+    MapPyhAddr += ActualSendLength;
+    LeftLength -= ActualSendLength;
+  }
+  //
+  // Empty Stage
+  //
+  EmptyTd = OhciCreateTD (Ohc);
+  if (EmptyTd == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n"));
+    goto FREE_OHCI_TDBUFF;
+  }
+  OhciSetTDField (EmptyTd, TD_PDATA, 0);
+  OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);
+  OhciSetTDField (EmptyTd, TD_DIR_PID, 0);
+  OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);
+  //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
+  EmptyTd->Word0.DataToggle = 0;
+  OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);
+  OhciSetTDField (EmptyTd, TD_COND_CODE, 0);
+  OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);
+  OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);
+  OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);
+  EmptyTd->ActualSendLength = 0;
+  EmptyTd->DataBuffer = 0;
+  EmptyTd->NextTDPointer = 0;
+  OhciLinkTD (HeadTd, EmptyTd);
+  Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;
+  OhciAttachTDListToED (Ed, HeadTd);
+
+  OhciSetEDField (Ed, ED_SKIP, 0);
+  Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);
+  if (EFI_ERROR(Status)) {
+    *TransferResult = EFI_USB_ERR_SYSTEM;
+    Status = EFI_DEVICE_ERROR;
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n"));
+    goto FREE_OHCI_TDBUFF;
+  }
+  Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1);
+  if (EFI_ERROR(Status)) {
+    *TransferResult = EFI_USB_ERR_SYSTEM;
+    Status = EFI_DEVICE_ERROR;
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n"));
+    goto FREE_OHCI_TDBUFF;
+  }
+  gBS->Stall(20 * 1000);
+
+  TimeCount = 0;
+  Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);
+  while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {
+    gBS->Stall (1000);
+    TimeCount++;
+    Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);
+  }
+
+  *TransferResult = ConvertErrorCode (EdResult.ErrorCode);
+
+  if (EdResult.ErrorCode != TD_NO_ERROR) {
+    if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {
+      DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));
+    } else {
+      DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));
+      *DataToggle = EdResult.NextToggle;
+    }
+    *DataLength = 0;
+  } else {
+    DEBUG ((EFI_D_INFO, "Bulk transfer successed\r\n"));
+  }
+  //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);
+
+FREE_OHCI_TDBUFF:
+  OhciSetEDField (Ed, ED_SKIP, 1);
+  if (HeadEd == Ed) {
+    OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+  }else {
+    HeadEd->NextED = Ed->NextED;
+  }
+  while (HeadTd) {
+    DataTd = HeadTd;
+    HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);
+    UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+  }
+
+  if(Mapping != NULL) {
+    Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);
+  }
+
+FREE_ED_BUFF:
+  UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+  return Status;
+}
+/**
+
+  Submits an interrupt transfer to an interrupt endpoint of a USB device.
+
+  @param  Ohc                   Device private data
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       The combination of an endpoint number and an endpoint
+                                direction of the target USB device. Each endpoint address
+                                supports data transfer in one direction except the
+                                control endpoint (whose default endpoint address is 0).
+                                It is the caller's responsibility to make sure that
+                                the EndPointAddress represents an interrupt endpoint.
+  @param  IsSlowDevice          Indicates whether the target device is slow device
+                                or full-speed device.
+  @param  MaxPacketLength       Indicates the maximum packet size the target endpoint
+                                is capable of sending or receiving.
+  @param  IsNewTransfer         If TRUE, an asynchronous interrupt pipe is built between
+                                the host and the target interrupt endpoint.
+                                If FALSE, the specified asynchronous interrupt pipe
+                                is canceled.
+  @param  DataToggle            A pointer to the data toggle value.  On input, it is valid
+                                when IsNewTransfer is TRUE, and it indicates the initial
+                                data toggle value the asynchronous interrupt transfer
+                                should adopt.
+                                On output, it is valid when IsNewTransfer is FALSE,
+                                and it is updated to indicate the data toggle value of
+                                the subsequent asynchronous interrupt transfer.
+  @param  PollingInterval       Indicates the interval, in milliseconds, that the
+                                asynchronous interrupt transfer is polled.
+                                This parameter is required when IsNewTransfer is TRUE.
+  @param  UCBuffer              Uncacheable buffer
+  @param  DataLength            Indicates the length of data to be received at the
+                                rate specified by PollingInterval from the target
+                                asynchronous interrupt endpoint.  This parameter
+                                is only required when IsNewTransfer is TRUE.
+  @param  CallBackFunction      The Callback function.This function is called at the
+                                rate specified by PollingInterval.This parameter is
+                                only required when IsNewTransfer is TRUE.
+  @param  Context               The context that is passed to the CallBackFunction.
+                                This is an optional parameter and may be NULL.
+  @param  IsPeriodic            Periodic interrupt or not
+  @param  OutputED              The correspoding ED carried out
+  @param  OutputTD              The correspoding TD carried out
+
+
+  @retval EFI_SUCCESS           The asynchronous interrupt transfer request has been successfully
+                                submitted or canceled.
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+
+**/
+
+EFI_STATUS
+OhciInterruptTransfer (
+  IN     USB_OHCI_HC_DEV                  *Ohc,
+  IN     UINT8                            DeviceAddress,
+  IN     UINT8                            EndPointAddress,
+  IN     BOOLEAN                          IsSlowDevice,
+  IN     UINT8                            MaxPacketLength,
+  IN     BOOLEAN                          IsNewTransfer,
+  IN OUT UINT8                            *DataToggle        OPTIONAL,
+  IN     UINTN                            PollingInterval    OPTIONAL,
+  IN     VOID                             *UCBuffer          OPTIONAL,
+  IN     UINTN                            DataLength         OPTIONAL,
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK  CallBackFunction   OPTIONAL,
+  IN     VOID                             *Context           OPTIONAL,
+  IN     BOOLEAN                          IsPeriodic         OPTIONAL,
+  OUT    ED_DESCRIPTOR                    **OutputED         OPTIONAL,
+  OUT    TD_DESCRIPTOR                    **OutputTD         OPTIONAL
+  )
+{
+  ED_DESCRIPTOR            *Ed;
+  UINT8                    EdDir;
+  ED_DESCRIPTOR            *HeadEd;
+  TD_DESCRIPTOR            *HeadTd;
+  TD_DESCRIPTOR            *DataTd;
+  TD_DESCRIPTOR            *EmptTd;
+  UINTN                    Depth;
+  UINTN                    Index;
+  EFI_STATUS               Status;
+  UINT8                    EndPointNum;
+  UINT32                   DataPidDir;
+  INTERRUPT_CONTEXT_ENTRY  *Entry;
+  EFI_TPL                  OldTpl;
+  BOOLEAN                  FirstTD;
+
+ VOID                      *Mapping;
+ UINTN                     MapLength;
+ EFI_PHYSICAL_ADDRESS      MapPyhAddr;
+ UINTN                     LeftLength;
+ UINTN                     ActualSendLength;
+
+
+  if (DataLength > MAX_BYTES_PER_TD) {
+    DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Error param\r\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((EndPointAddress & 0x80) != 0) {
+    EdDir = ED_IN_DIR;
+    DataPidDir = TD_IN_PID;
+  } else {
+    EdDir = ED_OUT_DIR;
+    DataPidDir = TD_OUT_PID;
+  }
+
+  EndPointNum = (EndPointAddress & 0xF);
+
+  if (!IsNewTransfer) {
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+    OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0);
+    OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle);
+    Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum);
+    OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);
+    gBS->RestoreTPL (OldTpl);
+    return Status;
+  }
+  MapLength = DataLength;
+  Status = Ohc->PciIo->Map(
+                         Ohc->PciIo,
+                         EfiPciIoOperationBusMasterWrite,
+                         UCBuffer,
+                         &MapLength,
+                         &MapPyhAddr,
+                         &Mapping
+                         );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n"));
+    goto EXIT;
+  }
+  Depth = 5;
+  Index = 1;
+  while (PollingInterval >= Index * 2 && Depth > 0) {
+    Index *= 2;
+    Depth--;
+  }
+  //
+  //ED Stage
+  //
+  HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth);
+  if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) {
+    OhciSetEDField (Ed, ED_SKIP, 1);
+  } else {
+    Ed = OhciCreateED (Ohc);
+    if (Ed == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n"));
+      goto UNMAP_OHCI_XBUFF;
+    }
+    OhciSetEDField (Ed, ED_SKIP, 1);
+    OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+    OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);
+    OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+    OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);
+    OhciSetEDField (Ed, ED_FORMAT, 0);
+    OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+    OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0);
+    OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);
+    OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);
+    OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);
+    OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd);
+  }
+  //
+  //Data Stage
+  //
+  LeftLength = MapLength;
+  ActualSendLength = MapLength;
+  HeadTd = NULL;
+  FirstTD = TRUE;
+  while (LeftLength > 0) {
+    ActualSendLength = LeftLength;
+    if (LeftLength > MaxPacketLength) {
+      ActualSendLength = MaxPacketLength;
+    }
+    DataTd = OhciCreateTD (Ohc);
+    if (DataTd == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
+      goto FREE_OHCI_TDBUFF;
+    }
+    OhciSetTDField (DataTd, TD_PDATA, 0);
+    OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+    OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+    OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+    OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);
+    OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+    OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+    OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);
+    OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));
+    OhciSetTDField (DataTd, TD_NEXT_PTR, 0);
+    DataTd->ActualSendLength = (UINT32)ActualSendLength;
+    DataTd->DataBuffer = (UINT32)MapPyhAddr;
+    DataTd->NextTDPointer = 0;
+    if (FirstTD) {
+      HeadTd = DataTd;
+      FirstTD = FALSE;
+    } else {
+      OhciLinkTD (HeadTd, DataTd);
+    }
+    *DataToggle ^= 1;
+    MapPyhAddr += ActualSendLength;
+    LeftLength -= ActualSendLength;
+  }
+
+  EmptTd = OhciCreateTD (Ohc);
+  if (EmptTd == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n"));
+    goto FREE_OHCI_TDBUFF;
+  }
+  OhciSetTDField (EmptTd, TD_PDATA, 0);
+  OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0);
+  OhciSetTDField (EmptTd, TD_DIR_PID, 0);
+  OhciSetTDField (EmptTd, TD_DELAY_INT, 0);
+  //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle);
+  EmptTd->Word0.DataToggle = 0;
+  OhciSetTDField (EmptTd, TD_ERROR_CNT, 0);
+  OhciSetTDField (EmptTd, TD_COND_CODE, 0);
+  OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0);
+  OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0);
+  OhciSetTDField (EmptTd, TD_NEXT_PTR, 0);
+  EmptTd->ActualSendLength = 0;
+  EmptTd->DataBuffer = 0;
+  EmptTd->NextTDPointer = 0;
+  OhciLinkTD (HeadTd, EmptTd);
+  Ed->TdTailPointer = (UINT32)(UINTN)EmptTd;
+  OhciAttachTDListToED (Ed, HeadTd);
+
+  if (OutputED != NULL) {
+    *OutputED = Ed;
+  }
+  if (OutputTD != NULL) {
+    *OutputTD = HeadTd;
+  }
+
+  if (CallBackFunction != NULL) {
+    Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY));
+    if (Entry == NULL) {
+      goto FREE_OHCI_TDBUFF;
+    }
+
+    Entry->DeviceAddress = DeviceAddress;
+    Entry->EndPointAddress = EndPointAddress;
+    Entry->Ed = Ed;
+    Entry->DataTd = HeadTd;
+    Entry->IsSlowDevice = IsSlowDevice;
+    Entry->MaxPacketLength = MaxPacketLength;
+    Entry->PollingInterval = PollingInterval;
+    Entry->CallBackFunction = CallBackFunction;
+    Entry->Context = Context;
+    Entry->IsPeriodic = IsPeriodic;
+    Entry->UCBuffer = UCBuffer;
+    Entry->UCBufferMapping = Mapping;
+    Entry->DataLength = DataLength;
+    Entry->Toggle = DataToggle;
+    Entry->NextEntry = NULL;
+    OhciAddInterruptContextEntry (Ohc, Entry);
+  }
+  OhciSetEDField (Ed, ED_SKIP, 0);
+
+  if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) {
+    Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);
+    gBS->Stall (1000);
+  }
+
+  return EFI_SUCCESS;
+
+FREE_OHCI_TDBUFF:
+  while (HeadTd) {
+    DataTd = HeadTd;
+    HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);
+    UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+  }
+
+//FREE_OHCI_EDBUFF:
+  if ((HeadEd != Ed) && HeadEd && Ed) {
+    while(HeadEd->NextED != (UINT32)(UINTN)Ed) {
+      HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED);
+    }
+  HeadEd->NextED = Ed->NextED;
+    UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+  }
+
+UNMAP_OHCI_XBUFF:
+  Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);
+
+EXIT:
+  return Status;
+}
+
+/**
+
+  Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       The combination of an endpoint number and an endpoint
+                                direction of the target USB device. Each endpoint address
+                                supports data transfer in one direction except the
+                                control endpoint (whose default endpoint address is 0).
+                                It is the caller's responsibility to make sure that
+                                the EndPointAddress represents an interrupt endpoint.
+  @param  IsSlowDevice          Indicates whether the target device is slow device
+                                or full-speed device.
+  @param  MaxiumPacketLength    Indicates the maximum packet size the target endpoint
+                                is capable of sending or receiving.
+  @param  IsNewTransfer         If TRUE, an asynchronous interrupt pipe is built between
+                                the host and the target interrupt endpoint.
+                                If FALSE, the specified asynchronous interrupt pipe
+                                is canceled.
+  @param  DataToggle            A pointer to the data toggle value.  On input, it is valid
+                                when IsNewTransfer is TRUE, and it indicates the initial
+                                data toggle value the asynchronous interrupt transfer
+                                should adopt.
+                                On output, it is valid when IsNewTransfer is FALSE,
+                                and it is updated to indicate the data toggle value of
+                                the subsequent asynchronous interrupt transfer.
+  @param  PollingInterval       Indicates the interval, in milliseconds, that the
+                                asynchronous interrupt transfer is polled.
+                                This parameter is required when IsNewTransfer is TRUE.
+  @param  DataLength            Indicates the length of data to be received at the
+                                rate specified by PollingInterval from the target
+                                asynchronous interrupt endpoint.  This parameter
+                                is only required when IsNewTransfer is TRUE.
+  @param  CallBackFunction      The Callback function.This function is called at the
+                                rate specified by PollingInterval.This parameter is
+                                only required when IsNewTransfer is TRUE.
+  @param  Context               The context that is passed to the CallBackFunction.
+                                This is an optional parameter and may be NULL.
+
+  @retval EFI_SUCCESS           The asynchronous interrupt transfer request has been successfully
+                                submitted or canceled.
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciAsyncInterruptTransfer (
+  IN     EFI_USB_HC_PROTOCOL              *This,
+  IN     UINT8                            DeviceAddress,
+  IN     UINT8                            EndPointAddress,
+  IN     BOOLEAN                          IsSlowDevice,
+  IN     UINT8                            MaxPacketLength,
+  IN     BOOLEAN                          IsNewTransfer,
+  IN OUT UINT8                            *DataToggle        OPTIONAL,
+  IN     UINTN                            PollingInterval    OPTIONAL,
+  IN     UINTN                            DataLength         OPTIONAL,
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK  CallBackFunction   OPTIONAL,
+  IN     VOID                             *Context           OPTIONAL
+  )
+{
+  EFI_STATUS              Status;
+  USB_OHCI_HC_DEV         *Ohc;
+  VOID                    *UCBuffer;
+
+  if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 ||
+    (IsNewTransfer && (DataLength == 0 ||
+    (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+  if ( IsNewTransfer ) {
+    UCBuffer = AllocatePool(DataLength);
+    if (UCBuffer == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    UCBuffer = NULL;
+  }
+  Status = OhciInterruptTransfer (
+             Ohc,
+             DeviceAddress,
+             EndPointAddress,
+             IsSlowDevice,
+             MaxPacketLength,
+             IsNewTransfer,
+             DataToggle,
+             PollingInterval,
+             UCBuffer,
+             DataLength,
+             CallBackFunction,
+             Context,
+             TRUE,
+             NULL,
+             NULL
+             );
+  if ( IsNewTransfer ) {
+    if (EFI_ERROR(Status)) {
+      gBS->FreePool (UCBuffer);
+    }
+  }
+  return Status;
+}
+
+
+/**
+
+  Submits synchronous interrupt transfer to an interrupt endpoint
+  of a USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       The combination of an endpoint number and an endpoint
+                                direction of the target USB device. Each endpoint
+                                address supports data transfer in one direction
+                                except the control endpoint (whose default
+                                endpoint address is 0). It is the caller's responsibility
+                                to make sure that the EndPointAddress represents
+                                an interrupt endpoint.
+  @param  IsSlowDevice          Indicates whether the target device is slow device
+                                or full-speed device.
+  @param  MaxPacketLength       Indicates the maximum packet size the target endpoint
+                                is capable of sending or receiving.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  DataLength            On input, the size, in bytes, of the data buffer specified
+                                by Data. On output, the number of bytes transferred.
+  @param  DataToggle            A pointer to the data toggle value. On input, it indicates
+                                the initial data toggle value the synchronous interrupt
+                                transfer should adopt;
+                                on output, it is updated to indicate the data toggle value
+                                of the subsequent synchronous interrupt transfer.
+  @param  TimeOut               Indicates the maximum time, in microseconds, which the
+                                transfer is allowed to complete.
+  @param  TransferResult        A pointer to the detailed result information from
+                                the synchronous interrupt transfer.
+
+  @retval EFI_UNSUPPORTED       This interface not available.
+  @retval EFI_INVALID_PARAMETER Parameters not follow spec
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciSyncInterruptTransfer (
+  IN     EFI_USB_HC_PROTOCOL  *This,
+  IN     UINT8                DeviceAddress,
+  IN     UINT8                EndPointAddress,
+  IN     BOOLEAN              IsSlowDevice,
+  IN     UINT8                MaxPacketLength,
+  IN OUT VOID                 *Data,
+  IN OUT UINTN                *DataLength,
+  IN OUT UINT8                *DataToggle,
+  IN     UINTN                TimeOut,
+  OUT    UINT32               *TransferResult
+  )
+{
+  USB_OHCI_HC_DEV         *Ohc;
+  EFI_STATUS              Status;
+  ED_DESCRIPTOR           *Ed;
+  TD_DESCRIPTOR           *HeadTd;
+  OHCI_ED_RESULT          EdResult;
+  VOID                    *UCBuffer;
+
+  if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 ||
+      (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) ||
+      DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+  UCBuffer = AllocatePool (*DataLength);
+  if (UCBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  Status = OhciInterruptTransfer (
+             Ohc,
+             DeviceAddress,
+             EndPointAddress,
+             IsSlowDevice,
+             MaxPacketLength,
+             TRUE,
+             DataToggle,
+             1,
+             UCBuffer,
+             *DataLength,
+             NULL,
+             NULL,
+             FALSE,
+             &Ed,
+             &HeadTd
+             );
+
+  if (!EFI_ERROR (Status)) {
+    Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);
+    while (Status == EFI_NOT_READY && TimeOut > 0) {
+      gBS->Stall (1000);
+      TimeOut--;
+      Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);
+    }
+
+    *TransferResult = ConvertErrorCode (EdResult.ErrorCode);
+  }
+  CopyMem(Data, UCBuffer, *DataLength);
+  Status = OhciInterruptTransfer (
+             Ohc,
+             DeviceAddress,
+             EndPointAddress,
+             IsSlowDevice,
+             MaxPacketLength,
+             FALSE,
+             DataToggle,
+             0,
+             NULL,
+             0,
+             NULL,
+             NULL,
+             FALSE,
+             NULL,
+             NULL
+             );
+
+  return Status;
+}
+/**
+
+  Submits isochronous transfer to a target USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       End point address
+  @param  MaximumPacketLength   Indicates the maximum packet size that the
+                                default control transfer endpoint is capable of
+                                sending or receiving.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  DataLength            Indicates the size, in bytes, of the data buffer
+                                specified by Data.
+  @param  TransferResult        A pointer to the detailed result information generated
+                                by this control transfer.
+
+  @retval EFI_UNSUPPORTED       This interface not available
+  @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciIsochronousTransfer (
+  IN     EFI_USB_HC_PROTOCOL  *This,
+  IN     UINT8                DeviceAddress,
+  IN     UINT8                EndPointAddress,
+  IN     UINT8                MaximumPacketLength,
+  IN OUT VOID                 *Data,
+  IN OUT UINTN                DataLength,
+  OUT    UINT32               *TransferResult
+  )
+{
+  if (Data == NULL || DataLength == 0 || TransferResult == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Submits Async isochronous transfer to a target USB device.
+
+  @param  his                   A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       End point address
+  @param  MaximumPacketLength   Indicates the maximum packet size that the
+                                default control transfer endpoint is capable of
+                                sending or receiving.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  IsochronousCallBack   When the transfer complete, the call back function will be called
+  @param  Context               Pass to the call back function as parameter
+
+  @retval EFI_UNSUPPORTED       This interface not available
+  @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciAsyncIsochronousTransfer (
+  IN     EFI_USB_HC_PROTOCOL                *This,
+  IN     UINT8                              DeviceAddress,
+  IN     UINT8                              EndPointAddress,
+  IN     UINT8                              MaximumPacketLength,
+  IN OUT VOID                               *Data,
+  IN OUT UINTN                              DataLength,
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK    IsochronousCallBack,
+  IN     VOID                               *Context OPTIONAL
+  )
+{
+
+  if (Data == NULL || DataLength == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+
+  Retrieves the number of root hub ports.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  NumOfPorts            A pointer to the number of the root hub ports.
+
+  @retval EFI_SUCCESS           The port number was retrieved successfully.
+**/
+EFI_STATUS
+EFIAPI
+OhciGetRootHubNumOfPorts (
+  IN  EFI_USB_HC_PROTOCOL  *This,
+  OUT UINT8                *NumOfPorts
+  )
+{
+  USB_OHCI_HC_DEV  *Ohc;
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+  if (NumOfPorts == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);
+
+  return EFI_SUCCESS;
+}
+/**
+
+  Retrieves the current status of a USB root hub port.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL.
+  @param  PortNumber            Specifies the root hub port from which the status
+                                is to be retrieved.  This value is zero-based. For example,
+                                if a root hub has two ports, then the first port is numbered 0,
+                                and the second port is numbered 1.
+  @param  PortStatus            A pointer to the current port status bits and
+                                port status change bits.
+
+  @retval EFI_SUCCESS           The status of the USB root hub port specified by PortNumber
+                                was returned in PortStatus.
+  @retval EFI_INVALID_PARAMETER Port number not valid
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubPortStatus (
+  IN  EFI_USB_HC_PROTOCOL  *This,
+  IN  UINT8                PortNumber,
+  OUT EFI_USB_PORT_STATUS  *PortStatus
+  )
+{
+  USB_OHCI_HC_DEV  *Ohc;
+  UINT8            NumOfPorts;
+
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+  OhciGetRootHubNumOfPorts (This, &NumOfPorts);
+  if (PortNumber >= NumOfPorts) {
+    return EFI_INVALID_PARAMETER;
+  }
+  PortStatus->PortStatus = 0;
+  PortStatus->PortChangeStatus = 0;
+
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_RESET;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_POWER;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+
+  Sets a feature for the specified root hub port.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL.
+  @param  PortNumber            Specifies the root hub port whose feature
+                                is requested to be set.
+  @param  PortFeature           Indicates the feature selector associated
+                                with the feature set request.
+
+  @retval EFI_SUCCESS           The feature specified by PortFeature was set for the
+                                USB root hub port specified by PortNumber.
+  @retval EFI_DEVICE_ERROR      Set feature failed because of hardware issue
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+**/
+EFI_STATUS
+EFIAPI
+OhciSetRootHubPortFeature (
+  IN EFI_USB_HC_PROTOCOL   *This,
+  IN UINT8                 PortNumber,
+  IN EFI_USB_PORT_FEATURE  PortFeature
+  )
+{
+  USB_OHCI_HC_DEV         *Ohc;
+  EFI_STATUS              Status;
+  UINT8                   NumOfPorts;
+  UINTN                   RetryTimes;
+
+  OhciGetRootHubNumOfPorts (This, &NumOfPorts);
+  if (PortNumber >= NumOfPorts) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+  Status = EFI_SUCCESS;
+
+
+  switch (PortFeature) {
+    case EfiUsbPortPower:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortReset:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||
+                OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+
+      OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);
+      break;
+
+    case EfiUsbPortEnable:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+
+    case EfiUsbPortSuspend:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  return Status;
+}
+
+/**
+
+  Clears a feature for the specified root hub port.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  PortNumber            Specifies the root hub port whose feature
+                                is requested to be cleared.
+  @param  PortFeature           Indicates the feature selector associated with the
+                                feature clear request.
+
+  @retval EFI_SUCCESS           The feature specified by PortFeature was cleared for the
+                                USB root hub port specified by PortNumber.
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+  @retval EFI_DEVICE_ERROR      Some error happened when clearing feature
+**/
+EFI_STATUS
+EFIAPI
+OhciClearRootHubPortFeature (
+  IN EFI_USB_HC_PROTOCOL   *This,
+  IN UINT8                 PortNumber,
+  IN EFI_USB_PORT_FEATURE  PortFeature
+  )
+{
+  USB_OHCI_HC_DEV         *Ohc;
+  EFI_STATUS              Status;
+  UINT8                   NumOfPorts;
+  UINTN                   RetryTimes;
+
+
+  OhciGetRootHubNumOfPorts (This, &NumOfPorts);
+  if (PortNumber >= NumOfPorts) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+  Status = EFI_SUCCESS;
+
+  switch (PortFeature) {
+    case EfiUsbPortEnable:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortSuspend:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortReset:
+      break;
+
+    case EfiUsbPortPower:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortConnectChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortResetChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+
+    case EfiUsbPortEnableChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortSuspendChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortOverCurrentChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        gBS->Stall (1000);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  return Status;
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = {
+  OHCIDriverBindingSupported,
+  OHCIDriverBindingStart,
+  OHCIDriverBindingStop,
+  0x10,
+  NULL,
+  NULL
+};
+
+
+/**
+  Entry point for EFI drivers.
+
+  @param  ImageHandle           EFI_HANDLE.
+  @param  SystemTable           EFI_SYSTEM_TABLE.
+
+  @retval EFI_SUCCESS           Driver is successfully loaded.
+  @return Others                Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverEntryPoint (
+  IN EFI_HANDLE          ImageHandle,
+  IN EFI_SYSTEM_TABLE    *SystemTable
+  )
+{
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &gOhciDriverBinding,
+           ImageHandle,
+           &gOhciComponentName,
+           &gOhciComponentName2
+           );
+}
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has UsbHcProtocol installed will be supported.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @return EFI_SUCCESS          This driver supports this device.
+  @return EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS              Status;
+  EFI_PCI_IO_PROTOCOL     *PciIo;
+  USB_CLASSC              UsbClassCReg;
+  //
+  // Test whether there is PCI IO Protocol attached on the controller handle.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint8,
+                        PCI_CLASSCODE_OFFSET,
+                        sizeof (USB_CLASSC) / sizeof (UINT8),
+                        &UsbClassCReg
+                        );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+  //
+  // Test whether the controller belongs to OHCI type
+  //
+  if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
+      (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
+      (UsbClassCReg.ProgInterface != PCI_IF_OHCI)
+      ) {
+
+    Status = EFI_UNSUPPORTED;
+  }
+ON_EXIT:
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return Status;
+
+}
+
+/**
+
+  Allocate and initialize the empty OHCI device.
+
+  @param  PciIo                  The PCIIO to use.
+  @param  OriginalPciAttributes  The original PCI attributes.
+
+  @return Allocated OHCI device  If err, return NULL.
+
+**/
+
+USB_OHCI_HC_DEV *
+OhciAllocateDev (
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN UINT64               OriginalPciAttributes
+  )
+{
+  USB_OHCI_HC_DEV         *Ohc;
+  EFI_STATUS              Status;
+  VOID                    *Buf;
+  EFI_PHYSICAL_ADDRESS    PhyAddr;
+  VOID                    *Map;
+  UINTN                   Pages;
+  UINTN                   Bytes;
+
+  Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV));
+  if (Ohc == NULL) {
+    return NULL;
+  }
+
+  Ohc->Signature                      = USB_OHCI_HC_DEV_SIGNATURE;
+  Ohc->PciIo                          = PciIo;
+
+  Ohc->UsbHc.Reset                    = OhciReset;
+  Ohc->UsbHc.GetState                 = OhciGetState;
+  Ohc->UsbHc.SetState                 = OhciSetState;
+  Ohc->UsbHc.ControlTransfer          = OhciControlTransfer;
+  Ohc->UsbHc.BulkTransfer             = OhciBulkTransfer;
+  Ohc->UsbHc.AsyncInterruptTransfer   = OhciAsyncInterruptTransfer;
+  Ohc->UsbHc.SyncInterruptTransfer    = OhciSyncInterruptTransfer;
+  Ohc->UsbHc.IsochronousTransfer      = OhciIsochronousTransfer;
+  Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer;
+  Ohc->UsbHc.GetRootHubPortNumber     = OhciGetRootHubNumOfPorts;
+  Ohc->UsbHc.GetRootHubPortStatus     = OhciGetRootHubPortStatus;
+  Ohc->UsbHc.SetRootHubPortFeature    = OhciSetRootHubPortFeature;
+  Ohc->UsbHc.ClearRootHubPortFeature  = OhciClearRootHubPortFeature;
+  Ohc->UsbHc.MajorRevision            = 0x1;
+  Ohc->UsbHc.MinorRevision            = 0x1;
+
+  Ohc->OriginalPciAttributes = OriginalPciAttributes;
+
+  Ohc->HccaMemoryBlock = NULL;
+  Ohc->HccaMemoryMapping   = NULL;
+  Ohc->HccaMemoryBuf = NULL;
+  Ohc->HccaMemoryPages = 0;
+  Ohc->InterruptContextList = NULL;
+  Ohc->ControllerNameTable = NULL;
+  Ohc->HouseKeeperTimer = NULL;
+
+  Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0);
+  if(Ohc->MemPool == NULL) {
+    goto FREE_DEV_BUFFER;
+  }
+
+  Bytes = 4096;
+  Pages = EFI_SIZE_TO_PAGES (Bytes);
+
+  Status = PciIo->AllocateBuffer (
+                    PciIo,
+                    AllocateAnyPages,
+                    EfiBootServicesData,
+                    Pages,
+                    &Buf,
+                    0
+                    );
+
+  if (EFI_ERROR (Status)) {
+    goto FREE_MEM_POOL;
+  }
+
+  Status = PciIo->Map (
+                    PciIo,
+                    EfiPciIoOperationBusMasterCommonBuffer,
+                    Buf,
+                    &Bytes,
+                    &PhyAddr,
+                    &Map
+                    );
+
+  if (EFI_ERROR (Status) || (Bytes != 4096)) {
+    goto FREE_MEM_PAGE;
+  }
+
+  Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr;
+  Ohc->HccaMemoryMapping = Map;
+  Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf;
+  Ohc->HccaMemoryPages = Pages;
+
+  return Ohc;
+
+FREE_MEM_PAGE:
+  PciIo->FreeBuffer (PciIo, Pages, Buf);
+FREE_MEM_POOL:
+  UsbHcFreeMemPool (Ohc->MemPool);
+FREE_DEV_BUFFER:
+  FreePool(Ohc);
+
+  return NULL;
+}
+/**
+
+  Free the OHCI device and release its associated resources.
+
+  @param  Ohc                   The OHCI device to release.
+
+**/
+VOID
+OhciFreeDev (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  OhciFreeFixedIntMemory (Ohc);
+
+  if (Ohc->HouseKeeperTimer != NULL) {
+    gBS->CloseEvent (Ohc->HouseKeeperTimer);
+  }
+
+  if (Ohc->ExitBootServiceEvent != NULL) {
+    gBS->CloseEvent (Ohc->ExitBootServiceEvent);
+  }
+
+  if (Ohc->MemPool != NULL) {
+    UsbHcFreeMemPool (Ohc->MemPool);
+  }
+
+  if (Ohc->HccaMemoryMapping != NULL ) {
+    Ohc->PciIo->FreeBuffer (Ohc->PciIo, Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf);
+  }
+
+  if (Ohc->ControllerNameTable != NULL) {
+    FreeUnicodeStringTable (Ohc->ControllerNameTable);
+  }
+
+  FreePool (Ohc);
+}
+/**
+
+  Uninstall all Ohci Interface.
+
+  @param  Controller            Controller handle.
+  @param  This                  Protocol instance pointer.
+
+**/
+VOID
+OhciCleanDevUp (
+  IN  EFI_HANDLE           Controller,
+  IN  EFI_USB_HC_PROTOCOL  *This
+  )
+{
+  USB_OHCI_HC_DEV  *Ohc;
+
+  //
+  // Retrieve private context structure
+  //
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+  //
+  // Uninstall the USB_HC and USB_HC2 protocol
+  //
+  gBS->UninstallProtocolInterface (
+         Controller,
+         &gEfiUsbHcProtocolGuid,
+         &Ohc->UsbHc
+         );
+
+  //
+  // Cancel the timer event
+  //
+  gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0);
+
+  //
+  // Stop the host controller
+  //
+  OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);
+  This->Reset (This, EFI_USB_HC_RESET_GLOBAL);
+  This->SetState (This, EfiUsbHcStateHalt);
+
+  //
+  // Free resources
+  //
+  OhciFreeDynamicIntMemory (Ohc);
+
+  //
+  // Restore original PCI attributes
+  //
+  Ohc->PciIo->Attributes (
+                Ohc->PciIo,
+                EfiPciIoAttributeOperationSet,
+                Ohc->OriginalPciAttributes,
+                NULL
+                );
+
+  //
+  // Free the private context structure
+  //
+  OhciFreeDev (Ohc);
+}
+
+/**
+
+  One notified function to stop the Host Controller when gBS->ExitBootServices() called.
+
+  @param  Event                 Pointer to this event
+  @param  Context               Event handler private data
+**/
+VOID
+EFIAPI
+OhcExitBootService (
+  EFI_EVENT                      Event,
+  VOID                           *Context
+  )
+{
+  USB_OHCI_HC_DEV           *Ohc;
+  EFI_USB_HC_PROTOCOL       *UsbHc;
+  Ohc = (USB_OHCI_HC_DEV *) Context;
+
+  UsbHc = &Ohc->UsbHc;
+  //
+  // Stop the Host Controller
+  //
+  //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT);
+  OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);
+  UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL);
+  UsbHc->SetState (UsbHc, EfiUsbHcStateHalt);
+
+  return;
+}
+
+
+/**
+  Starting the Usb OHCI Driver.
+
+  @param  This                  Protocol instance pointer.
+  @param  Controller            Handle of device to test.
+  @param  RemainingDevicePath   Not used.
+
+  @retval EFI_SUCCESS           This driver supports this device.
+  @retval EFI_UNSUPPORTED       This driver does not support this device.
+  @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
+                                EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS              Status;
+  EFI_PCI_IO_PROTOCOL     *PciIo;
+  USB_OHCI_HC_DEV         *Ohc;
+  UINT64                  Supports;
+  UINT64                  OriginalPciAttributes;
+  BOOLEAN                 PciAttributesSaved;
+
+  //
+  // Open PCIIO, then enable the HC device and turn off emulation
+  //
+  Ohc = NULL;
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  PciAttributesSaved = FALSE;
+  //
+  // Save original PCI attributes
+  //
+  Status = PciIo->Attributes (
+                    PciIo,
+                    EfiPciIoAttributeOperationGet,
+                    0,
+                    &OriginalPciAttributes
+                    );
+
+  if (EFI_ERROR (Status)) {
+    goto CLOSE_PCIIO;
+  }
+  PciAttributesSaved = TRUE;
+
+  //
+  // Robustnesss improvement such as for UoL
+  // Default is not required.
+  //
+  //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
+  //  OhciTurnOffUsbEmulation (PciIo);
+  //}
+
+  Status = PciIo->Attributes (
+                    PciIo,
+                    EfiPciIoAttributeOperationSupported,
+                    0,
+                    &Supports
+                    );
+  if (!EFI_ERROR (Status)) {
+    Supports &= EFI_PCI_DEVICE_ENABLE;
+    Status = PciIo->Attributes (
+                      PciIo,
+                      EfiPciIoAttributeOperationEnable,
+                      Supports,
+                      NULL
+                      );
+  }
+
+  if (EFI_ERROR (Status)) {
+    goto CLOSE_PCIIO;
+  }
+  //
+  //Allocate memory for OHC private data structure
+  //
+  Ohc = OhciAllocateDev(PciIo, OriginalPciAttributes);
+  if (Ohc == NULL){
+    Status = EFI_OUT_OF_RESOURCES;
+    goto CLOSE_PCIIO;
+  }
+
+  //Status = OhciInitializeInterruptList ( Uhc );
+  //if (EFI_ERROR (Status)) {
+  //  goto FREE_OHC;
+  //}
+
+  //
+  // Set 0.01 s timer
+  //
+  Status = gBS->CreateEvent (
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  OhciHouseKeeper,
+                  Ohc,
+                  &Ohc->HouseKeeperTimer
+                  );
+  if (EFI_ERROR (Status)) {
+    goto FREE_OHC;
+  }
+
+  Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10);
+  if (EFI_ERROR (Status)) {
+    goto FREE_OHC;
+  }
+
+  //
+  //Install Host Controller Protocol
+  //
+  Status = gBS->InstallProtocolInterface (
+                  &Controller,
+                  &gEfiUsbHcProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &Ohc->UsbHc
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "Install protocol error"));
+    goto FREE_OHC;
+  }
+  //
+  // Create event to stop the HC when exit boot service.
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  OhcExitBootService,
+                  Ohc,
+                  &gEfiEventExitBootServicesGuid,
+                  &Ohc->ExitBootServiceEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "Create exit boot event error"));
+    goto UNINSTALL_USBHC;
+  }
+  AddUnicodeString2 (
+    "eng",
+    gOhciComponentName.SupportedLanguages,
+    &Ohc->ControllerNameTable,
+    L"Usb Universal Host Controller",
+    TRUE
+    );
+  AddUnicodeString2 (
+    "en",
+    gOhciComponentName2.SupportedLanguages,
+    &Ohc->ControllerNameTable,
+    L"Usb Universal Host Controller",
+    FALSE
+    );
+
+  return EFI_SUCCESS;
+
+UNINSTALL_USBHC:
+  gBS->UninstallMultipleProtocolInterfaces (
+         Controller,
+         &gEfiUsbHcProtocolGuid,
+         &Ohc->UsbHc,
+         NULL
+         );
+
+FREE_OHC:
+  OhciFreeDev (Ohc);
+
+CLOSE_PCIIO:
+  if (PciAttributesSaved) {
+  //
+  // Restore original PCI attributes
+  //
+    PciIo->Attributes (
+             PciIo,
+             EfiPciIoAttributeOperationSet,
+             OriginalPciAttributes,
+             NULL
+             );
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+  return Status;
+}
+
+/**
+  Stop this driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param  This                  Protocol instance pointer.
+  @param  Controller            Handle of device to stop driver on.
+  @param  NumberOfChildren      Number of Children in the ChildHandleBuffer.
+  @param  ChildHandleBuffer     List of handles for the children we need to stop.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN UINTN                        NumberOfChildren,
+  IN EFI_HANDLE                   *ChildHandleBuffer
+  )
+{
+  EFI_STATUS           Status;
+  EFI_USB_HC_PROTOCOL  *UsbHc;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiUsbHcProtocolGuid,
+                  (VOID **)&UsbHc,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  OhciCleanDevUp(Controller, UsbHc);
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+  return EFI_SUCCESS;
+}
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h
new file mode 100644
index 0000000000..4c374ab9e2
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h
@@ -0,0 +1,663 @@
+/** @file
+Provides the definition of Usb Hc Protocol and OHCI controller
+private data structure.
+
+Copyright (c) 2013-2016 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#ifndef _OHCI_H
+#define _OHCI_H
+
+
+#include <Uefi.h>
+
+#include <Protocol/UsbHostController.h>
+#include <Protocol/PciIo.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+
+typedef struct _USB_OHCI_HC_DEV USB_OHCI_HC_DEV;
+
+#include "UsbHcMem.h"
+#include "OhciReg.h"
+#include "OhciSched.h"
+#include "OhciUrb.h"
+#include "Descriptor.h"
+#include "ComponentName.h"
+#include "OhciDebug.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL   gOhciDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gOhciComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gOhciComponentName2;
+
+#define USB_OHCI_HC_DEV_SIGNATURE     SIGNATURE_32('o','h','c','i')
+
+typedef struct _HCCA_MEMORY_BLOCK{
+  UINT32                    HccaInterruptTable[32];    // 32-bit Physical Address to ED_DESCRIPTOR
+  UINT16                    HccaFrameNumber;
+  UINT16                    HccaPad;
+  UINT32                    HccaDoneHead;              // 32-bit Physical Address to TD_DESCRIPTOR
+  UINT8                     Reserved[116];
+} HCCA_MEMORY_BLOCK;
+
+
+struct _USB_OHCI_HC_DEV {
+  UINTN                     Signature;
+  EFI_USB_HC_PROTOCOL       UsbHc;
+  EFI_USB2_HC_PROTOCOL      Usb2Hc;
+  EFI_PCI_IO_PROTOCOL       *PciIo;
+  UINT64                    OriginalPciAttributes;
+
+  HCCA_MEMORY_BLOCK         *HccaMemoryBlock;
+  VOID                      *HccaMemoryBuf;
+  VOID                      *HccaMemoryMapping;
+  UINTN                     HccaMemoryPages;
+
+  ED_DESCRIPTOR             *IntervalList[6][32];
+  INTERRUPT_CONTEXT_ENTRY   *InterruptContextList;
+  VOID                      *MemPool;
+
+  UINT32                    ToggleFlag;
+
+  EFI_EVENT                 HouseKeeperTimer;
+  //
+  // ExitBootServicesEvent is used to stop the OHC DMA operation
+  // after exit boot service.
+  //
+  EFI_EVENT                  ExitBootServiceEvent;
+
+  EFI_UNICODE_STRING_TABLE  *ControllerNameTable;
+};
+
+#define USB_OHCI_HC_DEV_FROM_THIS(a)    CR(a, USB_OHCI_HC_DEV, UsbHc, USB_OHCI_HC_DEV_SIGNATURE)
+#define USB2_OHCI_HC_DEV_FROM_THIS(a)    CR(a, USB_OHCI_HC_DEV, Usb2Hc, USB_OHCI_HC_DEV_SIGNATURE)
+
+//
+// Func List
+//
+
+/**
+  Provides software reset for the USB host controller.
+
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.
+  @param  Attributes            A bit mask of the reset operation to perform.
+
+  @retval EFI_SUCCESS           The reset operation succeeded.
+  @retval EFI_INVALID_PARAMETER Attributes is not valid.
+  @retval EFI_UNSUPPOURTED      The type of reset specified by Attributes is
+                                not currently supported by the host controller.
+  @retval EFI_DEVICE_ERROR      Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciReset (
+  IN EFI_USB_HC_PROTOCOL  *This,
+  IN UINT16               Attributes
+  );
+/**
+  Retrieve the current state of the USB host controller.
+
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.
+  @param  State                 Variable to return the current host controller
+                                state.
+
+  @retval EFI_SUCCESS           Host controller state was returned in State.
+  @retval EFI_INVALID_PARAMETER State is NULL.
+  @retval EFI_DEVICE_ERROR      An error was encountered while attempting to
+                                retrieve the host controller's current state.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetState (
+  IN  EFI_USB_HC_PROTOCOL  *This,
+  OUT EFI_USB_HC_STATE     *State
+  );
+/**
+  Sets the USB host controller to a specific state.
+
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.
+  @param  State                 The state of the host controller that will be set.
+
+  @retval EFI_SUCCESS           The USB host controller was successfully placed
+                                in the state specified by State.
+  @retval EFI_INVALID_PARAMETER State is invalid.
+  @retval EFI_DEVICE_ERROR      Failed to set the state due to device error.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciSetState(
+  IN EFI_USB_HC_PROTOCOL  *This,
+  IN EFI_USB_HC_STATE     State
+  );
+/**
+
+  Submits control transfer to a target USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  IsSlowDevice          Indicates whether the target device is slow device
+                                or full-speed device.
+  @param  MaxPaketLength        Indicates the maximum packet size that the
+                                default control transfer endpoint is capable of
+                                sending or receiving.
+  @param  Request               A pointer to the USB device request that will be sent
+                                to the USB device.
+  @param  TransferDirection     Specifies the data direction for the transfer.
+                                There are three values available, DataIn, DataOut
+                                and NoData.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  DataLength            Indicates the size, in bytes, of the data buffer
+                                specified by Data.
+  @param  TimeOut               Indicates the maximum time, in microseconds,
+                                which the transfer is allowed to complete.
+  @param  TransferResult        A pointer to the detailed result information generated
+                                by this control transfer.
+
+  @retval EFI_SUCCESS           The control transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The control transfer could not be completed due to a lack of resources.
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+  @retval EFI_TIMEOUT           The control transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR      The control transfer failed due to host controller or device error.
+                                Caller should check TranferResult for detailed error information.
+
+--*/
+
+
+EFI_STATUS
+EFIAPI
+OhciControlTransfer (
+  IN     EFI_USB_HC_PROTOCOL     *This,
+  IN     UINT8                   DeviceAddress,
+  IN     BOOLEAN                 IsSlowDevice,
+  IN     UINT8                   MaxPacketLength,
+  IN     EFI_USB_DEVICE_REQUEST  *Request,
+  IN     EFI_USB_DATA_DIRECTION  TransferDirection,
+  IN OUT VOID                    *Data                 OPTIONAL,
+  IN OUT UINTN                   *DataLength           OPTIONAL,
+  IN     UINTN                   TimeOut,
+  OUT    UINT32                  *TransferResult
+  );
+/**
+
+  Submits bulk transfer to a bulk endpoint of a USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       The combination of an endpoint number and an
+                                endpoint direction of the target USB device.
+                                Each endpoint address supports data transfer in
+                                one direction except the control endpoint
+                                (whose default endpoint address is 0).
+                                It is the caller's responsibility to make sure that
+                                the EndPointAddress represents a bulk endpoint.
+  @param  MaximumPacketLength   Indicates the maximum packet size the target endpoint
+                                is capable of sending or receiving.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  DataLength            When input, indicates the size, in bytes, of the data buffer
+                                specified by Data. When output, indicates the actually
+                                transferred data size.
+  @param  DataToggle            A pointer to the data toggle value. On input, it indicates
+                                the initial data toggle value the bulk transfer should adopt;
+                                on output, it is updated to indicate the data toggle value
+                                of the subsequent bulk transfer.
+  @param  TimeOut               Indicates the maximum time, in microseconds, which the
+                                transfer is allowed to complete.
+  TransferResult                A pointer to the detailed result information of the
+                                bulk transfer.
+
+  @retval EFI_SUCCESS           The bulk transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The bulk transfer could not be submitted due to lack of resource.
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+  @retval EFI_TIMEOUT           The bulk transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR      The bulk transfer failed due to host controller or device error.
+                                Caller should check TranferResult for detailed error information.
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciBulkTransfer(
+  IN     EFI_USB_HC_PROTOCOL  *This,
+  IN     UINT8                DeviceAddress,
+  IN     UINT8                EndPointAddress,
+  IN     UINT8                MaxPacketLength,
+  IN OUT VOID                 *Data,
+  IN OUT UINTN                *DataLength,
+  IN OUT UINT8                *DataToggle,
+  IN     UINTN                TimeOut,
+  OUT    UINT32               *TransferResult
+  );
+/**
+
+  Submits an interrupt transfer to an interrupt endpoint of a USB device.
+
+  @param  Ohc                   Device private data
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       The combination of an endpoint number and an endpoint
+                                direction of the target USB device. Each endpoint address
+                                supports data transfer in one direction except the
+                                control endpoint (whose default endpoint address is 0).
+                                It is the caller's responsibility to make sure that
+                                the EndPointAddress represents an interrupt endpoint.
+  @param  IsSlowDevice          Indicates whether the target device is slow device
+                                or full-speed device.
+  @param  MaxPacketLength       Indicates the maximum packet size the target endpoint
+                                is capable of sending or receiving.
+  @param  IsNewTransfer         If TRUE, an asynchronous interrupt pipe is built between
+                                the host and the target interrupt endpoint.
+                                If FALSE, the specified asynchronous interrupt pipe
+                                is canceled.
+  @param  DataToggle            A pointer to the data toggle value.  On input, it is valid
+                                when IsNewTransfer is TRUE, and it indicates the initial
+                                data toggle value the asynchronous interrupt transfer
+                                should adopt.
+                                On output, it is valid when IsNewTransfer is FALSE,
+                                and it is updated to indicate the data toggle value of
+                                the subsequent asynchronous interrupt transfer.
+  @param  PollingInterval       Indicates the interval, in milliseconds, that the
+                                asynchronous interrupt transfer is polled.
+                                This parameter is required when IsNewTransfer is TRUE.
+  @param  UCBuffer              Uncacheable buffer
+  @param  DataLength            Indicates the length of data to be received at the
+                                rate specified by PollingInterval from the target
+                                asynchronous interrupt endpoint.  This parameter
+                                is only required when IsNewTransfer is TRUE.
+  @param  CallBackFunction      The Callback function.This function is called at the
+                                rate specified by PollingInterval.This parameter is
+                                only required when IsNewTransfer is TRUE.
+  @param  Context               The context that is passed to the CallBackFunction.
+                                This is an optional parameter and may be NULL.
+  @param  IsPeriodic            Periodic interrupt or not
+  @param  OutputED              The correspoding ED carried out
+  @param  OutputTD              The correspoding TD carried out
+
+
+  @retval EFI_SUCCESS           The asynchronous interrupt transfer request has been successfully
+                                submitted or canceled.
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+
+**/
+
+EFI_STATUS
+OhciInterruptTransfer (
+  IN     USB_OHCI_HC_DEV                  *Ohc,
+  IN     UINT8                            DeviceAddress,
+  IN     UINT8                            EndPointAddress,
+  IN     BOOLEAN                          IsSlowDevice,
+  IN     UINT8                            MaxPacketLength,
+  IN     BOOLEAN                          IsNewTransfer,
+  IN OUT UINT8                            *DataToggle        OPTIONAL,
+  IN     UINTN                            PollingInterval    OPTIONAL,
+  IN     VOID                             *UCBuffer          OPTIONAL,
+  IN     UINTN                            DataLength         OPTIONAL,
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK  CallBackFunction   OPTIONAL,
+  IN     VOID                             *Context           OPTIONAL,
+  IN     BOOLEAN                          IsPeriodic         OPTIONAL,
+  OUT    ED_DESCRIPTOR                    **OutputED         OPTIONAL,
+  OUT    TD_DESCRIPTOR                    **OutputTD         OPTIONAL
+  );
+/**
+
+  Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       The combination of an endpoint number and an endpoint
+                                direction of the target USB device. Each endpoint address
+                                supports data transfer in one direction except the
+                                control endpoint (whose default endpoint address is 0).
+                                It is the caller's responsibility to make sure that
+                                the EndPointAddress represents an interrupt endpoint.
+  @param  IsSlowDevice          Indicates whether the target device is slow device
+                                or full-speed device.
+  @param  MaxiumPacketLength    Indicates the maximum packet size the target endpoint
+                                is capable of sending or receiving.
+  @param  IsNewTransfer         If TRUE, an asynchronous interrupt pipe is built between
+                                the host and the target interrupt endpoint.
+                                If FALSE, the specified asynchronous interrupt pipe
+                                is canceled.
+  @param  DataToggle            A pointer to the data toggle value.  On input, it is valid
+                                when IsNewTransfer is TRUE, and it indicates the initial
+                                data toggle value the asynchronous interrupt transfer
+                                should adopt.
+                                On output, it is valid when IsNewTransfer is FALSE,
+                                and it is updated to indicate the data toggle value of
+                                the subsequent asynchronous interrupt transfer.
+  @param  PollingInterval       Indicates the interval, in milliseconds, that the
+                                asynchronous interrupt transfer is polled.
+                                This parameter is required when IsNewTransfer is TRUE.
+  @param  DataLength            Indicates the length of data to be received at the
+                                rate specified by PollingInterval from the target
+                                asynchronous interrupt endpoint.  This parameter
+                                is only required when IsNewTransfer is TRUE.
+  @param  CallBackFunction      The Callback function.This function is called at the
+                                rate specified by PollingInterval.This parameter is
+                                only required when IsNewTransfer is TRUE.
+  @param  Context               The context that is passed to the CallBackFunction.
+                                This is an optional parameter and may be NULL.
+
+  @retval EFI_SUCCESS           The asynchronous interrupt transfer request has been successfully
+                                submitted or canceled.
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciAsyncInterruptTransfer (
+  IN     EFI_USB_HC_PROTOCOL              *This,
+  IN     UINT8                            DeviceAddress,
+  IN     UINT8                            EndPointAddress,
+  IN     BOOLEAN                          IsSlowDevice,
+  IN     UINT8                            MaxPacketLength,
+  IN     BOOLEAN                          IsNewTransfer,
+  IN OUT UINT8                            *DataToggle        OPTIONAL,
+  IN     UINTN                            PollingInterval    OPTIONAL,
+  IN     UINTN                            DataLength         OPTIONAL,
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK  CallBackFunction   OPTIONAL,
+  IN     VOID                             *Context           OPTIONAL
+  );
+/**
+
+  Submits synchronous interrupt transfer to an interrupt endpoint
+  of a USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       The combination of an endpoint number and an endpoint
+                                direction of the target USB device. Each endpoint
+                                address supports data transfer in one direction
+                                except the control endpoint (whose default
+                                endpoint address is 0). It is the caller's responsibility
+                                to make sure that the EndPointAddress represents
+                                an interrupt endpoint.
+  @param  IsSlowDevice          Indicates whether the target device is slow device
+                                or full-speed device.
+  @param  MaxPacketLength       Indicates the maximum packet size the target endpoint
+                                is capable of sending or receiving.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  DataLength            On input, the size, in bytes, of the data buffer specified
+                                by Data. On output, the number of bytes transferred.
+  @param  DataToggle            A pointer to the data toggle value. On input, it indicates
+                                the initial data toggle value the synchronous interrupt
+                                transfer should adopt;
+                                on output, it is updated to indicate the data toggle value
+                                of the subsequent synchronous interrupt transfer.
+  @param  TimeOut               Indicates the maximum time, in microseconds, which the
+                                transfer is allowed to complete.
+  @param  TransferResult        A pointer to the detailed result information from
+                                the synchronous interrupt transfer.
+
+  @retval EFI_UNSUPPORTED       This interface not available.
+  @retval EFI_INVALID_PARAMETER Parameters not follow spec
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciSyncInterruptTransfer (
+  IN     EFI_USB_HC_PROTOCOL  *This,
+  IN     UINT8                DeviceAddress,
+  IN     UINT8                EndPointAddress,
+  IN     BOOLEAN              IsSlowDevice,
+  IN     UINT8                MaxPacketLength,
+  IN OUT VOID                 *Data,
+  IN OUT UINTN                *DataLength,
+  IN OUT UINT8                *DataToggle,
+  IN     UINTN                TimeOut,
+  OUT    UINT32               *TransferResult
+  );
+/**
+
+  Submits isochronous transfer to a target USB device.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       End point address
+  @param  MaximumPacketLength   Indicates the maximum packet size that the
+                                default control transfer endpoint is capable of
+                                sending or receiving.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  DataLength            Indicates the size, in bytes, of the data buffer
+                                specified by Data.
+  @param  TransferResult        A pointer to the detailed result information generated
+                                by this control transfer.
+
+  @retval EFI_UNSUPPORTED       This interface not available
+  @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciIsochronousTransfer (
+  IN     EFI_USB_HC_PROTOCOL  *This,
+  IN     UINT8                DeviceAddress,
+  IN     UINT8                EndPointAddress,
+  IN     UINT8                MaximumPacketLength,
+  IN OUT VOID                 *Data,
+  IN OUT UINTN                DataLength,
+  OUT    UINT32               *TransferResult
+  );
+/**
+
+  Submits Async isochronous transfer to a target USB device.
+
+  @param  his                   A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  DeviceAddress         Represents the address of the target device on the USB,
+                                which is assigned during USB enumeration.
+  @param  EndPointAddress       End point address
+  @param  MaximumPacketLength   Indicates the maximum packet size that the
+                                default control transfer endpoint is capable of
+                                sending or receiving.
+  @param  Data                  A pointer to the buffer of data that will be transmitted
+                                to USB device or received from USB device.
+  @param  IsochronousCallBack   When the transfer complete, the call back function will be called
+  @param  Context               Pass to the call back function as parameter
+
+  @retval EFI_UNSUPPORTED       This interface not available
+  @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciAsyncIsochronousTransfer (
+  IN     EFI_USB_HC_PROTOCOL                *This,
+  IN     UINT8                              DeviceAddress,
+  IN     UINT8                              EndPointAddress,
+  IN     UINT8                              MaximumPacketLength,
+  IN OUT VOID                               *Data,
+  IN OUT UINTN                              DataLength,
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK    IsochronousCallBack,
+  IN     VOID                               *Context OPTIONAL
+  );
+
+/**
+
+  Retrieves the number of root hub ports.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  NumOfPorts            A pointer to the number of the root hub ports.
+
+  @retval EFI_SUCCESS           The port number was retrieved successfully.
+**/
+EFI_STATUS
+EFIAPI
+OhciGetRootHubNumOfPorts (
+  IN  EFI_USB_HC_PROTOCOL  *This,
+  OUT UINT8                *NumOfPorts
+  );
+/**
+
+  Retrieves the current status of a USB root hub port.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL.
+  @param  PortNumber            Specifies the root hub port from which the status
+                                is to be retrieved.  This value is zero-based. For example,
+                                if a root hub has two ports, then the first port is numbered 0,
+                                and the second port is numbered 1.
+  @param  PortStatus            A pointer to the current port status bits and
+                                port status change bits.
+
+  @retval EFI_SUCCESS           The status of the USB root hub port specified by PortNumber
+                                was returned in PortStatus.
+  @retval EFI_INVALID_PARAMETER Port number not valid
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubPortStatus (
+  IN  EFI_USB_HC_PROTOCOL  *This,
+  IN  UINT8                PortNumber,
+  OUT EFI_USB_PORT_STATUS  *PortStatus
+  );
+
+/**
+
+  Sets a feature for the specified root hub port.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL.
+  @param  PortNumber            Specifies the root hub port whose feature
+                                is requested to be set.
+  @param  PortFeature           Indicates the feature selector associated
+                                with the feature set request.
+
+  @retval EFI_SUCCESS           The feature specified by PortFeature was set for the
+                                USB root hub port specified by PortNumber.
+  @retval EFI_DEVICE_ERROR      Set feature failed because of hardware issue
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+**/
+EFI_STATUS
+EFIAPI
+OhciSetRootHubPortFeature (
+  IN EFI_USB_HC_PROTOCOL   *This,
+  IN UINT8                 PortNumber,
+  IN EFI_USB_PORT_FEATURE  PortFeature
+  );
+/**
+
+  Clears a feature for the specified root hub port.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.
+  @param  PortNumber            Specifies the root hub port whose feature
+                                is requested to be cleared.
+  @param  PortFeature           Indicates the feature selector associated with the
+                                feature clear request.
+
+  @retval EFI_SUCCESS           The feature specified by PortFeature was cleared for the
+                                USB root hub port specified by PortNumber.
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+  @retval EFI_DEVICE_ERROR      Some error happened when clearing feature
+**/
+EFI_STATUS
+EFIAPI
+OhciClearRootHubPortFeature (
+  IN EFI_USB_HC_PROTOCOL   *This,
+  IN UINT8                 PortNumber,
+  IN EFI_USB_PORT_FEATURE  PortFeature
+  );
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has UsbHcProtocol installed will be supported.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to test.
+  @param  RemainingDevicePath  Not used.
+
+  @return EFI_SUCCESS          This driver supports this device.
+  @return EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+
+OHCIDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+/**
+  Starting the Usb OHCI Driver.
+
+  @param  This                  Protocol instance pointer.
+  @param  Controller            Handle of device to test.
+  @param  RemainingDevicePath   Not used.
+
+  @retval EFI_SUCCESS           This driver supports this device.
+  @retval EFI_UNSUPPORTED       This driver does not support this device.
+  @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
+                                EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+/**
+  Stop this driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param  This                  Protocol instance pointer.
+  @param  Controller            Handle of device to stop driver on.
+  @param  NumberOfChildren      Number of Children in the ChildHandleBuffer.
+  @param  ChildHandleBuffer     List of handles for the children we need to stop.
+
+  @return EFI_SUCCESS
+  @return others
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN UINTN                        NumberOfChildren,
+  IN EFI_HANDLE                   *ChildHandleBuffer
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c
new file mode 100644
index 0000000000..cf60794a99
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c
@@ -0,0 +1,78 @@
+/** @file
+This file provides the information dump support for OHCI when in debug mode.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ohci.h"
+
+
+/*++
+
+  Print the data of ED and the TDs attached to the ED
+
+  @param  Uhc                   Pointer to OHCI private data
+  @param  Ed                    Pointer to a ED to free
+  @param  Td                    Pointer to the Td head
+
+  @retval EFI_SUCCESS           ED
+
+**/
+EFI_STATUS
+OhciDumpEdTdInfo (
+  IN USB_OHCI_HC_DEV      *Uhc,
+  IN ED_DESCRIPTOR        *Ed,
+  IN TD_DESCRIPTOR        *Td,
+  BOOLEAN                 Stage
+  )
+{
+  UINT32                  Index;
+
+  if (Stage) {
+    DEBUG ((EFI_D_INFO, "\n Before executing command\n"));
+  }else{
+    DEBUG ((EFI_D_INFO, "\n after executing command\n"));
+  }
+  if (Ed != NULL) {
+    DEBUG ((EFI_D_INFO, "\nED Address:%p, ED buffer:\n", Ed));
+    DEBUG ((EFI_D_INFO, "DWord0  :TD Tail :TD Head :Next ED\n"));
+    for (Index = 0; Index < sizeof (ED_DESCRIPTOR)/4; Index ++) {
+      DEBUG ((EFI_D_INFO, "%8x ", *((UINT32*)(Ed) + Index)  ));
+    }
+    DEBUG ((EFI_D_INFO, "\nNext TD buffer:%p\n", Td));
+  }
+  while (Td != NULL) {
+    if (Td->Word0.DirPID == TD_SETUP_PID) {
+      DEBUG ((EFI_D_INFO, "\nSetup PID "));
+    }else if (Td->Word0.DirPID == TD_OUT_PID) {
+      DEBUG ((EFI_D_INFO, "\nOut PID "));
+    }else if (Td->Word0.DirPID == TD_IN_PID) {
+      DEBUG ((EFI_D_INFO, "\nIn PID "));
+    }else if (Td->Word0.DirPID == TD_NODATA_PID) {
+      DEBUG ((EFI_D_INFO, "\nNo data PID "));
+    }
+    DEBUG ((EFI_D_INFO, "TD Address:%p, TD buffer:\n", Td));
+    DEBUG ((EFI_D_INFO, "DWord0  :CuBuffer:Next TD :Buff End:Next TD :DataBuff:ActLength\n"));
+    for (Index = 0; Index < sizeof (TD_DESCRIPTOR)/4; Index ++) {
+      DEBUG ((EFI_D_INFO, "%8x ", *((UINT32*)(Td) + Index)  ));
+    }
+    DEBUG ((EFI_D_INFO, "\nCurrent TD Data buffer(size%d)\n", (UINT32)Td->ActualSendLength));
+    for (Index = 0; Index < Td->ActualSendLength; Index ++) {
+      DEBUG ((EFI_D_INFO, "%2x ", *(UINT8 *)(UINTN)(Td->DataBuffer + Index) ));
+    }
+  Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer);
+  }
+  DEBUG ((EFI_D_INFO, "\n TD buffer End\n"));
+
+  return EFI_SUCCESS;
+}
+
+
+
+
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h
new file mode 100644
index 0000000000..a2d79ff7e5
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h
@@ -0,0 +1,42 @@
+/** @file
+This file contains the definination for host controller
+debug support routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+/*++
+
+Routine Description:
+
+  Print the data of ED and the TDs attached to the ED
+
+  @param  Uhc                   Pointer to OHCI private data
+  @param  Ed                    Pointer to a ED to free
+  @param  Td                    Pointer to the Td head
+
+  @retval EFI_SUCCESS           ED
+
+**/
+EFI_STATUS
+OhciDumpEdTdInfo (
+  IN USB_OHCI_HC_DEV          *Uhc,
+  IN ED_DESCRIPTOR     *Ed,
+  IN TD_DESCRIPTOR     *Td,
+  BOOLEAN Stage
+  );
+
+
+
+
+
+
+
+
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf
new file mode 100644
index 0000000000..9b8f455969
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf
@@ -0,0 +1,71 @@
+## @file
+# OHCI USB Host Controller UEFI Driver
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = OhciDxe
+  FILE_GUID                      = 4ACA697E-F883-446f-98F7-096416FFFFFF
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = OHCIDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+#  DRIVER_BINDING                =  gOhciDriverBinding
+#  COMPONENT_NAME                =  gOhciComponentName
+#  COMPONENT_NAME2               =  gOhciComponentName2
+#
+[Sources]
+  Descriptor.h
+  Ohci.c
+  Ohci.h
+  OhciSched.c
+  OhciSched.h
+  OhciReg.c
+  OhciReg.h
+  OhciUrb.c
+  OhciUrb.h
+  OhciDebug.c
+  OhciDebug.h
+  ComponentName.c
+  ComponentName.h
+  UsbHcMem.c
+  UsbHcMem.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  DebugLib
+
+[Guids]
+  gEfiEventExitBootServicesGuid                 ## SOMETIMES_CONSUMES   ## Event
+
+[Protocols]
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gEfiUsbHcProtocolGuid                         ## BY_START
+
+#
+# [Event]
+#   ##
+#   # Periodic timer event for checking the result of interrupt transfer execution.
+#   #
+#   EVENT_TYPE_PERIODIC_TIMER                   ## CONSUMES
+#
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c
new file mode 100644
index 0000000000..f9cdd049be
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c
@@ -0,0 +1,1390 @@
+/** @file
+The OHCI register operation routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ohci.h"
+
+/**
+
+  Get OHCI operational reg value
+
+  @param  PciIo                 PciIo protocol instance
+  @param  Offset                Offset of the operational reg
+
+  @retval                       Value of the register
+
+**/
+UINT32
+OhciGetOperationalReg (
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN UINT32               Offset
+  )
+{
+  UINT32                  Value;
+
+  PciIo->Mem.Read(PciIo, EfiPciIoWidthUint32, OHC_BAR_INDEX, Offset, 1, &Value);
+
+  return Value;
+}
+/**
+
+  Set OHCI operational reg value
+
+  @param  PciIo                  PCI Bus Io protocol instance
+  @param  Offset                 Offset of the operational reg
+  @param  Value                  Value to set
+
+  @retval EFI_SUCCESS            Value set to the reg
+
+**/
+
+
+EFI_STATUS
+OhciSetOperationalReg (
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN UINT32               Offset,
+  IN VOID                 *Value
+  )
+{
+  EFI_STATUS Status;
+
+  Status = PciIo->Mem.Write(PciIo, EfiPciIoWidthUint32, OHC_BAR_INDEX, Offset, 1, Value);
+
+  return Status;
+}
+/**
+
+  Get HcRevision reg value
+
+  @param  PciIo                 PCI Bus Io protocol instance
+
+  @retval                       Value of the register
+
+**/
+
+
+UINT32
+OhciGetHcRevision (
+  IN EFI_PCI_IO_PROTOCOL  *PciIo
+  )
+{
+  return OhciGetOperationalReg (PciIo, HC_REVISION);
+}
+/**
+
+  Set HcReset reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcReset (
+  IN USB_OHCI_HC_DEV            *Ohc,
+  IN UINT32                     Field,
+  IN UINT32                     Value
+  )
+{
+  HcRESET                       Reset;
+
+  *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR);
+
+  if (Field & RESET_SYSTEM_BUS) {
+    Reset.FSBIR = Value;
+  }
+
+  if (Field & RESET_HOST_CONTROLLER) {
+    Reset.FHR = Value;
+  }
+
+  if (Field & RESET_CLOCK_GENERATION) {
+    Reset.CGR = Value;
+  }
+
+  if (Field & RESET_SSE_GLOBAL) {
+    Reset.SSE = Value;
+  }
+
+  if (Field & RESET_PSPL) {
+    Reset.PSPL = Value;
+  }
+
+  if (Field & RESET_PCPL) {
+    Reset.PCPL = Value;
+  }
+
+  if (Field & RESET_SSEP1) {
+    Reset.SSEP1 = Value;
+  }
+
+  if (Field & RESET_SSEP2) {
+    Reset.SSEP2 = Value;
+  }
+
+  if (Field & RESET_SSEP3) {
+    Reset.SSEP3 = Value;
+  }
+
+  OhciSetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR, &Reset);
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Get specific field of HcReset reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcReset (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Field
+  )
+{
+  HcRESET                 Reset;
+  UINT32                  Value;
+
+
+  *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR);
+  Value = 0;
+
+  switch (Field) {
+  case RESET_SYSTEM_BUS:
+    Value = Reset.FSBIR;
+    break;
+
+  case RESET_HOST_CONTROLLER:
+    Value = Reset.FHR;
+    break;
+
+  case RESET_CLOCK_GENERATION:
+    Value = Reset.CGR;
+    break;
+
+  case RESET_SSE_GLOBAL:
+    Value = Reset.SSE;
+    break;
+
+  case RESET_PSPL:
+    Value = Reset.PSPL;
+    break;
+
+  case RESET_PCPL:
+    Value = Reset.PCPL;
+    break;
+
+  case RESET_SSEP1:
+    Value = Reset.SSEP1;
+    break;
+
+  case RESET_SSEP2:
+    Value = Reset.SSEP2;
+    break;
+
+  case RESET_SSEP3:
+    Value = Reset.SSEP3;
+    break;
+
+  default:
+    ASSERT (FALSE);
+  }
+
+
+  return Value;
+}
+
+/**
+
+  Set HcControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcCONTROL               Control;
+
+
+
+  *(UINT32 *) &Control = OhciGetOperationalReg (Ohc->PciIo, HC_CONTROL);
+
+  if (Field & CONTROL_BULK_RATIO) {
+    Control.ControlBulkRatio = Value;
+  }
+
+  if (Field & HC_FUNCTIONAL_STATE) {
+    Control.FunctionalState = Value;
+  }
+
+  if (Field & PERIODIC_ENABLE) {
+    Control.PeriodicEnable = Value;
+  }
+
+  if (Field & CONTROL_ENABLE) {
+    Control.ControlEnable = Value;
+  }
+
+  if (Field & ISOCHRONOUS_ENABLE) {
+    Control.IsochronousEnable = Value;
+  }
+
+  if (Field & BULK_ENABLE) {
+    Control.BulkEnable = Value;
+  }
+
+  if (Field & INTERRUPT_ROUTING) {
+    Control.InterruptRouting = Value;
+  }
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_CONTROL, &Control);
+
+  return Status;
+}
+
+
+/**
+
+  Get specific field of HcControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+
+UINT32
+OhciGetHcControl (
+  IN USB_OHCI_HC_DEV   *Ohc,
+  IN UINTN             Field
+  )
+{
+  HcCONTROL     Control;
+
+  *(UINT32 *) &Control = OhciGetOperationalReg (Ohc->PciIo, HC_CONTROL);
+
+  switch (Field) {
+  case CONTROL_BULK_RATIO:
+    return Control.ControlBulkRatio;
+    break;
+  case PERIODIC_ENABLE:
+    return Control.PeriodicEnable;
+    break;
+  case CONTROL_ENABLE:
+    return Control.ControlEnable;
+    break;
+  case BULK_ENABLE:
+    return Control.BulkEnable;
+    break;
+  case ISOCHRONOUS_ENABLE:
+    return Control.IsochronousEnable;
+    break;
+  case HC_FUNCTIONAL_STATE:
+    return Control.FunctionalState;
+    break;
+  case INTERRUPT_ROUTING:
+    return Control.InterruptRouting;
+    break;
+  default:
+    ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set HcCommand reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcCommandStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcCOMMAND_STATUS        CommandStatus;
+
+  ZeroMem (&CommandStatus, sizeof (HcCOMMAND_STATUS));
+
+  if(Field & HC_RESET){
+    CommandStatus.HcReset = Value;
+  }
+
+  if(Field & CONTROL_LIST_FILLED){
+    CommandStatus.ControlListFilled = Value;
+  }
+
+  if(Field & BULK_LIST_FILLED){
+    CommandStatus.BulkListFilled = Value;
+  }
+
+  if(Field & CHANGE_OWNER_REQUEST){
+    CommandStatus.ChangeOwnerRequest = Value;
+  }
+
+  if(Field & SCHEDULE_OVERRUN_COUNT){
+    CommandStatus.ScheduleOverrunCount = Value;
+  }
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS, &CommandStatus);
+
+  return Status;
+}
+
+/**
+
+  Get specific field of HcCommand reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcCommandStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcCOMMAND_STATUS        CommandStatus;
+
+  *(UINT32 *) &CommandStatus = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS);
+
+  switch (Field){
+  case HC_RESET:
+    return CommandStatus.HcReset;
+    break;
+  case CONTROL_LIST_FILLED:
+    return CommandStatus.ControlListFilled;
+    break;
+  case BULK_LIST_FILLED:
+    return CommandStatus.BulkListFilled;
+    break;
+  case CHANGE_OWNER_REQUEST:
+    return CommandStatus.ChangeOwnerRequest;
+    break;
+  case SCHEDULE_OVERRUN_COUNT:
+    return CommandStatus.ScheduleOverrunCount;
+    break;
+  default:
+    ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Clear specific fields of Interrupt Status
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to clear
+
+  @retval EFI_SUCCESS           Fields cleared
+
+**/
+
+EFI_STATUS
+OhciClearInterruptStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  EFI_STATUS              Status;
+  HcINTERRUPT_STATUS      InterruptStatus;
+
+  ZeroMem (&InterruptStatus, sizeof (HcINTERRUPT_STATUS));
+
+  if(Field & SCHEDULE_OVERRUN){
+    InterruptStatus.SchedulingOverrun = 1;
+  }
+
+  if(Field & WRITEBACK_DONE_HEAD){
+    InterruptStatus.WriteBackDone = 1;
+  }
+  if(Field & START_OF_FRAME){
+    InterruptStatus.Sof = 1;
+  }
+
+  if(Field & RESUME_DETECT){
+    InterruptStatus.ResumeDetected = 1;
+  }
+
+  if(Field & UNRECOVERABLE_ERROR){
+    InterruptStatus.UnrecoverableError = 1;
+  }
+
+  if(Field & FRAME_NUMBER_OVERFLOW){
+    InterruptStatus.FrameNumOverflow = 1;
+  }
+
+  if(Field & ROOTHUB_STATUS_CHANGE){
+    InterruptStatus.RHStatusChange = 1;
+  }
+
+  if(Field & OWNERSHIP_CHANGE){
+    InterruptStatus.OwnerChange = 1;
+  }
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_STATUS, &InterruptStatus);
+
+  return Status;
+}
+
+/**
+
+  Get fields of HcInterrupt reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcINTERRUPT_STATUS      InterruptStatus;
+
+  *(UINT32 *) &InterruptStatus = OhciGetOperationalReg (Ohc->PciIo, HC_INTERRUPT_STATUS);
+
+  switch (Field){
+  case SCHEDULE_OVERRUN:
+    return InterruptStatus.SchedulingOverrun;
+    break;
+
+  case  WRITEBACK_DONE_HEAD:
+    return InterruptStatus.WriteBackDone;
+    break;
+
+  case START_OF_FRAME:
+    return InterruptStatus.Sof;
+    break;
+
+  case RESUME_DETECT:
+    return InterruptStatus.ResumeDetected;
+    break;
+
+  case UNRECOVERABLE_ERROR:
+    return InterruptStatus.UnrecoverableError;
+    break;
+
+  case FRAME_NUMBER_OVERFLOW:
+    return InterruptStatus.FrameNumOverflow;
+    break;
+
+  case ROOTHUB_STATUS_CHANGE:
+    return InterruptStatus.RHStatusChange;
+    break;
+
+  case OWNERSHIP_CHANGE:
+    return InterruptStatus.OwnerChange;
+    break;
+
+  default:
+    ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set Interrupt Control reg value
+
+  @param  Ohc                   UHC private data
+  @param  StatEnable            Enable or Disable
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetInterruptControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN BOOLEAN              StatEnable,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcINTERRUPT_CONTROL     InterruptState;
+
+
+  ZeroMem (&InterruptState, sizeof (HcINTERRUPT_CONTROL));
+
+  if(Field & SCHEDULE_OVERRUN) {
+    InterruptState.SchedulingOverrunInt = Value;
+  }
+
+  if(Field & WRITEBACK_DONE_HEAD) {
+    InterruptState.WriteBackDoneInt = Value;
+  }
+  if(Field & START_OF_FRAME) {
+    InterruptState.SofInt = Value;
+  }
+
+  if(Field & RESUME_DETECT) {
+    InterruptState.ResumeDetectedInt = Value;
+  }
+
+  if(Field & UNRECOVERABLE_ERROR) {
+    InterruptState.UnrecoverableErrorInt = Value;
+  }
+
+  if(Field & FRAME_NUMBER_OVERFLOW) {
+    InterruptState.FrameNumOverflowInt = Value;
+  }
+
+  if(Field & ROOTHUB_STATUS_CHANGE) {
+    InterruptState.RHStatusChangeInt = Value;
+  }
+
+  if(Field & OWNERSHIP_CHANGE) {
+    InterruptState.OwnerChangedInt = Value;
+  }
+
+  if(Field & MASTER_INTERRUPT) {
+    InterruptState.MasterInterruptEnable = Value;
+  }
+
+  if (StatEnable) {
+    Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_ENABLE, &InterruptState);
+  } else {
+    Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_DISABLE, &InterruptState);
+  }
+
+  return Status;
+}
+
+/**
+
+  Get field of HcInterruptControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcINTERRUPT_CONTROL     InterruptState;
+
+  *(UINT32 *) &InterruptState = OhciGetOperationalReg (Ohc->PciIo, HC_INTERRUPT_ENABLE);
+
+  switch (Field){
+    case SCHEDULE_OVERRUN:
+      return InterruptState.SchedulingOverrunInt;
+      break;
+
+    case WRITEBACK_DONE_HEAD:
+      return InterruptState.WriteBackDoneInt;
+      break;
+
+    case START_OF_FRAME:
+      return InterruptState.SofInt;
+      break;
+
+    case RESUME_DETECT:
+      return InterruptState.ResumeDetectedInt;
+      break;
+
+    case UNRECOVERABLE_ERROR:
+      return InterruptState.UnrecoverableErrorInt;
+      break;
+
+    case FRAME_NUMBER_OVERFLOW:
+      return InterruptState.FrameNumOverflowInt;
+      break;
+
+    case ROOTHUB_STATUS_CHANGE:
+      return InterruptState.RHStatusChangeInt;
+      break;
+
+    case OWNERSHIP_CHANGE:
+      return InterruptState.OwnerChangedInt;
+      break;
+
+    case MASTER_INTERRUPT:
+      return InterruptState.MasterInterruptEnable;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set memory pointer of specific type
+
+  @param  Ohc                   UHC private data
+  @param  PointerType           Type of the pointer to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Memory pointer set
+
+**/
+
+EFI_STATUS
+OhciSetMemoryPointer(
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               PointerType,
+  IN VOID                 *Value
+  )
+{
+  EFI_STATUS              Status;
+  UINT32                  Verify;
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, PointerType, &Value);
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Verify = OhciGetOperationalReg (Ohc->PciIo, PointerType);
+
+  while (Verify != (UINT32)(UINTN) Value) {
+    gBS->Stall(1000);
+    Verify = OhciGetOperationalReg (Ohc->PciIo, PointerType);
+  };
+
+
+  return Status;
+}
+
+/**
+
+  Get memory pointer of specific type
+
+  @param  Ohc                   UHC private data
+  @param  PointerType           Type of pointer
+
+  @retval                       Memory pointer of the specific type
+
+**/
+
+VOID *
+OhciGetMemoryPointer (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               PointerType
+  )
+{
+
+  return (VOID *)(UINTN) OhciGetOperationalReg (Ohc->PciIo, PointerType);
+}
+
+
+/**
+
+  Set Frame Interval value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameInterval (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcFRM_INTERVAL          FrameInterval;
+
+
+  *(UINT32 *) &FrameInterval = OhciGetOperationalReg(Ohc->PciIo, HC_FRM_INTERVAL);
+
+  if (Field & FRAME_INTERVAL) {
+    FrameInterval.FrmIntervalToggle = !FrameInterval.FrmIntervalToggle;
+    FrameInterval.FrameInterval = Value;
+  }
+
+  if (Field & FS_LARGEST_DATA_PACKET) {
+    FrameInterval.FSMaxDataPacket = Value;
+  }
+
+  if (Field & FRMINT_TOGGLE) {
+    FrameInterval.FrmIntervalToggle = Value;
+  }
+
+  Status = OhciSetOperationalReg (
+             Ohc->PciIo,
+             HC_FRM_INTERVAL,
+             &FrameInterval
+             );
+
+  return Status;
+}
+
+
+/**
+
+  Get field of frame interval reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetFrameInterval (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcFRM_INTERVAL          FrameInterval;
+
+  *(UINT32 *) &FrameInterval = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_INTERVAL);
+
+  switch (Field){
+    case FRAME_INTERVAL:
+      return FrameInterval.FrameInterval;
+      break;
+
+    case FS_LARGEST_DATA_PACKET:
+      return FrameInterval.FSMaxDataPacket;
+      break;
+
+    case FRMINT_TOGGLE:
+      return FrameInterval.FrmIntervalToggle;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set Frame Remaining reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameRemaining (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcFRAME_REMAINING       FrameRemaining;
+
+
+  *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING);
+
+  FrameRemaining.FrameRemaining = Value;
+  FrameRemaining.FrameRemainingToggle = !FrameRemaining.FrameRemainingToggle;
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING, &FrameRemaining);
+
+  return Status;
+}
+/**
+
+  Get value of frame remaining reg
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of frame remaining reg
+
+**/
+UINT32
+OhciGetFrameRemaining (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+
+{
+  HcFRAME_REMAINING       FrameRemaining;
+
+
+  *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING);
+
+  switch (Field){
+    case FRAME_REMAINING:
+      return FrameRemaining.FrameRemaining;
+      break;
+
+    case FRAME_REMAIN_TOGGLE:
+      return FrameRemaining.FrameRemainingToggle;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set frame number reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameNumber(
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_FRM_NUMBER, &Value);
+
+  return Status;
+}
+
+/**
+
+  Get frame number reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of frame number reg
+
+**/
+
+UINT32
+OhciGetFrameNumber (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  return OhciGetOperationalReg(Ohc->PciIo, HC_FRM_NUMBER);
+}
+
+/**
+
+  Set period start reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetPeriodicStart (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_PERIODIC_START, &Value);
+
+  return Status;
+}
+
+
+/**
+
+  Get periodic start reg value
+
+  @param  Ohc                   UHC private data
+
+  @param                        Value of periodic start reg
+
+**/
+
+UINT32
+OhciGetPeriodicStart (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  return OhciGetOperationalReg(Ohc->PciIo, HC_PERIODIC_START);
+}
+
+
+/**
+
+  Set Ls Threshold reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetLsThreshold (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_LS_THREASHOLD, &Value);
+
+  return Status;
+}
+
+
+/**
+
+  Get Ls Threshold reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of Ls Threshold reg
+
+**/
+
+UINT32
+OhciGetLsThreshold (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  return OhciGetOperationalReg(Ohc->PciIo, HC_LS_THREASHOLD);
+}
+
+/**
+
+  Set Root Hub Descriptor reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetRootHubDescriptor (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcRH_DESC_A             DescriptorA;
+  HcRH_DESC_B             DescriptorB;
+
+
+  if (Field & (RH_DEV_REMOVABLE | RH_PORT_PWR_CTRL_MASK)) {
+    *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_B);
+
+    if(Field & RH_DEV_REMOVABLE) {
+      DescriptorB.DeviceRemovable = Value;
+    }
+    if(Field & RH_PORT_PWR_CTRL_MASK) {
+      DescriptorB.PortPowerControlMask = Value;
+    }
+
+    Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_DESC_B, &DescriptorB);
+
+    return Status;
+  }
+
+  *(UINT32 *)&DescriptorA = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_A);
+
+  if(Field & RH_NUM_DS_PORTS) {
+    DescriptorA.NumDownStrmPorts = Value;
+  }
+  if(Field & RH_NO_PSWITCH) {
+    DescriptorA.NoPowerSwitch = Value;
+  }
+  if(Field & RH_PSWITCH_MODE) {
+    DescriptorA.PowerSwitchMode = Value;
+  }
+  if(Field & RH_DEVICE_TYPE) {
+    DescriptorA.DeviceType = Value;
+  }
+  if(Field & RH_OC_PROT_MODE) {
+    DescriptorA.OverCurrentProtMode = Value;
+  }
+  if(Field & RH_NOC_PROT) {
+    DescriptorA.NoOverCurrentProtMode = Value;
+  }
+  if(Field & RH_NO_POTPGT) {
+    DescriptorA.PowerOnToPowerGoodTime = Value;
+  }
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_DESC_A, &DescriptorA);
+
+  return Status;
+}
+
+
+/**
+
+  Get Root Hub Descriptor reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubDescriptor (
+  IN USB_OHCI_HC_DEV     *Ohc,
+  IN UINTN               Field
+  )
+{
+  HcRH_DESC_A             DescriptorA;
+  HcRH_DESC_B             DescriptorB;
+
+
+  *(UINT32 *) &DescriptorA = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_A);
+  *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_B);
+
+  switch (Field){
+    case RH_DEV_REMOVABLE:
+      return DescriptorB.DeviceRemovable;
+      break;
+
+    case RH_PORT_PWR_CTRL_MASK:
+      return DescriptorB.PortPowerControlMask;
+      break;
+
+    case RH_NUM_DS_PORTS:
+      return DescriptorA.NumDownStrmPorts;
+      break;
+
+    case RH_NO_PSWITCH:
+      return DescriptorA.NoPowerSwitch;
+      break;
+
+    case RH_PSWITCH_MODE:
+      return DescriptorA.PowerSwitchMode;
+      break;
+
+    case RH_DEVICE_TYPE:
+      return DescriptorA.DeviceType;
+      break;
+
+    case RH_OC_PROT_MODE:
+      return DescriptorA.OverCurrentProtMode;
+      break;
+
+    case RH_NOC_PROT:
+      return DescriptorA.NoOverCurrentProtMode;
+      break;
+
+    case RH_NO_POTPGT:
+      return DescriptorA.PowerOnToPowerGoodTime;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+
+/**
+
+  Set Root Hub Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  EFI_STATUS              Status;
+  HcRH_STATUS             RootHubStatus;
+
+
+  ZeroMem (&RootHubStatus, sizeof(HcRH_STATUS));
+
+  if(Field & RH_LOCAL_PSTAT){
+    RootHubStatus.LocalPowerStat = 1;
+  }
+  if(Field & RH_OC_ID){
+    RootHubStatus.OverCurrentIndicator = 1;
+  }
+  if(Field & RH_REMOTE_WK_ENABLE){
+    RootHubStatus.DevRemoteWakeupEnable = 1;
+  }
+  if(Field & RH_LOCAL_PSTAT_CHANGE){
+    RootHubStatus.LocalPowerStatChange = 1;
+  }
+  if(Field & RH_OC_ID_CHANGE){
+    RootHubStatus.OverCurrentIndicatorChange = 1;
+  }
+  if(Field & RH_CLR_RMT_WK_ENABLE){
+    RootHubStatus.ClearRemoteWakeupEnable = 1;
+  }
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_STATUS, &RootHubStatus);
+
+  return Status;
+}
+
+
+/**
+
+  Get Root Hub Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcRH_STATUS             RootHubStatus;
+
+
+  *(UINT32 *) &RootHubStatus = OhciGetOperationalReg (Ohc->PciIo, HC_RH_STATUS);
+
+  switch (Field) {
+    case RH_LOCAL_PSTAT:
+      return RootHubStatus.LocalPowerStat;
+      break;
+    case RH_OC_ID:
+      return RootHubStatus.OverCurrentIndicator;
+      break;
+    case RH_REMOTE_WK_ENABLE:
+      return RootHubStatus.DevRemoteWakeupEnable;
+      break;
+    case RH_LOCAL_PSTAT_CHANGE:
+      return RootHubStatus.LocalPowerStatChange;
+      break;
+    case RH_OC_ID_CHANGE:
+      return RootHubStatus.OverCurrentIndicatorChange;
+      break;
+    case RH_CLR_RMT_WK_ENABLE:
+      return RootHubStatus.ClearRemoteWakeupEnable;
+      break;
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+
+/**
+
+  Set Root Hub Port Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Index                 Index of the port
+  @param  Field                 Field to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubPortStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Index,
+  IN UINTN                Field
+  )
+{
+  EFI_STATUS              Status;
+  HcRHPORT_STATUS         PortStatus;
+
+
+  ZeroMem (&PortStatus, sizeof(HcRHPORT_STATUS));
+
+  if (Field & RH_CLEAR_PORT_ENABLE) {
+    PortStatus.CurrentConnectStat = 1;
+  }
+  if (Field & RH_SET_PORT_ENABLE) {
+    PortStatus.EnableStat = 1;
+  }
+  if (Field & RH_SET_PORT_SUSPEND) {
+    PortStatus.SuspendStat = 1;
+  }
+  if (Field & RH_CLEAR_SUSPEND_STATUS) {
+    PortStatus.OCIndicator = 1;
+  }
+  if (Field & RH_SET_PORT_RESET) {
+    PortStatus.ResetStat = 1;
+  }
+  if (Field & RH_SET_PORT_POWER) {
+    PortStatus.PowerStat = 1;
+  }
+  if (Field & RH_CLEAR_PORT_POWER) {
+    PortStatus.LsDeviceAttached = 1;
+  }
+  if (Field & RH_CONNECT_STATUS_CHANGE) {
+    PortStatus.ConnectStatChange = 1;
+  }
+  if (Field & RH_PORT_ENABLE_STAT_CHANGE) {
+    PortStatus.EnableStatChange = 1;
+  }
+  if (Field & RH_PORT_SUSPEND_STAT_CHANGE) {
+    PortStatus.SuspendStatChange = 1;
+  }
+  if (Field & RH_OC_INDICATOR_CHANGE) {
+    PortStatus.OCIndicatorChange = 1;
+  }
+  if (Field & RH_PORT_RESET_STAT_CHANGE ) {
+    PortStatus.ResetStatChange = 1;
+  }
+
+  Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_PORT_STATUS + (Index * 4), &PortStatus);
+
+  return Status;
+}
+
+
+/**
+
+  Get Root Hub Port Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Index                 Index of the port
+  @param  Field                 Field to get
+
+  @retval                       Value of the field and index
+
+**/
+
+UINT32
+OhciReadRootHubPortStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Index,
+  IN UINTN                Field
+  )
+{
+  HcRHPORT_STATUS         PortStatus;
+
+  *(UINT32 *) &PortStatus = OhciGetOperationalReg (
+                              Ohc->PciIo,
+                              HC_RH_PORT_STATUS + (Index * 4)
+                              );
+
+  switch (Field){
+  case RH_CURR_CONNECT_STAT:
+    return PortStatus.CurrentConnectStat;
+    break;
+  case RH_PORT_ENABLE_STAT:
+    return PortStatus.EnableStat;
+    break;
+  case RH_PORT_SUSPEND_STAT:
+    return PortStatus.SuspendStat;
+    break;
+  case RH_PORT_OC_INDICATOR:
+    return PortStatus.OCIndicator;
+    break;
+  case RH_PORT_RESET_STAT:
+    return PortStatus.ResetStat;
+    break;
+  case RH_PORT_POWER_STAT:
+    return PortStatus.PowerStat;
+    break;
+  case RH_LSDEVICE_ATTACHED:
+    return PortStatus.LsDeviceAttached;
+    break;
+  case RH_CONNECT_STATUS_CHANGE:
+    return PortStatus.ConnectStatChange;
+    break;
+  case RH_PORT_ENABLE_STAT_CHANGE:
+    return PortStatus.EnableStatChange;
+    break;
+  case RH_PORT_SUSPEND_STAT_CHANGE:
+    return PortStatus.SuspendStatChange;
+    break;
+  case RH_OC_INDICATOR_CHANGE:
+    return PortStatus.OCIndicatorChange;
+    break;
+  case RH_PORT_RESET_STAT_CHANGE:
+    return PortStatus.ResetStatChange;
+    break;
+  default:
+    ASSERT (FALSE);
+  }
+
+  return 0;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h
new file mode 100644
index 0000000000..e4d1008053
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h
@@ -0,0 +1,920 @@
+/** @file
+This file contains the definination for host controller
+register operation routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#ifndef   _OHCI_REG_H
+#define   _OHCI_REG_H
+
+#define   HC_STATE_RESET         0x0
+#define   HC_STATE_RESUME        0x1
+#define   HC_STATE_OPERATIONAL   0x2
+#define   HC_STATE_SUSPEND       0x3
+
+#define   PERIODIC_ENABLE               0x01
+#define   ISOCHRONOUS_ENABLE            0x02
+#define   CONTROL_ENABLE                0x04
+#define   BULK_ENABLE                   0x08
+#define   CONTROL_BULK_RATIO            0x10
+
+#define   HC_FUNCTIONAL_STATE    0x20
+#define   INTERRUPT_ROUTING      0x40
+
+#define   HC_RESET               0x01
+#define   CONTROL_LIST_FILLED    0x02
+#define   BULK_LIST_FILLED       0x04
+#define   CHANGE_OWNER_REQUEST   0x08
+
+#define   SCHEDULE_OVERRUN_COUNT 0x10
+
+#define   SCHEDULE_OVERRUN       0x00001
+#define   WRITEBACK_DONE_HEAD    0x00002
+#define   START_OF_FRAME         0x00004
+#define   RESUME_DETECT          0x00008
+#define   UNRECOVERABLE_ERROR    0x00010
+#define   FRAME_NUMBER_OVERFLOW  0x00020
+#define   ROOTHUB_STATUS_CHANGE  0x00040
+#define   OWNERSHIP_CHANGE       0x00080
+
+#define   MASTER_INTERRUPT       0x00400
+
+#define   CONTROL_HEAD           0x001
+#define   BULK_HEAD              0x002
+#define   DONE_HEAD              0x004
+
+#define   Hc_HCCA                0x001
+#define   Hc_PERIODIC_CURRENT    0x002
+#define   Hc_CONTOL_HEAD         0x004
+#define   Hc_CONTROL_CURRENT_PTR 0x008
+#define   Hc_BULK_HEAD           0x010
+#define   Hc_BULK_CURRENT_PTR    0x020
+#define   Hc_DONE_HEAD           0x040
+
+#define   FRAME_INTERVAL         0x008
+#define   FS_LARGEST_DATA_PACKET 0x010
+#define   FRMINT_TOGGLE          0x020
+#define   FRAME_REMAINING        0x040
+#define   FRAME_REMAIN_TOGGLE    0x080
+
+#define   RH_DESC_A              0x00001
+#define   RH_DESC_B              0x00002
+#define   RH_NUM_DS_PORTS        0x00004
+#define   RH_NO_PSWITCH          0x00008
+#define   RH_PSWITCH_MODE        0x00010
+#define   RH_DEVICE_TYPE         0x00020
+#define   RH_OC_PROT_MODE        0x00040
+#define   RH_NOC_PROT            0x00080
+#define   RH_POTPGT              0x00100
+#define   RH_NO_POTPGT           0x00200
+#define   RH_DEV_REMOVABLE       0x00400
+#define   RH_PORT_PWR_CTRL_MASK  0x00800
+
+#define   RH_LOCAL_PSTAT         0x00001
+#define   RH_OC_ID               0x00002
+#define   RH_REMOTE_WK_ENABLE    0x00004
+#define   RH_LOCAL_PSTAT_CHANGE  0x00008
+#define   RH_OC_ID_CHANGE        0x00010
+#define   RH_CLR_RMT_WK_ENABLE   0x00020
+
+#define   RH_CLEAR_PORT_ENABLE        0x0001
+#define   RH_SET_PORT_ENABLE          0x0002
+#define   RH_SET_PORT_SUSPEND         0x0004
+#define   RH_CLEAR_SUSPEND_STATUS     0x0008
+#define   RH_SET_PORT_RESET           0x0010
+#define   RH_SET_PORT_POWER           0x0020
+#define   RH_CLEAR_PORT_POWER         0x0040
+#define   RH_CONNECT_STATUS_CHANGE    0x10000
+#define   RH_PORT_ENABLE_STAT_CHANGE  0x20000
+#define   RH_PORT_SUSPEND_STAT_CHANGE 0x40000
+#define   RH_OC_INDICATOR_CHANGE      0x80000
+#define   RH_PORT_RESET_STAT_CHANGE   0x100000
+
+#define   RH_CURR_CONNECT_STAT        0x0001
+#define   RH_PORT_ENABLE_STAT         0x0002
+#define   RH_PORT_SUSPEND_STAT        0x0004
+#define   RH_PORT_OC_INDICATOR        0x0008
+#define   RH_PORT_RESET_STAT          0x0010
+#define   RH_PORT_POWER_STAT          0x0020
+#define   RH_LSDEVICE_ATTACHED        0x0040
+
+#define   RESET_SYSTEM_BUS            (1 << 0)
+#define   RESET_HOST_CONTROLLER       (1 << 1)
+#define   RESET_CLOCK_GENERATION      (1 << 2)
+#define   RESET_SSE_GLOBAL            (1 << 5)
+#define   RESET_PSPL                  (1 << 6)
+#define   RESET_PCPL                  (1 << 7)
+#define   RESET_SSEP1                 (1 << 9)
+#define   RESET_SSEP2                 (1 << 10)
+#define   RESET_SSEP3                 (1 << 11)
+
+#define ONE_SECOND                      1000000
+#define ONE_MILLI_SEC                   1000
+#define MAX_BYTES_PER_TD                0x1000
+#define MAX_RETRY_TIMES                 100
+#define PORT_NUMBER_ON_MAINSTONE2       1
+
+
+//
+// Operational Register Offsets
+//
+
+//
+// Command & Status Registers Offsets
+//
+#define HC_REVISION             0x00
+#define HC_CONTROL              0x04
+#define HC_COMMAND_STATUS       0x08
+#define HC_INTERRUPT_STATUS     0x0C
+#define HC_INTERRUPT_ENABLE     0x10
+#define HC_INTERRUPT_DISABLE    0x14
+
+//
+// Memory Pointer Offsets
+//
+#define HC_HCCA                 0x18
+#define HC_PERIODIC_CURRENT     0x1C
+#define HC_CONTROL_HEAD         0x20
+#define HC_CONTROL_CURRENT_PTR  0x24
+#define HC_BULK_HEAD            0x28
+#define HC_BULK_CURRENT_PTR     0x2C
+#define HC_DONE_HEAD            0x30
+
+//
+// Frame Register Offsets
+//
+#define HC_FRM_INTERVAL         0x34
+#define HC_FRM_REMAINING        0x38
+#define HC_FRM_NUMBER           0x3C
+#define HC_PERIODIC_START       0x40
+#define HC_LS_THREASHOLD        0x44
+
+//
+// Root Hub Register Offsets
+//
+#define HC_RH_DESC_A            0x48
+#define HC_RH_DESC_B            0x4C
+#define HC_RH_STATUS            0x50
+#define HC_RH_PORT_STATUS       0x54
+
+#define USBHOST_OFFSET_UHCHR         0x64         // Usb Host reset register
+
+#define OHC_BAR_INDEX               0
+
+//
+// Usb Host controller register offset
+//
+#define USBHOST_OFFSET_UHCREV        0x0          // Usb Host revision register
+#define USBHOST_OFFSET_UHCHCON       0x4          // Usb Host control register
+#define USBHOST_OFFSET_UHCCOMS       0x8          // Usb Host Command Status register
+#define USBHOST_OFFSET_UHCINTS       0xC          // Usb Host Interrupt Status register
+#define USBHOST_OFFSET_UHCINTE       0x10         // Usb Host Interrupt Enable register
+#define USBHOST_OFFSET_UHCINTD       0x14         // Usb Host Interrupt Disable register
+#define USBHOST_OFFSET_UHCHCCA       0x18         // Usb Host Controller Communication Area
+#define USBHOST_OFFSET_UHCPCED       0x1C         // Usb Host Period Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCCHED       0x20         // Usb Host Control Head Endpoint Descriptor
+#define USBHOST_OFFSET_UHCCCED       0x24         // Usb Host Control Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCBHED       0x28         // Usb Host Bulk Head Endpoint Descriptor
+#define USBHOST_OFFSET_UHCBCED       0x2C         // Usb Host Bulk Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCDHEAD      0x30         // Usb Host Done Head register
+#define USBHOST_OFFSET_UHCFMI        0x34         // Usb Host Frame Interval register
+#define USBHOST_OFFSET_UHCFMR        0x38         // Usb Host Frame Remaining register
+#define USBHOST_OFFSET_UHCFMN        0x3C         // Usb Host Frame Number register
+#define USBHOST_OFFSET_UHCPERS       0x40         // Usb Host Periodic Start register
+#define USBHOST_OFFSET_UHCLST        0x44         // Usb Host Low-Speed Threshold register
+#define USBHOST_OFFSET_UHCRHDA       0x48         // Usb Host Root Hub Descriptor A register
+#define USBHOST_OFFSET_UHCRHDB       0x4C         // Usb Host Root Hub Descriptor B register
+#define USBHOST_OFFSET_UHCRHS        0x50         // Usb Host Root Hub Status register
+#define USBHOST_OFFSET_UHCRHPS1      0x54         // Usb Host Root Hub Port Status 1 register
+
+//
+// Usb Host controller register bit fields
+//
+#pragma pack(1)
+
+typedef struct {
+  UINT8                   ProgInterface;
+  UINT8                   SubClassCode;
+  UINT8                   BaseCode;
+} USB_CLASSC;
+
+typedef struct {
+    UINT32 Revision:8;
+    UINT32 Rsvd:24;
+} HcREVISION;
+
+typedef struct {
+    UINT32 ControlBulkRatio:2;
+    UINT32 PeriodicEnable:1;
+    UINT32 IsochronousEnable:1;
+    UINT32 ControlEnable:1;
+    UINT32 BulkEnable:1;
+    UINT32 FunctionalState:2;
+    UINT32 InterruptRouting:1;
+    UINT32 RemoteWakeup:1;
+    UINT32 RemoteWakeupEnable:1;
+    UINT32 Reserved:21;
+} HcCONTROL;
+
+typedef struct {
+    UINT32 HcReset:1;
+    UINT32 ControlListFilled:1;
+    UINT32 BulkListFilled:1;
+    UINT32 ChangeOwnerRequest:1;
+    UINT32 Reserved1:12;
+    UINT32 ScheduleOverrunCount:2;
+    UINT32 Reserved:14;
+} HcCOMMAND_STATUS;
+
+typedef struct {
+    UINT32 SchedulingOverrun:1;
+    UINT32 WriteBackDone:1;
+    UINT32 Sof:1;
+    UINT32 ResumeDetected:1;
+    UINT32 UnrecoverableError:1;
+    UINT32 FrameNumOverflow:1;
+    UINT32 RHStatusChange:1;
+    UINT32 Reserved1:23;
+    UINT32 OwnerChange:1;
+    UINT32 Reserved2:1;
+} HcINTERRUPT_STATUS;
+
+typedef struct {
+    UINT32 SchedulingOverrunInt:1;
+    UINT32 WriteBackDoneInt:1;
+    UINT32 SofInt:1;
+    UINT32 ResumeDetectedInt:1;
+    UINT32 UnrecoverableErrorInt:1;
+    UINT32 FrameNumOverflowInt:1;
+    UINT32 RHStatusChangeInt:1;
+    UINT32 Reserved:23;
+    UINT32 OwnerChangedInt:1;
+    UINT32 MasterInterruptEnable:1;
+} HcINTERRUPT_CONTROL;
+
+typedef struct {
+    UINT32 Rerserved:8;
+    UINT32 Hcca:24;
+} HcHCCA;
+
+typedef struct {
+    UINT32 Reserved:4;
+    UINT32 MemoryPtr:28;
+} HcMEMORY_PTR;
+
+typedef struct {
+    UINT32 FrameInterval:14;
+    UINT32 Reserved:2;
+    UINT32 FSMaxDataPacket:15;
+    UINT32 FrmIntervalToggle:1;
+} HcFRM_INTERVAL;
+
+typedef struct {
+    UINT32 FrameRemaining:14;
+    UINT32 Reserved:17;
+    UINT32 FrameRemainingToggle:1;
+} HcFRAME_REMAINING;
+
+typedef struct {
+    UINT32 FrameNumber:16;
+    UINT32 Reserved:16;
+} HcFRAME_NUMBER;
+
+typedef struct {
+    UINT32 PeriodicStart:14;
+    UINT32 Reserved:18;
+} HcPERIODIC_START;
+
+typedef struct {
+    UINT32 LsThreshold:12;
+    UINT32 Reserved:20;
+} HcLS_THRESHOLD;
+
+typedef struct {
+    UINT32 NumDownStrmPorts:8;
+    UINT32 PowerSwitchMode:1;
+    UINT32 NoPowerSwitch:1;
+    UINT32 DeviceType:1;
+    UINT32 OverCurrentProtMode:1;
+    UINT32 NoOverCurrentProtMode:1;
+    UINT32 Reserved:11;
+    UINT32 PowerOnToPowerGoodTime:8;
+} HcRH_DESC_A;
+
+typedef struct {
+    UINT32 DeviceRemovable:16;
+    UINT32 PortPowerControlMask:16;
+} HcRH_DESC_B;
+
+typedef struct {
+    UINT32 LocalPowerStat:1;
+    UINT32 OverCurrentIndicator:1;
+    UINT32 Reserved1:13;
+    UINT32 DevRemoteWakeupEnable:1;
+    UINT32 LocalPowerStatChange:1;
+    UINT32 OverCurrentIndicatorChange:1;
+    UINT32 Reserved2:13;
+    UINT32 ClearRemoteWakeupEnable:1;
+} HcRH_STATUS;
+
+typedef struct {
+    UINT32 CurrentConnectStat:1;
+    UINT32 EnableStat:1;
+    UINT32 SuspendStat:1;
+    UINT32 OCIndicator:1;
+    UINT32 ResetStat:1;
+    UINT32 Reserved1:3;
+    UINT32 PowerStat:1;
+    UINT32 LsDeviceAttached:1;
+    UINT32 Reserved2:6;
+    UINT32 ConnectStatChange:1;
+    UINT32 EnableStatChange:1;
+    UINT32 SuspendStatChange:1;
+    UINT32 OCIndicatorChange:1;
+    UINT32 ResetStatChange:1;
+    UINT32 Reserved3:11;
+} HcRHPORT_STATUS;
+
+typedef struct {
+    UINT32 FSBIR:1;
+    UINT32 FHR:1;
+    UINT32 CGR:1;
+    UINT32 SSDC:1;
+    UINT32 UIT:1;
+    UINT32 SSE:1;
+    UINT32 PSPL:1;
+    UINT32 PCPL:1;
+    UINT32 Reserved0:1;
+    UINT32 SSEP1:1;
+    UINT32 SSEP2:1;
+    UINT32 SSEP3:1;
+    UINT32 Reserved1:20;
+} HcRESET;
+
+
+#pragma pack()
+
+//
+// Func List
+//
+
+
+/**
+
+  Get OHCI operational reg value
+
+  @param  PciIo                 PciIo protocol instance
+  @param  Offset                Offset of the operational reg
+
+  @retval                       Value of the register
+
+**/
+UINT32
+OhciGetOperationalReg (
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN UINT32               Offset
+  );
+
+/**
+
+  Set OHCI operational reg value
+
+  @param  PciIo                  PCI Bus Io protocol instance
+  @param  Offset                 Offset of the operational reg
+  @param  Value                  Value to set
+
+  @retval EFI_SUCCESS            Value set to the reg
+
+**/
+
+
+EFI_STATUS
+OhciSetOperationalReg (
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN UINT32               Offset,
+  IN VOID                 *Value
+  );
+
+
+/**
+
+  Get HcRevision reg value
+
+  @param  PciIo                 PCI Bus Io protocol instance
+
+  @retval                       Value of the register
+
+**/
+
+
+UINT32
+OhciGetHcRevision (
+  IN EFI_PCI_IO_PROTOCOL  *PciIo
+  );
+
+/**
+
+  Set HcReset reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcReset (
+  IN USB_OHCI_HC_DEV            *Ohc,
+  IN UINT32                     Field,
+  IN UINT32                     Value
+  );
+/**
+
+  Get specific field of HcReset reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcReset (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Field
+  );
+/**
+
+  Set HcControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+
+
+/**
+
+  Get specific field of HcControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+
+UINT32
+OhciGetHcControl (
+  IN USB_OHCI_HC_DEV   *Ohc,
+  IN UINTN             Field
+  );
+
+
+/**
+
+  Set HcCommand reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcCommandStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+
+/**
+
+  Get specific field of HcCommand reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcCommandStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+
+/**
+
+  Clear specific fields of Interrupt Status
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to clear
+
+  @retval EFI_SUCCESS           Fields cleared
+
+**/
+
+EFI_STATUS
+OhciClearInterruptStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+
+/**
+
+  Get fields of HcInterrupt reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+
+/**
+
+  Set Interrupt Control reg value
+
+  @param  Ohc                   UHC private data
+  @param  StatEnable            Enable or Disable
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetInterruptControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN BOOLEAN              StatEnable,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+
+/**
+
+  Get field of HcInterruptControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+
+
+/**
+
+  Set memory pointer of specific type
+
+  @param  Ohc                   UHC private data
+  @param  PointerType           Type of the pointer to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Memory pointer set
+
+**/
+
+EFI_STATUS
+OhciSetMemoryPointer(
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               PointerType,
+  IN VOID                 *Value
+  );
+
+/**
+
+  Get memory pointer of specific type
+
+  @param  Ohc                   UHC private data
+  @param  PointerType           Type of pointer
+
+  @retval                       Memory pointer of the specific type
+
+**/
+
+VOID *
+OhciGetMemoryPointer (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               PointerType
+  );
+
+/**
+
+  Set Frame Interval value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameInterval (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+
+
+/**
+
+  Get field of frame interval reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetFrameInterval (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+
+
+/**
+
+  Set Frame Remaining reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameRemaining (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  );
+
+/**
+
+  Get value of frame remaining reg
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of frame remaining reg
+
+**/
+UINT32
+OhciGetFrameRemaining (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+
+/**
+
+  Set frame number reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameNumber(
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  );
+
+/**
+
+  Get frame number reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of frame number reg
+
+**/
+
+UINT32
+OhciGetFrameNumber (
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+
+
+/**
+
+  Set period start reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetPeriodicStart (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  );
+
+
+/**
+
+  Get periodic start reg value
+
+  @param  Ohc                   UHC private data
+
+  @param                        Value of periodic start reg
+
+**/
+
+UINT32
+OhciGetPeriodicStart (
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+
+
+/**
+
+  Set Ls Threshold reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetLsThreshold (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  );
+
+/**
+
+  Get Ls Threshold reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of Ls Threshold reg
+
+**/
+
+UINT32
+OhciGetLsThreshold (
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+
+/**
+
+  Set Root Hub Descriptor reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetRootHubDescriptor (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+
+
+/**
+
+  Get Root Hub Descriptor reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubDescriptor (
+  IN USB_OHCI_HC_DEV     *Ohc,
+  IN UINTN               Field
+  );
+
+/**
+
+  Set Root Hub Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+
+
+/**
+
+  Get Root Hub Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+
+
+/**
+
+  Set Root Hub Port Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Index                 Index of the port
+  @param  Field                 Field to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubPortStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Index,
+  IN UINTN                Field
+  );
+
+
+/**
+
+  Get Root Hub Port Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Index                 Index of the port
+  @param  Field                 Field to get
+
+  @retval                       Value of the field and index
+
+**/
+
+UINT32
+OhciReadRootHubPortStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Index,
+  IN UINTN                Field
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c
new file mode 100644
index 0000000000..d49b5ec9ad
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c
@@ -0,0 +1,528 @@
+/** @file
+OHCI transfer scheduling routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ohci.h"
+
+/**
+
+  Add an item of interrupt context
+
+  @param  Ohc                   UHC private data
+  @param  NewEntry              New entry to add
+
+  @retval EFI_SUCCESS           Item successfully added
+
+**/
+EFI_STATUS
+OhciAddInterruptContextEntry (
+  IN  USB_OHCI_HC_DEV          *Ohc,
+  IN  INTERRUPT_CONTEXT_ENTRY  *NewEntry
+  )
+{
+  INTERRUPT_CONTEXT_ENTRY  *Entry;
+  EFI_TPL                  OriginalTPL;
+
+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+  if (Ohc->InterruptContextList == NULL) {
+    Ohc->InterruptContextList = NewEntry;
+  } else {
+    Entry = Ohc->InterruptContextList;
+    while (Entry->NextEntry != NULL) {
+      Entry = Entry->NextEntry;
+    }
+    Entry->NextEntry = NewEntry;
+  }
+
+  gBS->RestoreTPL (OriginalTPL);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Free a interrupt context entry
+
+  @param  Ohc                   UHC private data
+  @param  Entry                 Pointer to an interrupt context entry
+
+  @retval EFI_SUCCESS           Entry freed
+  @retval EFI_INVALID_PARAMETER Entry is NULL
+
+**/
+EFI_STATUS
+OhciFreeInterruptContextEntry (
+  IN USB_OHCI_HC_DEV          *Ohc,
+  IN INTERRUPT_CONTEXT_ENTRY  *Entry
+  )
+{
+  TD_DESCRIPTOR           *Td;
+  if (Entry == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  if (Entry->UCBufferMapping != NULL) {
+    Ohc->PciIo->Unmap(Ohc->PciIo, Entry->UCBufferMapping);
+  }
+  if (Entry->UCBuffer != NULL) {
+    FreePool(Entry->UCBuffer);
+  }
+  while (Entry->DataTd) {
+    Td = Entry->DataTd;
+    Entry->DataTd = (TD_DESCRIPTOR *)(UINTN)(Entry->DataTd->NextTDPointer);
+    UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));
+  }
+  FreePool(Entry);
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Free entries match the device address and endpoint address
+
+  @Param  Ohc                   UHC private date
+  @Param  DeviceAddress         Item to free must match this device address
+  @Param  EndPointAddress       Item to free must match this end point address
+  @Param  DataToggle            DataToggle for output
+
+  @retval  EFI_SUCCESS          Items match the requirement removed
+
+**/
+EFI_STATUS
+OhciFreeInterruptContext(
+  IN  USB_OHCI_HC_DEV     *Ohc,
+  IN  UINT8               DeviceAddress,
+  IN  UINT8               EndPointAddress,
+  OUT UINT8               *DataToggle
+  )
+{
+  INTERRUPT_CONTEXT_ENTRY  *Entry;
+  INTERRUPT_CONTEXT_ENTRY  *TempEntry;
+  EFI_TPL                  OriginalTPL;
+
+
+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+  while (Ohc->InterruptContextList != NULL &&
+    Ohc->InterruptContextList->DeviceAddress == DeviceAddress &&
+    Ohc->InterruptContextList->EndPointAddress == EndPointAddress) {
+    TempEntry = Ohc->InterruptContextList;
+    Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry;
+    if (DataToggle != NULL) {
+      *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1);
+    }
+    OhciFreeInterruptContextEntry (Ohc, TempEntry);
+  }
+
+  Entry = Ohc->InterruptContextList;
+  if (Entry == NULL) {
+    gBS->RestoreTPL (OriginalTPL);
+    return EFI_SUCCESS;
+  }
+  while (Entry->NextEntry != NULL) {
+    if (Entry->NextEntry->DeviceAddress == DeviceAddress &&
+      Entry->NextEntry->EndPointAddress == EndPointAddress) {
+      TempEntry = Entry->NextEntry;
+      Entry->NextEntry = Entry->NextEntry->NextEntry;
+      if (DataToggle != NULL) {
+        *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1);
+      }
+      OhciFreeInterruptContextEntry (Ohc, TempEntry);
+    } else {
+      Entry = Entry->NextEntry;
+    }
+  }
+
+  gBS->RestoreTPL (OriginalTPL);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Convert Error code from OHCI format to EFI format
+
+  @Param  ErrorCode             ErrorCode in OHCI format
+
+  @retval                       ErrorCode in EFI format
+
+**/
+UINT32
+ConvertErrorCode (
+  IN  UINT32              ErrorCode
+  )
+{
+  UINT32                  TransferResult;
+
+  switch (ErrorCode) {
+    case TD_NO_ERROR:
+      TransferResult = EFI_USB_NOERROR;
+      break;
+
+    case TD_TOBE_PROCESSED:
+    case TD_TOBE_PROCESSED_2:
+      TransferResult = EFI_USB_ERR_NOTEXECUTE;
+      break;
+
+    case TD_DEVICE_STALL:
+      TransferResult = EFI_USB_ERR_STALL;
+      break;
+
+    case TD_BUFFER_OVERRUN:
+    case TD_BUFFER_UNDERRUN:
+      TransferResult = EFI_USB_ERR_BUFFER;
+      break;
+
+    case TD_CRC_ERROR:
+      TransferResult = EFI_USB_ERR_CRC;
+      break;
+
+    case TD_NO_RESPONSE:
+      TransferResult = EFI_USB_ERR_TIMEOUT;
+      break;
+
+    case TD_BITSTUFFING_ERROR:
+      TransferResult = EFI_USB_ERR_BITSTUFF;
+      break;
+
+    default:
+      TransferResult = EFI_USB_ERR_SYSTEM;
+  }
+
+  return TransferResult;
+}
+
+
+/**
+
+  Check TDs Results
+
+  @Param  Ohc                   UHC private data
+  @Param  Td                    TD_DESCRIPTOR
+  @Param  Result                Result to return
+
+  @retval TRUE                  means OK
+  @retval FLASE                 means Error or Short packet
+
+**/
+BOOLEAN
+OhciCheckTDsResults (
+  IN  USB_OHCI_HC_DEV     *Ohc,
+  IN  TD_DESCRIPTOR       *Td,
+  OUT UINT32              *Result
+  )
+{
+  UINT32                  TdCompletionCode;
+
+  *Result   = EFI_USB_NOERROR;
+
+  while (Td) {
+    TdCompletionCode = Td->Word0.ConditionCode;
+
+    *Result |= ConvertErrorCode(TdCompletionCode);
+    //
+    // if any error encountered, stop processing the left TDs.
+    //
+    if (*Result) {
+      return FALSE;
+    }
+
+    Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer);
+  }
+  return TRUE;
+
+}
+
+
+/**
+
+  Check the task status on an ED
+
+  @Param  Ed                    Pointer to the ED task that TD hooked on
+  @Param  HeadTd                TD header for current transaction
+
+  @retval                       Task Status Code
+
+**/
+
+UINT32
+CheckEDStatus (
+  IN  ED_DESCRIPTOR       *Ed,
+  IN  TD_DESCRIPTOR       *HeadTd,
+  OUT OHCI_ED_RESULT      *EdResult
+  )
+{
+  while(HeadTd != NULL) {
+    if (HeadTd->NextTDPointer == 0) {
+      return TD_NO_ERROR;
+    }
+    if (HeadTd->Word0.ConditionCode != 0) {
+      return HeadTd->Word0.ConditionCode;
+    }
+    EdResult->NextToggle = ((UINT8)(HeadTd->Word0.DataToggle) & BIT0) ^ BIT0;
+    HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);
+  }
+  if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) {
+    return TD_TOBE_PROCESSED;
+  }
+  return TD_NO_ERROR;
+}
+
+/**
+
+  Check the task status
+
+  @Param  Ohc                   UHC private data
+  @Param  ListType              Pipe type
+  @Param  Ed                    Pointer to the ED task hooked on
+  @Param  HeadTd                Head of TD corresponding to the task
+  @Param  ErrorCode             return the ErrorCode
+
+  @retval  EFI_SUCCESS          Task done
+  @retval  EFI_NOT_READY        Task on processing
+  @retval  EFI_DEVICE_ERROR     Some error occured
+
+**/
+EFI_STATUS
+CheckIfDone (
+  IN  USB_OHCI_HC_DEV       *Ohc,
+  IN  DESCRIPTOR_LIST_TYPE  ListType,
+  IN  ED_DESCRIPTOR         *Ed,
+  IN  TD_DESCRIPTOR         *HeadTd,
+  OUT OHCI_ED_RESULT        *EdResult
+  )
+{
+  EdResult->ErrorCode = TD_TOBE_PROCESSED;
+
+  switch (ListType) {
+    case CONTROL_LIST:
+      if (OhciGetHcCommandStatus (Ohc, CONTROL_LIST_FILLED) != 0) {
+        return EFI_NOT_READY;
+      }
+      break;
+    case BULK_LIST:
+      if (OhciGetHcCommandStatus (Ohc, BULK_LIST_FILLED) != 0) {
+        return EFI_NOT_READY;
+      }
+      break;
+    default:
+      break;
+  }
+
+  EdResult->ErrorCode = CheckEDStatus (Ed, HeadTd, EdResult);
+
+  if (EdResult->ErrorCode == TD_NO_ERROR) {
+    return EFI_SUCCESS;
+  } else if (EdResult->ErrorCode == TD_TOBE_PROCESSED) {
+    return EFI_NOT_READY;
+  } else {
+    return EFI_DEVICE_ERROR;
+  }
+}
+
+
+/**
+
+  Convert TD condition code to Efi Status
+
+  @Param  ConditionCode         Condition code to convert
+
+  @retval  EFI_SUCCESS          No error occured
+  @retval  EFI_NOT_READY        TD still on processing
+  @retval  EFI_DEVICE_ERROR     Error occured in processing TD
+
+**/
+
+EFI_STATUS
+OhciTDConditionCodeToStatus (
+  IN  UINT32              ConditionCode
+  )
+{
+  if (ConditionCode == TD_NO_ERROR) {
+    return EFI_SUCCESS;
+  }
+
+  if (ConditionCode == TD_TOBE_PROCESSED) {
+    return EFI_NOT_READY;
+  }
+
+  return EFI_DEVICE_ERROR;
+}
+
+/**
+
+  Invoke callbacks hooked on done TDs
+
+  @Param  Entry                 Interrupt transfer transaction information data structure
+  @Param  Context               Ohc private data
+
+**/
+
+VOID
+OhciInvokeInterruptCallBack(
+  IN  INTERRUPT_CONTEXT_ENTRY  *Entry,
+  IN  UINT32                   Result
+)
+{
+  //Generally speaking, Keyboard driver should not
+  //check the Keyboard buffer if an error happens, it will be robust
+  //if we NULLed the buffer once error happens
+  if (Result) {
+    Entry->CallBackFunction (
+             NULL,
+             0,
+             Entry->Context,
+             Result
+             );
+  }else{
+    Entry->CallBackFunction (
+             (VOID *)(UINTN)(Entry->DataTd->DataBuffer),
+             Entry->DataTd->ActualSendLength,
+             Entry->Context,
+             Result
+             );
+  }
+}
+
+
+/**
+
+  Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs
+
+  @param  Event                 Event handle
+  @param  Context               Device private data
+
+**/
+
+VOID
+EFIAPI
+OhciHouseKeeper (
+  IN  EFI_EVENT           Event,
+  IN  VOID                *Context
+  )
+{
+
+  USB_OHCI_HC_DEV          *Ohc;
+  INTERRUPT_CONTEXT_ENTRY  *Entry;
+  INTERRUPT_CONTEXT_ENTRY  *PreEntry;
+  ED_DESCRIPTOR            *Ed;
+  TD_DESCRIPTOR            *DataTd;
+  TD_DESCRIPTOR            *HeadTd;
+
+  UINT8                    Toggle;
+  EFI_TPL                  OriginalTPL;
+  UINT32                   Result;
+
+  Ohc = (USB_OHCI_HC_DEV *) Context;
+  OriginalTPL = gBS->RaiseTPL(TPL_NOTIFY);
+
+  Entry = Ohc->InterruptContextList;
+  PreEntry = NULL;
+
+  while(Entry != NULL) {
+
+    OhciCheckTDsResults(Ohc, Entry->DataTd, &Result );
+    if (((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) ||
+      ((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)) {
+      PreEntry = Entry;
+      Entry = Entry->NextEntry;
+      continue;
+    }
+
+    if (Entry->CallBackFunction != NULL) {
+      OhciInvokeInterruptCallBack (Entry, Result);
+      if (Ohc->InterruptContextList == NULL) {
+        gBS->RestoreTPL (OriginalTPL);
+        return;
+      }
+    }
+    if (Entry->IsPeriodic) {
+
+      Ed = Entry->Ed;
+      HeadTd = Entry->DataTd;
+      DataTd = HeadTd;
+      Toggle = 0;
+      if (Result == EFI_USB_NOERROR) {
+        //
+        // Update toggle if there is no error, and re-submit the interrupt Ed&Tds
+        //
+        if ((Ed != NULL) && (DataTd != NULL)) {
+          Ed->Word0.Skip = 1;
+        }
+        //
+        // From hcir1_0a.pdf 4.2.2
+        // ToggleCarry:This bit is the data toggle carry bit,
+        // Whenever a TD is retired, this bit is written to
+        // contain the last data toggle value(LSb of data Toggel
+        // file) from the retired TD.
+        // This field is not used for Isochronous Endpoints
+        //
+        if (Ed == NULL) {
+          return;
+        }
+        Toggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);
+        while(DataTd != NULL) {
+          if (DataTd->NextTDPointer == 0) {
+            DataTd->Word0.DataToggle = 0;
+            break;
+          } else {
+            OhciSetTDField (DataTd, TD_DT_TOGGLE, Toggle);
+          }
+          DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer);
+          Toggle ^= 1;
+        }
+        //
+        // HC will only update DataToggle, ErrorCount, ConditionCode
+        // CurrentBufferPointer & NextTD, so we only need to update
+        // them once we want to active them again
+        //
+        DataTd = HeadTd;
+        while (DataTd != NULL) {
+          if (DataTd->NextTDPointer == 0) {
+            OhciSetTDField (DataTd, TD_ERROR_CNT | TD_COND_CODE | TD_CURR_BUFFER_PTR | TD_NEXT_PTR, 0);
+            break;
+          }
+          OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+          OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+          DataTd->NextTD = DataTd->NextTDPointer;
+          DataTd->CurrBufferPointer = DataTd->DataBuffer;
+          DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer);
+        }
+        //
+        // Active current Ed,Td
+        //
+        // HC will only update Halted, ToggleCarry & TDQueueHeadPointer,
+        // So we only need to update them once we want to active them again.
+        //
+        if ((Ed != NULL) && (DataTd != NULL)) {
+          Ed->Word2.TdHeadPointer = (UINT32)((UINTN)HeadTd>>4);
+          OhciSetEDField (Ed, ED_HALTED | ED_DTTOGGLE, 0);
+          Ed->Word0.Skip = 0;
+        }
+      }
+    } else {
+      if (PreEntry == NULL) {
+        Ohc->InterruptContextList = Entry->NextEntry;
+      } else {
+        PreEntry = Entry;
+        PreEntry->NextEntry = Entry->NextEntry;
+      }
+      OhciFreeInterruptContextEntry (Ohc, PreEntry);
+      gBS->RestoreTPL (OriginalTPL);
+      return;
+    }
+    PreEntry = Entry;
+    Entry = Entry->NextEntry;
+  }
+  gBS->RestoreTPL (OriginalTPL);
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h
new file mode 100644
index 0000000000..1c4114cb00
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h
@@ -0,0 +1,225 @@
+/** @file
+This file contains the definination for host controller schedule routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#ifndef _OHCI_SCHED_H
+#define _OHCI_SCHED_H
+
+#include "Descriptor.h"
+
+#define HCCA_MEM_SIZE     256
+#define GRID_SIZE         16
+#define GRID_SHIFT        4
+
+typedef struct _INTERRUPT_CONTEXT_ENTRY INTERRUPT_CONTEXT_ENTRY;
+
+struct _INTERRUPT_CONTEXT_ENTRY{
+  UINT8                               DeviceAddress;
+  UINT8                               EndPointAddress;
+  ED_DESCRIPTOR                       *Ed;
+  TD_DESCRIPTOR                       *DataTd;
+  BOOLEAN                             IsSlowDevice;
+  UINT8                               MaxPacketLength;
+  UINTN                               PollingInterval;
+  EFI_ASYNC_USB_TRANSFER_CALLBACK     CallBackFunction;
+  VOID                                *Context;
+  BOOLEAN                             IsPeriodic;
+  VOID                                *Buffer;
+  UINTN                               DataLength;
+  VOID                                *UCBuffer;
+  VOID                                *UCBufferMapping;
+  UINT8                               *Toggle;
+  INTERRUPT_CONTEXT_ENTRY      *NextEntry;
+};
+
+
+typedef struct {
+  UINT32                  ErrorCode;
+  UINT8                   NextToggle;
+} OHCI_ED_RESULT;
+
+/**
+
+  Add an item of interrupt context
+
+  @param  Ohc                   UHC private data
+  @param  NewEntry              New entry to add
+
+  @retval EFI_SUCCESS           Item successfully added
+
+**/
+EFI_STATUS
+OhciAddInterruptContextEntry (
+  IN  USB_OHCI_HC_DEV          *Ohc,
+  IN  INTERRUPT_CONTEXT_ENTRY  *NewEntry
+  );
+
+/**
+
+  Free a interrupt context entry
+
+  @param  Ohc                   UHC private data
+  @param  Entry                 Pointer to an interrupt context entry
+
+  @retval EFI_SUCCESS           Entry freed
+  @retval EFI_INVALID_PARAMETER Entry is NULL
+
+**/
+EFI_STATUS
+OhciFreeInterruptContextEntry (
+  IN USB_OHCI_HC_DEV          *Ohc,
+  IN INTERRUPT_CONTEXT_ENTRY  *Entry
+  );
+
+/**
+
+  Free entries match the device address and endpoint address
+
+  @Param  Ohc                   UHC private date
+  @Param  DeviceAddress         Item to free must match this device address
+  @Param  EndPointAddress       Item to free must match this end point address
+  @Param  DataToggle            DataToggle for output
+
+  @retval  EFI_SUCCESS          Items match the requirement removed
+
+**/
+EFI_STATUS
+OhciFreeInterruptContext(
+  IN  USB_OHCI_HC_DEV     *Ohc,
+  IN  UINT8               DeviceAddress,
+  IN  UINT8               EndPointAddress,
+  OUT UINT8               *DataToggle
+  );
+
+
+/**
+
+  Convert Error code from OHCI format to EFI format
+
+  @Param  ErrorCode             ErrorCode in OHCI format
+
+  @retval                       ErrorCode in EFI format
+
+**/
+UINT32
+ConvertErrorCode (
+  IN  UINT32              ErrorCode
+  );
+
+
+/**
+
+  Check TDs Results
+
+  @Param  Ohc                   UHC private data
+  @Param  Td                    TD_DESCRIPTOR
+  @Param  Result                Result to return
+
+  @retval TRUE                  means OK
+  @retval FLASE                 means Error or Short packet
+
+**/
+BOOLEAN
+OhciCheckTDsResults (
+  IN  USB_OHCI_HC_DEV     *Ohc,
+  IN  TD_DESCRIPTOR       *Td,
+  OUT UINT32              *Result
+  );
+/**
+
+  Check the task status on an ED
+
+  @Param  Ed                    Pointer to the ED task that TD hooked on
+  @Param  HeadTd                TD header for current transaction
+
+  @retval                       Task Status Code
+
+**/
+
+UINT32
+CheckEDStatus (
+  IN  ED_DESCRIPTOR       *Ed,
+  IN  TD_DESCRIPTOR       *HeadTd,
+  OUT OHCI_ED_RESULT      *EdResult
+  );
+/**
+
+  Check the task status
+
+  @Param  Ohc                   UHC private data
+  @Param  ListType              Pipe type
+  @Param  Ed                    Pointer to the ED task hooked on
+  @Param  HeadTd                Head of TD corresponding to the task
+  @Param  ErrorCode             return the ErrorCode
+
+  @retval  EFI_SUCCESS          Task done
+  @retval  EFI_NOT_READY        Task on processing
+  @retval  EFI_DEVICE_ERROR     Some error occured
+
+**/
+EFI_STATUS
+CheckIfDone (
+  IN  USB_OHCI_HC_DEV       *Ohc,
+  IN  DESCRIPTOR_LIST_TYPE  ListType,
+  IN  ED_DESCRIPTOR         *Ed,
+  IN  TD_DESCRIPTOR         *HeadTd,
+  OUT OHCI_ED_RESULT        *EdResult
+  );
+
+/**
+
+  Convert TD condition code to Efi Status
+
+  @Param  ConditionCode         Condition code to convert
+
+  @retval  EFI_SUCCESS          No error occured
+  @retval  EFI_NOT_READY        TD still on processing
+  @retval  EFI_DEVICE_ERROR     Error occured in processing TD
+
+**/
+
+EFI_STATUS
+OhciTDConditionCodeToStatus (
+  IN  UINT32              ConditionCode
+  );
+
+/**
+
+  Invoke callbacks hooked on done TDs
+
+  @Param  Entry                 Interrupt transfer transaction information data structure
+  @Param  Context               Ohc private data
+
+**/
+
+VOID
+OhciInvokeInterruptCallBack(
+  IN  INTERRUPT_CONTEXT_ENTRY  *Entry,
+  IN  UINT32                   Result
+);
+
+
+/**
+
+  Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs
+
+  @param  Event                 Event handle
+  @param  Context               Device private data
+
+**/
+
+VOID
+EFIAPI
+OhciHouseKeeper (
+  IN  EFI_EVENT           Event,
+  IN  VOID                *Context
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c
new file mode 100644
index 0000000000..ccf4c96de4
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c
@@ -0,0 +1,889 @@
+/** @file
+This file contains URB request, each request is warpped in a
+URB (Usb Request Block).
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#include "Ohci.h"
+
+
+/**
+
+  Create a TD
+
+  @Param  Ohc                   UHC private data
+
+  @retval                       TD structure pointer
+
+**/
+TD_DESCRIPTOR *
+OhciCreateTD (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  TD_DESCRIPTOR           *Td;
+
+  Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR));
+  if (Td == NULL) {
+    DEBUG ((EFI_D_INFO, "STV allocate TD fail !\r\n"));
+    return NULL;
+  }
+  Td->CurrBufferPointer = 0;
+  Td->NextTD = 0;
+  Td->BufferEndPointer = 0;
+  Td->NextTDPointer = 0;
+
+  return Td;
+}
+
+
+/**
+
+  Free a TD
+
+  @Param  Ohc                   UHC private data
+  @Param  Td                    Pointer to a TD to free
+
+  @retval  EFI_SUCCESS          TD freed
+
+**/
+EFI_STATUS
+OhciFreeTD (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN TD_DESCRIPTOR        *Td
+  )
+{
+  if (Td == NULL) {
+    return EFI_SUCCESS;
+  }
+  UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Create a ED
+
+  @Param   Ohc                  Device private data
+
+  @retval  ED                   descriptor pointer
+
+**/
+ED_DESCRIPTOR *
+OhciCreateED (
+  USB_OHCI_HC_DEV          *Ohc
+  )
+{
+  ED_DESCRIPTOR   *Ed;
+  Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR));
+  if (Ed == NULL) {
+    DEBUG ((EFI_D_INFO, "STV allocate ED fail !\r\n"));
+    return NULL;
+  }
+  Ed->Word0.Skip = 1;
+  Ed->TdTailPointer = 0;
+  Ed->Word2.TdHeadPointer = 0;
+  Ed->NextED = 0;
+
+  return Ed;
+}
+
+/**
+
+  Free a ED
+
+  @Param  Ohc                   UHC private data
+  @Param  Ed                    Pointer to a ED to free
+
+  @retval  EFI_SUCCESS          ED freed
+
+**/
+
+EFI_STATUS
+OhciFreeED (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *Ed
+  )
+{
+  if (Ed == NULL) {
+    return EFI_SUCCESS;
+  }
+  UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Free  ED
+
+  @Param  Ohc                    Device private data
+  @Param  Ed                     Pointer to a ED to free
+
+  @retval  EFI_SUCCESS           ED freed
+
+**/
+EFI_STATUS
+OhciFreeAllTDFromED (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *Ed
+  )
+{
+  TD_DESCRIPTOR           *HeadTd;
+  TD_DESCRIPTOR           *TailTd;
+  TD_DESCRIPTOR           *Td;
+  TD_DESCRIPTOR           *TempTd;
+
+  if (Ed == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  HeadTd = TD_PTR (Ed->Word2.TdHeadPointer);
+  TailTd = (TD_DESCRIPTOR *)(UINTN)(Ed->TdTailPointer);
+
+  Td = HeadTd;
+  while (Td != TailTd) {
+    TempTd = Td;
+    Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer);
+    OhciFreeTD (Ohc, TempTd);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Find a working ED match the requirement
+
+  @Param  EdHead                Head of the ED list
+  @Param  DeviceAddress         Device address to search
+  @Param  EndPointNum           End point num to search
+  @Param  EdDir                 ED Direction to search
+
+  @retval   ED descriptor searched
+
+**/
+
+ED_DESCRIPTOR *
+OhciFindWorkingEd (
+  IN ED_DESCRIPTOR       *EdHead,
+  IN UINT8               DeviceAddress,
+  IN UINT8               EndPointNum,
+  IN UINT8               EdDir
+  )
+{
+  ED_DESCRIPTOR           *Ed;
+
+  for (Ed = EdHead; Ed != NULL; Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED)) {
+    if (Ed->Word2.Halted == 0 && Ed->Word0.Skip == 0 &&
+        Ed->Word0.FunctionAddress == DeviceAddress && Ed->Word0.EndPointNum == EndPointNum &&
+        Ed->Word0.Direction == EdDir) {
+      break;
+    }
+  }
+
+  return Ed;
+}
+
+
+/**
+
+  Initialize interrupt list.
+
+  @Param Ohc                    Device private data
+
+  @retval  EFI_SUCCESS          Initialization done
+
+**/
+EFI_STATUS
+OhciInitializeInterruptList (
+  USB_OHCI_HC_DEV          *Ohc
+  )
+{
+  static UINT32     Leaf[32] = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17,
+                                9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31};
+  UINT32            *HccaInterruptTable;
+  UINTN             Index;
+  UINTN             Level;
+  UINTN             Count;
+  ED_DESCRIPTOR     *NewEd;
+
+  HccaInterruptTable = Ohc->HccaMemoryBlock->HccaInterruptTable;
+
+  for (Index = 0; Index < 32; Index++) {
+    NewEd = OhciCreateED (Ohc);
+    if (NewEd == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    HccaInterruptTable[Index] = (UINT32)(UINTN)NewEd;
+  }
+
+  for (Index = 0; Index < 32; Index++) {
+    Ohc->IntervalList[0][Index] = (ED_DESCRIPTOR *)(UINTN)HccaInterruptTable[Leaf[Index]];
+  }
+
+  Count = 32;
+  for (Level = 1; Level <= 5; Level++) {
+    Count = Count >> 1;
+
+    for (Index = 0; Index < Count; Index++) {
+      Ohc->IntervalList[Level][Index] = OhciCreateED (Ohc);
+      if (HccaInterruptTable[Index] == 0) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      Ohc->IntervalList[Level - 1][Index * 2    ]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index];
+      Ohc->IntervalList[Level - 1][Index * 2 + 1]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index];
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Attach an ED
+
+  @Param  Ed                    Ed to be attached
+  @Param  NewEd                 Ed to attach
+
+  @retval EFI_SUCCESS           NewEd attached to Ed
+  @retval EFI_INVALID_PARAMETER Ed is NULL
+
+**/
+EFI_STATUS
+OhciAttachED (
+  IN ED_DESCRIPTOR        *Ed,
+  IN ED_DESCRIPTOR        *NewEd
+  )
+{
+  ED_DESCRIPTOR           *Temp;
+
+  if (Ed == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Ed->NextED == 0){
+    Ed->NextED = (UINT32)(UINTN)NewEd;
+  } else {
+    Temp = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+    Ed->NextED = (UINT32)(UINTN)NewEd;
+    NewEd->NextED = (UINT32)(UINTN)Temp;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Count ED number on a ED chain
+
+  @Param  Ed                    Head of the ED chain
+
+  @retval                       ED number on the chain
+
+**/
+
+UINTN
+CountEdNum (
+  IN ED_DESCRIPTOR      *Ed
+  )
+{
+  UINTN     Count;
+
+  Count = 0;
+
+  while (Ed) {
+    Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+    Count++;
+  }
+
+  return Count;
+}
+
+/**
+
+  Find the minimal burn ED list on a specific depth level
+
+  @Param  Ohc                   Device private data
+  @Param  Depth                 Depth level
+
+  @retval                       ED list found
+
+**/
+
+ED_DESCRIPTOR *
+OhciFindMinInterruptEDList (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Depth
+  )
+{
+  UINTN                   EdNum;
+  UINTN                   MinEdNum;
+  ED_DESCRIPTOR           *TempEd;
+  ED_DESCRIPTOR           *HeadEd;
+  UINTN                   Index;
+
+  if (Depth > 5) {
+    return NULL;
+  }
+
+  MinEdNum = 0xFFFFFFFF;
+  TempEd = NULL;
+  for (Index = 0; Index < (UINTN)(32 >> Depth); Index++) {
+    HeadEd = Ohc->IntervalList[Depth][Index];
+    EdNum = CountEdNum (HeadEd);
+    if (EdNum < MinEdNum) {
+      MinEdNum = EdNum;
+      TempEd = HeadEd;
+    }
+  }
+
+  ASSERT (TempEd != NULL);
+
+  return TempEd;
+}
+
+
+/**
+
+  Attach an ED to an ED list
+
+  @Param  OHC                   UHC private data
+  @Param  ListType              Type of the ED list
+  @Param  Ed                    ED to attach
+  @Param  EdList                ED list to be attached
+
+  @retval  EFI_SUCCESS          ED attached to ED list
+
+**/
+ED_DESCRIPTOR *
+OhciAttachEDToList (
+  IN USB_OHCI_HC_DEV       *Ohc,
+  IN DESCRIPTOR_LIST_TYPE  ListType,
+  IN ED_DESCRIPTOR         *Ed,
+  IN ED_DESCRIPTOR         *EdList
+  )
+{
+  ED_DESCRIPTOR            *HeadEd;
+
+  HeadEd = NULL;
+  switch(ListType) {
+    case CONTROL_LIST:
+      HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD);
+      if (HeadEd == NULL) {
+        OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed);
+        HeadEd = Ed;
+      } else {
+        OhciAttachED (HeadEd, Ed);
+      }
+    break;
+
+    case BULK_LIST:
+      HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD);
+      if (HeadEd == NULL) {
+        OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed);
+        HeadEd = Ed;
+      } else {
+        OhciAttachED (HeadEd, Ed);
+      }
+    break;
+
+    case INTERRUPT_LIST:
+      OhciAttachED (EdList, Ed);
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return HeadEd;
+}
+
+/**
+
+  Remove interrupt EDs that match requirement
+
+  @Param  Ohc                   UHC private data
+  @Param  IntEd                 The address of Interrupt endpoint
+
+  @retval  EFI_SUCCESS          EDs match requirement removed
+
+**/
+
+EFI_STATUS
+OhciFreeInterruptEdByEd (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *IntEd
+  )
+{
+  ED_DESCRIPTOR           *Ed;
+  ED_DESCRIPTOR           *TempEd;
+  UINTN                   Index;
+
+  if (IntEd == NULL)
+    return EFI_SUCCESS;
+
+  for (Index = 0; Index < 32; Index++) {
+    Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index];
+    if (Ed == NULL) {
+      continue;
+    }
+    while (Ed->NextED != 0) {
+      if (Ed->NextED == (UINT32)(UINTN)IntEd ) {
+        TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+        Ed->NextED = TempEd->NextED;
+        OhciFreeED (Ohc, TempEd);
+      } else {
+        Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+      }
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Remove interrupt EDs that match requirement
+
+  @Param  Ohc                   UHC private data
+  @Param  FunctionAddress       Requirement on function address
+  @Param  EndPointNum           Requirement on end point number
+
+  @retval  EFI_SUCCESS          EDs match requirement removed
+
+**/
+EFI_STATUS
+OhciFreeInterruptEdByAddr (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT8                FunctionAddress,
+  IN UINT8                EndPointNum
+  )
+{
+  ED_DESCRIPTOR           *Ed;
+  ED_DESCRIPTOR           *TempEd;
+  UINTN                   Index;
+
+  for (Index = 0; Index < 32; Index++) {
+    Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index];
+    if (Ed == NULL) {
+      continue;
+    }
+
+    while (Ed->NextED != 0) {
+      TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+      if (TempEd->Word0.FunctionAddress == FunctionAddress &&
+          TempEd->Word0.EndPointNum     == EndPointNum        ) {
+        Ed->NextED = TempEd->NextED;
+        OhciFreeED (Ohc, TempEd);
+      } else {
+        Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Link Td2 to the end of Td1
+
+  @Param Td1                    TD to be linked
+  @Param Td2                    TD to link
+
+  @retval EFI_SUCCESS           TD successfully linked
+  @retval EFI_INVALID_PARAMETER Td1 is NULL
+
+**/
+EFI_STATUS
+OhciLinkTD (
+  IN TD_DESCRIPTOR        *Td1,
+  IN TD_DESCRIPTOR        *Td2
+  )
+{
+  TD_DESCRIPTOR           *TempTd;
+
+  if (Td1 == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Td1 == Td2) {
+    return EFI_SUCCESS;
+  }
+
+  TempTd = Td1;
+  while (TempTd->NextTD != 0) {
+    TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD);
+  }
+
+  TempTd->NextTD = (UINT32)(UINTN)Td2;
+  TempTd->NextTDPointer = (UINT32)(UINTN)Td2;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Attach TD list to ED
+
+  @Param  Ed                    ED which TD list attach on
+  @Param  HeadTd                Head of the TD list to attach
+
+  @retval  EFI_SUCCESS          TD list attached on the ED
+
+**/
+EFI_STATUS
+OhciAttachTDListToED (
+  IN ED_DESCRIPTOR        *Ed,
+  IN TD_DESCRIPTOR        *HeadTd
+  )
+{
+  TD_DESCRIPTOR           *TempTd;
+
+  TempTd = TD_PTR (Ed->Word2.TdHeadPointer);
+
+  if (TempTd != NULL) {
+    while (TempTd->NextTD != 0) {
+      TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD);
+    }
+    TempTd->NextTD = (UINT32)(UINTN)HeadTd;
+    TempTd->NextTDPointer = (UINT32)(UINTN)HeadTd;
+  } else {
+    Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32)(UINTN)HeadTd);
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Set value to ED specific field
+
+  @Param  Ed                    ED to be set
+  @Param  Field                 Field to be set
+  @Param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetEDField (
+  IN ED_DESCRIPTOR        *Ed,
+  IN UINT32               Field,
+  IN UINT32               Value
+  )
+{
+  if (Field & ED_FUNC_ADD) {
+    Ed->Word0.FunctionAddress = Value;
+  }
+  if (Field & ED_ENDPT_NUM) {
+    Ed->Word0.EndPointNum = Value;
+  }
+  if (Field & ED_DIR) {
+    Ed->Word0.Direction = Value;
+  }
+  if (Field & ED_SPEED) {
+    Ed->Word0.Speed = Value;
+  }
+  if (Field & ED_SKIP) {
+    Ed->Word0.Skip = Value;
+  }
+  if (Field & ED_FORMAT) {
+    Ed->Word0.Format = Value;
+  }
+  if (Field & ED_MAX_PACKET) {
+    Ed->Word0.MaxPacketSize = Value;
+  }
+  if (Field & ED_PDATA) {
+    Ed->Word0.FreeSpace = Value;
+  }
+  if (Field & ED_ZERO) {
+    Ed->Word2.Zero = Value;
+  }
+  if (Field & ED_TDTAIL_PTR) {
+    Ed->TdTailPointer = Value;
+  }
+
+  if (Field & ED_HALTED) {
+    Ed->Word2.Halted = Value;
+  }
+  if (Field & ED_DTTOGGLE) {
+    Ed->Word2.ToggleCarry = Value;
+  }
+  if (Field & ED_TDHEAD_PTR) {
+    Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value);
+  }
+
+  if (Field & ED_NEXT_EDPTR) {
+    Ed->NextED = Value;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Get value from an ED's specific field
+
+  @Param  Ed                    ED pointer
+  @Param  Field                 Field to get value from
+
+  @retval                       Value of the field
+
+**/
+UINT32
+OhciGetEDField (
+  IN ED_DESCRIPTOR        *Ed,
+  IN UINT32               Field
+  )
+{
+  switch (Field) {
+    case ED_FUNC_ADD:
+      return Ed->Word0.FunctionAddress;
+      break;
+    case ED_ENDPT_NUM:
+      return Ed->Word0.EndPointNum;
+      break;
+    case ED_DIR:
+      return Ed->Word0.Direction;
+      break;
+    case ED_SPEED:
+      return Ed->Word0.Speed;
+      break;
+    case ED_SKIP:
+      return Ed->Word0.Skip;
+      break;
+    case ED_FORMAT:
+      return Ed->Word0.Format;
+      break;
+    case ED_MAX_PACKET:
+      return Ed->Word0.MaxPacketSize;
+      break;
+
+    case ED_TDTAIL_PTR:
+      return Ed->TdTailPointer;
+      break;
+
+    case ED_HALTED:
+      return Ed->Word2.Halted;
+      break;
+
+    case ED_DTTOGGLE:
+      return Ed->Word2.ToggleCarry;
+      break;
+
+    case ED_TDHEAD_PTR:
+      return Ed->Word2.TdHeadPointer << 4;
+      break;
+
+    case ED_NEXT_EDPTR:
+      return Ed->NextED;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+
+/**
+
+  Set value to TD specific field
+
+  @Param  Td                    TD to be set
+  @Param  Field                 Field to be set
+  @Param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetTDField (
+  IN TD_DESCRIPTOR        *Td,
+  IN UINT32               Field,
+  IN UINT32               Value
+  )
+{
+  if (Field & TD_PDATA) {
+    Td->Word0.Reserved = Value;
+  }
+  if (Field & TD_BUFFER_ROUND) {
+    Td->Word0.BufferRounding = Value;
+  }
+  if (Field & TD_DIR_PID) {
+    Td->Word0.DirPID = Value;
+  }
+  if (Field & TD_DELAY_INT) {
+    Td->Word0.DelayInterrupt = Value;
+  }
+  if (Field & TD_DT_TOGGLE) {
+    Td->Word0.DataToggle = Value | 0x2;
+  }
+  if (Field & TD_ERROR_CNT) {
+    Td->Word0.ErrorCount = Value;
+  }
+  if (Field & TD_COND_CODE) {
+    Td->Word0.ConditionCode = Value;
+  }
+
+  if (Field & TD_CURR_BUFFER_PTR) {
+    Td->CurrBufferPointer = Value;
+  }
+
+
+  if (Field & TD_NEXT_PTR) {
+    Td->NextTD = Value;
+  }
+
+  if (Field & TD_BUFFER_END_PTR) {
+    Td->BufferEndPointer = Value;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Get value from ED specific field
+
+  @Param  Td                    TD pointer
+  @Param  Field                 Field to get value from
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetTDField (
+  IN TD_DESCRIPTOR      *Td,
+  IN UINT32             Field
+  )
+{
+  switch (Field){
+    case TD_BUFFER_ROUND:
+      return Td->Word0.BufferRounding;
+      break;
+    case TD_DIR_PID:
+      return Td->Word0.DirPID;
+      break;
+    case TD_DELAY_INT:
+      return Td->Word0.DelayInterrupt;
+      break;
+    case TD_DT_TOGGLE:
+      return Td->Word0.DataToggle;
+      break;
+    case TD_ERROR_CNT:
+      return Td->Word0.ErrorCount;
+      break;
+    case TD_COND_CODE:
+      return Td->Word0.ConditionCode;
+      break;
+    case TD_CURR_BUFFER_PTR:
+      return Td->CurrBufferPointer;
+      break;
+
+    case TD_NEXT_PTR:
+      return Td->NextTD;
+      break;
+
+    case TD_BUFFER_END_PTR:
+      return Td->BufferEndPointer;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Free the Ed,Td,buffer that were created during transferring
+
+  @Param  Ohc                   Device private data
+**/
+
+VOID
+OhciFreeDynamicIntMemory(
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  INTERRUPT_CONTEXT_ENTRY *Entry;
+  if (Ohc != NULL) {
+    while (Ohc->InterruptContextList != NULL) {
+      Entry = Ohc->InterruptContextList;
+      Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry;
+      OhciFreeInterruptEdByEd (Ohc, Entry->Ed);
+      OhciFreeInterruptContextEntry (Ohc, Entry);
+    }
+  }
+}
+/**
+
+  Free the Ed that were initilized during driver was starting,
+  those memory were used as interrupt ED head
+
+  @Param  Ohc                   Device private data
+
+
+**/
+VOID
+OhciFreeFixedIntMemory (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  static UINT32           Leaf[] = {32,16,8,4,2,1};
+  UINTN                   Index;
+  UINTN                   Level;
+
+  for (Level = 0; Level < 6; Level++) {
+    for (Index = 0; Index < Leaf[Level]; Index++) {
+      if (Ohc->IntervalList[Level][Index] != NULL) {
+        UsbHcFreeMem(Ohc->MemPool, Ohc->IntervalList[Level][Index], sizeof(ED_DESCRIPTOR));
+      }
+    }
+  }
+}
+/**
+
+  Release all OHCI used memory when OHCI going to quit
+
+  @Param  Ohc                   Device private data
+
+  @retval EFI_SUCCESS          Memory released
+
+**/
+
+EFI_STATUS
+OhciFreeIntTransferMemory (
+  IN USB_OHCI_HC_DEV           *Ohc
+  )
+{
+  //
+  // Free the Ed,Td,buffer that were created during transferring
+  //
+  OhciFreeDynamicIntMemory (Ohc);
+  //
+  // Free the Ed that were initilized during driver was starting
+  //
+  OhciFreeFixedIntMemory (Ohc);
+  return EFI_SUCCESS;
+}
+
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h
new file mode 100644
index 0000000000..6bf2fe7e54
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h
@@ -0,0 +1,387 @@
+/** @file
+Provides some data struct used by OHCI controller driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _OHCI_URB_H
+#define _OHCI_URB_H
+
+#include "Descriptor.h"
+
+
+//
+// Func List
+//
+
+
+/**
+
+  Create a TD
+
+  @Param  Ohc                   UHC private data
+
+  @retval                       TD structure pointer
+
+**/
+TD_DESCRIPTOR *
+OhciCreateTD (
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+
+/**
+
+  Free a TD
+
+  @Param  Ohc                   UHC private data
+  @Param  Td                    Pointer to a TD to free
+
+  @retval  EFI_SUCCESS          TD freed
+
+**/
+EFI_STATUS
+OhciFreeTD (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN TD_DESCRIPTOR        *Td
+  );
+
+/**
+
+  Create a ED
+
+  @Param   Ohc                  Device private data
+
+  @retval  ED                   descriptor pointer
+
+**/
+ED_DESCRIPTOR *
+OhciCreateED (
+  USB_OHCI_HC_DEV          *Ohc
+  );
+
+
+/**
+
+  Free a ED
+
+  @Param  Ohc                   UHC private data
+  @Param  Ed                    Pointer to a ED to free
+
+  @retval  EFI_SUCCESS          ED freed
+
+**/
+
+EFI_STATUS
+OhciFreeED (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *Ed
+  );
+
+/**
+
+  Free  ED
+
+  @Param  Ohc                    Device private data
+  @Param  Ed                     Pointer to a ED to free
+
+  @retval  EFI_SUCCESS           ED freed
+
+**/
+EFI_STATUS
+OhciFreeAllTDFromED (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *Ed
+  );
+
+/**
+
+  Find a working ED match the requirement
+
+  @Param  EdHead                Head of the ED list
+  @Param  DeviceAddress         Device address to search
+  @Param  EndPointNum           End point num to search
+  @Param  EdDir                 ED Direction to search
+
+  @retval   ED descriptor searched
+
+**/
+
+ED_DESCRIPTOR *
+OhciFindWorkingEd (
+  IN ED_DESCRIPTOR       *EdHead,
+  IN UINT8               DeviceAddress,
+  IN UINT8               EndPointNum,
+  IN UINT8               EdDir
+  );
+
+
+/**
+
+  Initialize interrupt list.
+
+  @Param Ohc                    Device private data
+
+  @retval  EFI_SUCCESS          Initialization done
+
+**/
+EFI_STATUS
+OhciInitializeInterruptList (
+  USB_OHCI_HC_DEV          *Ohc
+  );
+
+/**
+
+  Attach an ED
+
+  @Param  Ed                    Ed to be attached
+  @Param  NewEd                 Ed to attach
+
+  @retval EFI_SUCCESS           NewEd attached to Ed
+  @retval EFI_INVALID_PARAMETER Ed is NULL
+
+**/
+EFI_STATUS
+OhciAttachED (
+  IN ED_DESCRIPTOR        *Ed,
+  IN ED_DESCRIPTOR        *NewEd
+  );
+
+/**
+
+  Count ED number on a ED chain
+
+  @Param  Ed                    Head of the ED chain
+
+  @retval                       ED number on the chain
+
+**/
+
+UINTN
+CountEdNum (
+  IN ED_DESCRIPTOR      *Ed
+  );
+
+/**
+
+  Find the minimal burn ED list on a specific depth level
+
+  @Param  Ohc                   Device private data
+  @Param  Depth                 Depth level
+
+  @retval                       ED list found
+
+**/
+
+ED_DESCRIPTOR *
+OhciFindMinInterruptEDList (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Depth
+  );
+
+/**
+
+  Attach an ED to an ED list
+
+  @Param  OHC                   UHC private data
+  @Param  ListType              Type of the ED list
+  @Param  Ed                    ED to attach
+  @Param  EdList                ED list to be attached
+
+  @retval  EFI_SUCCESS          ED attached to ED list
+
+**/
+ED_DESCRIPTOR *
+OhciAttachEDToList (
+  IN USB_OHCI_HC_DEV       *Ohc,
+  IN DESCRIPTOR_LIST_TYPE  ListType,
+  IN ED_DESCRIPTOR         *Ed,
+  IN ED_DESCRIPTOR         *EdList
+  );
+
+/**
+
+  Remove interrupt EDs that match requirement
+
+  @Param  Ohc                   UHC private data
+  @Param  IntEd                 The address of Interrupt endpoint
+
+  @retval  EFI_SUCCESS          EDs match requirement removed
+
+**/
+
+EFI_STATUS
+OhciFreeInterruptEdByEd (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *IntEd
+  );
+
+/**
+
+  Remove interrupt EDs that match requirement
+
+  @Param  Ohc                   UHC private data
+  @Param  FunctionAddress       Requirement on function address
+  @Param  EndPointNum           Requirement on end point number
+
+  @retval  EFI_SUCCESS          EDs match requirement removed
+
+**/
+EFI_STATUS
+OhciFreeInterruptEdByAddr (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT8                FunctionAddress,
+  IN UINT8                EndPointNum
+  );
+
+
+/**
+
+  Link Td2 to the end of Td1
+
+  @Param Td1                    TD to be linked
+  @Param Td2                    TD to link
+
+  @retval EFI_SUCCESS           TD successfully linked
+  @retval EFI_INVALID_PARAMETER Td1 is NULL
+
+**/
+EFI_STATUS
+OhciLinkTD (
+  IN TD_DESCRIPTOR        *Td1,
+  IN TD_DESCRIPTOR        *Td2
+  );
+
+
+/**
+
+  Attach TD list to ED
+
+  @Param  Ed                    ED which TD list attach on
+  @Param  HeadTd                Head of the TD list to attach
+
+  @retval  EFI_SUCCESS          TD list attached on the ED
+
+**/
+EFI_STATUS
+OhciAttachTDListToED (
+  IN ED_DESCRIPTOR        *Ed,
+  IN TD_DESCRIPTOR        *HeadTd
+  );
+
+
+/**
+
+  Set value to ED specific field
+
+  @Param  Ed                    ED to be set
+  @Param  Field                 Field to be set
+  @Param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetEDField (
+  IN ED_DESCRIPTOR        *Ed,
+  IN UINT32               Field,
+  IN UINT32               Value
+  );
+
+
+/**
+
+  Get value from an ED's specific field
+
+  @Param  Ed                    ED pointer
+  @Param  Field                 Field to get value from
+
+  @retval                       Value of the field
+
+**/
+UINT32
+OhciGetEDField (
+  IN ED_DESCRIPTOR        *Ed,
+  IN UINT32               Field
+  );
+
+
+/**
+
+  Set value to TD specific field
+
+  @Param  Td                    TD to be set
+  @Param  Field                 Field to be set
+  @Param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetTDField (
+  IN TD_DESCRIPTOR        *Td,
+  IN UINT32               Field,
+  IN UINT32               Value
+  );
+
+
+/**
+
+  Get value from ED specific field
+
+  @Param  Td                    TD pointer
+  @Param  Field                 Field to get value from
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetTDField (
+  IN TD_DESCRIPTOR      *Td,
+  IN UINT32             Field
+  );
+/**
+
+  Free the Ed,Td,buffer that were created during transferring
+
+  @Param  Ohc                   Device private data
+**/
+
+VOID
+OhciFreeDynamicIntMemory(
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+
+/**
+
+  Free the Ed that were initilized during driver was starting,
+  those memory were used as interrupt ED head
+
+  @Param  Ohc                   Device private data
+
+
+**/
+VOID
+OhciFreeFixedIntMemory (
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+/**
+
+  Release all OHCI used memory when OHCI going to quit
+
+  @Param  Ohc                   Device private data
+
+  @retval EFI_SUCCESS          Memory released
+
+**/
+
+EFI_STATUS
+OhciFreeIntTransferMemory (
+  IN USB_OHCI_HC_DEV           *Ohc
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c
new file mode 100644
index 0000000000..e2709a25d4
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c
@@ -0,0 +1,560 @@
+/** @file
+Routine procedures for memory allocate/free.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Ohci.h"
+
+
+/**
+  Allocate a block of memory to be used by the buffer pool.
+
+  @param  Pool           The buffer pool to allocate memory for.
+  @param  Pages          How many pages to allocate.
+
+  @return The allocated memory block or NULL if failed.
+
+**/
+USBHC_MEM_BLOCK *
+UsbHcAllocMemBlock (
+  IN  USBHC_MEM_POOL      *Pool,
+  IN  UINTN               Pages
+  )
+{
+  USBHC_MEM_BLOCK         *Block;
+  EFI_PCI_IO_PROTOCOL     *PciIo;
+  VOID                    *BufHost;
+  VOID                    *Mapping;
+  EFI_PHYSICAL_ADDRESS    MappedAddr;
+  UINTN                   Bytes;
+  EFI_STATUS              Status;
+
+  PciIo = Pool->PciIo;
+
+  Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));
+  if (Block == NULL) {
+    return NULL;
+  }
+
+  //
+  // each bit in the bit array represents USBHC_MEM_UNIT
+  // bytes of memory in the memory block.
+  //
+  ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+  Block->BufLen   = EFI_PAGES_TO_SIZE (Pages);
+  Block->BitsLen  = Block->BufLen / (USBHC_MEM_UNIT * 8);
+  Block->Bits     = AllocateZeroPool (Block->BitsLen);
+
+  if (Block->Bits == NULL) {
+    gBS->FreePool (Block);
+    return NULL;
+  }
+
+  //
+  // Allocate the number of Pages of memory, then map it for
+  // bus master read and write.
+  //
+  Status = PciIo->AllocateBuffer (
+                    PciIo,
+                    AllocateAnyPages,
+                    EfiBootServicesData,
+                    Pages,
+                    &BufHost,
+                    0
+                    );
+
+  if (EFI_ERROR (Status)) {
+    goto FREE_BITARRAY;
+  }
+
+  Bytes = EFI_PAGES_TO_SIZE (Pages);
+  Status = PciIo->Map (
+                    PciIo,
+                    EfiPciIoOperationBusMasterCommonBuffer,
+                    BufHost,
+                    &Bytes,
+                    &MappedAddr,
+                    &Mapping
+                    );
+
+  if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
+    goto FREE_BUFFER;
+  }
+
+  //
+  // Check whether the data structure used by the host controller
+  // should be restricted into the same 4G
+  //
+  if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
+    PciIo->Unmap (PciIo, Mapping);
+    goto FREE_BUFFER;
+  }
+
+  Block->BufHost  = BufHost;
+  Block->Buf      = (UINT8 *) ((UINTN) MappedAddr);
+  Block->Mapping  = Mapping;
+
+  return Block;
+
+FREE_BUFFER:
+  PciIo->FreeBuffer (PciIo, Pages, BufHost);
+
+FREE_BITARRAY:
+  gBS->FreePool (Block->Bits);
+  gBS->FreePool (Block);
+  return NULL;
+}
+
+
+/**
+  Free the memory block from the memory pool.
+
+  @param  Pool           The memory pool to free the block from.
+  @param  Block          The memory block to free.
+
+**/
+VOID
+UsbHcFreeMemBlock (
+  IN USBHC_MEM_POOL       *Pool,
+  IN USBHC_MEM_BLOCK      *Block
+  )
+{
+  EFI_PCI_IO_PROTOCOL     *PciIo;
+
+  ASSERT ((Pool != NULL) && (Block != NULL));
+
+  PciIo = Pool->PciIo;
+
+  //
+  // Unmap the common buffer then free the structures
+  //
+  PciIo->Unmap (PciIo, Block->Mapping);
+  PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);
+
+  gBS->FreePool (Block->Bits);
+  gBS->FreePool (Block);
+}
+
+
+/**
+  Alloc some memory from the block.
+
+  @param  Block          The memory block to allocate memory from.
+  @param  Units          Number of memory units to allocate.
+
+  @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+          the return value is NULL.
+
+**/
+VOID *
+UsbHcAllocMemFromBlock (
+  IN  USBHC_MEM_BLOCK     *Block,
+  IN  UINTN               Units
+  )
+{
+  UINTN                   Byte;
+  UINT8                   Bit;
+  UINTN                   StartByte;
+  UINT8                   StartBit;
+  UINTN                   Available;
+  UINTN                   Count;
+
+  ASSERT ((Block != 0) && (Units != 0));
+
+  StartByte  = 0;
+  StartBit   = 0;
+  Available  = 0;
+
+  for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+    //
+    // If current bit is zero, the corresponding memory unit is
+    // available, otherwise we need to restart our searching.
+    // Available counts the consective number of zero bit.
+    //
+    if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+      Available++;
+
+      if (Available >= Units) {
+        break;
+      }
+
+      NEXT_BIT (Byte, Bit);
+
+    } else {
+      NEXT_BIT (Byte, Bit);
+
+      Available  = 0;
+      StartByte  = Byte;
+      StartBit   = Bit;
+    }
+  }
+
+  if (Available < Units) {
+    return NULL;
+  }
+
+  //
+  // Mark the memory as allocated
+  //
+  Byte  = StartByte;
+  Bit   = StartBit;
+
+  for (Count = 0; Count < Units; Count++) {
+    ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+    Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | USB_HC_BIT (Bit));
+    NEXT_BIT (Byte, Bit);
+  }
+
+  return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
+}
+
+/**
+  Calculate the corresponding pci bus address according to the Mem parameter.
+
+  @param  Pool           The memory pool of the host controller.
+  @param  Mem            The pointer to host memory.
+  @param  Size           The size of the memory region.
+
+  @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+  IN USBHC_MEM_POOL       *Pool,
+  IN VOID                 *Mem,
+  IN UINTN                Size
+  )
+{
+  USBHC_MEM_BLOCK         *Head;
+  USBHC_MEM_BLOCK         *Block;
+  UINTN                   AllocSize;
+  EFI_PHYSICAL_ADDRESS    PhyAddr;
+  UINTN                   Offset;
+
+  Head      = Pool->Head;
+  AllocSize = USBHC_MEM_ROUND (Size);
+
+  if (Mem == NULL) {
+    return 0;
+  }
+
+  for (Block = Head; Block != NULL; Block = Block->Next) {
+    //
+    // scan the memory block list for the memory block that
+    // completely contains the allocated memory.
+    //
+    if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+      break;
+    }
+  }
+
+  ASSERT ((Block != NULL));
+  //
+  // calculate the pci memory address for host memory address.
+  //
+  Offset = (UINT8 *)Mem - Block->BufHost;
+  PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);
+  return PhyAddr;
+}
+
+
+/**
+  Insert the memory block to the pool's list of the blocks.
+
+  @param  Head           The head of the memory pool's block list.
+  @param  Block          The memory block to insert.
+
+**/
+VOID
+UsbHcInsertMemBlockToPool (
+  IN USBHC_MEM_BLOCK      *Head,
+  IN USBHC_MEM_BLOCK      *Block
+  )
+{
+  ASSERT ((Head != NULL) && (Block != NULL));
+  Block->Next = Head->Next;
+  Head->Next  = Block;
+}
+
+
+/**
+  Is the memory block empty?
+
+  @param  Block   The memory block to check.
+
+  @retval TRUE    The memory block is empty.
+  @retval FALSE   The memory block isn't empty.
+
+**/
+BOOLEAN
+UsbHcIsMemBlockEmpty (
+  IN USBHC_MEM_BLOCK     *Block
+  )
+{
+  UINTN                   Index;
+
+  for (Index = 0; Index < Block->BitsLen; Index++) {
+    if (Block->Bits[Index] != 0) {
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+
+/**
+  Unlink the memory block from the pool's list.
+
+  @param  Head           The block list head of the memory's pool.
+  @param  BlockToUnlink  The memory block to unlink.
+
+**/
+VOID
+UsbHcUnlinkMemBlock (
+  IN USBHC_MEM_BLOCK      *Head,
+  IN USBHC_MEM_BLOCK      *BlockToUnlink
+  )
+{
+  USBHC_MEM_BLOCK         *Block;
+
+  ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
+
+  for (Block = Head; Block != NULL; Block = Block->Next) {
+    if (Block->Next == BlockToUnlink) {
+      Block->Next         = BlockToUnlink->Next;
+      BlockToUnlink->Next = NULL;
+      break;
+    }
+  }
+}
+
+
+/**
+  Initialize the memory management pool for the host controller.
+
+  @param  PciIo                The PciIo that can be used to access the host controller.
+  @param  Check4G              Whether the host controller requires allocated memory
+                               from one 4G address space.
+  @param  Which4G              The 4G memory area each memory allocated should be from.
+
+  @retval EFI_SUCCESS          The memory pool is initialized.
+  @retval EFI_OUT_OF_RESOURCE  Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN BOOLEAN              Check4G,
+  IN UINT32               Which4G
+  )
+{
+  USBHC_MEM_POOL          *Pool;
+
+  Pool = AllocatePool (sizeof (USBHC_MEM_POOL));
+
+  if (Pool == NULL) {
+    return Pool;
+  }
+
+  Pool->PciIo   = PciIo;
+  Pool->Check4G = Check4G;
+  Pool->Which4G = Which4G;
+  Pool->Head    = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
+
+  if (Pool->Head == NULL) {
+    gBS->FreePool (Pool);
+    Pool = NULL;
+  }
+
+  return Pool;
+}
+
+
+/**
+  Release the memory management pool.
+
+  @param  Pool              The USB memory pool to free.
+
+  @retval EFI_SUCCESS       The memory pool is freed.
+  @retval EFI_DEVICE_ERROR  Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+  IN USBHC_MEM_POOL       *Pool
+  )
+{
+  USBHC_MEM_BLOCK *Block;
+
+  ASSERT (Pool->Head != NULL);
+
+  //
+  // Unlink all the memory blocks from the pool, then free them.
+  // UsbHcUnlinkMemBlock can't be used to unlink and free the
+  // first block.
+  //
+  for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+    UsbHcUnlinkMemBlock (Pool->Head, Block);
+    UsbHcFreeMemBlock (Pool, Block);
+  }
+
+  UsbHcFreeMemBlock (Pool, Pool->Head);
+  gBS->FreePool (Pool);
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Allocate some memory from the host controller's memory pool
+  which can be used to communicate with host controller.
+
+  @param  Pool           The host controller's memory pool.
+  @param  Size           Size of the memory to allocate.
+
+  @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+  IN  USBHC_MEM_POOL      *Pool,
+  IN  UINTN               Size
+  )
+{
+  USBHC_MEM_BLOCK         *Head;
+  USBHC_MEM_BLOCK         *Block;
+  USBHC_MEM_BLOCK         *NewBlock;
+  VOID                    *Mem;
+  UINTN                   AllocSize;
+  UINTN                   Pages;
+
+  Mem       = NULL;
+  AllocSize = USBHC_MEM_ROUND (Size);
+  Head      = Pool->Head;
+  ASSERT (Head != NULL);
+
+  //
+  // First check whether current memory blocks can satisfy the allocation.
+  //
+  for (Block = Head; Block != NULL; Block = Block->Next) {
+    Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
+
+    if (Mem != NULL) {
+      ZeroMem (Mem, Size);
+      break;
+    }
+  }
+
+  if (Mem != NULL) {
+    return Mem;
+  }
+
+  //
+  // Create a new memory block if there is not enough memory
+  // in the pool. If the allocation size is larger than the
+  // default page number, just allocate a large enough memory
+  // block. Otherwise allocate default pages.
+  //
+  if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
+    Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+  } else {
+    Pages = USBHC_MEM_DEFAULT_PAGES;
+  }
+
+  NewBlock = UsbHcAllocMemBlock (Pool, Pages);
+
+  if (NewBlock == NULL) {
+    DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));
+    return NULL;
+  }
+
+  //
+  // Add the new memory block to the pool, then allocate memory from it
+  //
+  UsbHcInsertMemBlockToPool (Head, NewBlock);
+  Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
+
+  if (Mem != NULL) {
+    ZeroMem (Mem, Size);
+  }
+
+  return Mem;
+}
+
+
+/**
+  Free the allocated memory back to the memory pool.
+
+  @param  Pool           The memory pool of the host controller.
+  @param  Mem            The memory to free.
+  @param  Size           The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+  IN USBHC_MEM_POOL       *Pool,
+  IN VOID                 *Mem,
+  IN UINTN                Size
+  )
+{
+  USBHC_MEM_BLOCK         *Head;
+  USBHC_MEM_BLOCK         *Block;
+  UINT8                   *ToFree;
+  UINTN                   AllocSize;
+  UINTN                   Byte;
+  UINTN                   Bit;
+  UINTN                   Count;
+
+  Head      = Pool->Head;
+  AllocSize = USBHC_MEM_ROUND (Size);
+  ToFree    = (UINT8 *) Mem;
+
+  for (Block = Head; Block != NULL; Block = Block->Next) {
+    //
+    // scan the memory block list for the memory block that
+    // completely contains the memory to free.
+    //
+    if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+      //
+      // compute the start byte and bit in the bit array
+      //
+      Byte  = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
+      Bit   = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
+
+      //
+      // reset associated bits in bit arry
+      //
+      for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
+        ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+        Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
+        NEXT_BIT (Byte, Bit);
+      }
+
+      break;
+    }
+  }
+
+  //
+  // If Block == NULL, it means that the current memory isn't
+  // in the host controller's pool. This is critical because
+  // the caller has passed in a wrong memory point
+  //
+  ASSERT (Block != NULL);
+
+  //
+  // Release the current memory block if it is empty and not the head
+  //
+  if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
+    UsbHcUnlinkMemBlock (Head, Block);
+    UsbHcFreeMemBlock (Pool, Block);
+  }
+
+  return ;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h
new file mode 100644
index 0000000000..e2973bfe49
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h
@@ -0,0 +1,152 @@
+/** @file
+This file contains the definination for host controller memory
+management routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _USB_HC_MEM_H_
+#define _USB_HC_MEM_H_
+
+#define USB_HC_BIT(a)                  ((UINTN)(1 << (a)))
+
+#define USB_HC_BIT_IS_SET(Data, Bit)   \
+          ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
+
+#define USB_HC_HIGH_32BIT(Addr64)    \
+          ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
+struct _USBHC_MEM_BLOCK {
+  UINT8                   *Bits;    // Bit array to record which unit is allocated
+  UINTN                   BitsLen;
+  UINT8                   *Buf;
+  UINT8                   *BufHost;
+  UINTN                   BufLen;   // Memory size in bytes
+  VOID                    *Mapping;
+  USBHC_MEM_BLOCK         *Next;
+};
+
+//
+// USBHC_MEM_POOL is used to manage the memory used by USB
+// host controller. EHCI requires the control memory and transfer
+// data to be on the same 4G memory.
+//
+typedef struct _USBHC_MEM_POOL {
+  EFI_PCI_IO_PROTOCOL     *PciIo;
+  BOOLEAN                 Check4G;
+  UINT32                  Which4G;
+  USBHC_MEM_BLOCK         *Head;
+} USBHC_MEM_POOL;
+
+//
+// Memory allocation unit, must be 2^n, n>4
+//
+#define USBHC_MEM_UNIT           64
+
+#define USBHC_MEM_UNIT_MASK      (USBHC_MEM_UNIT - 1)
+#define USBHC_MEM_DEFAULT_PAGES  16
+
+#define USBHC_MEM_ROUND(Len)  (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define NEXT_BIT(Byte, Bit)   \
+          do {                \
+            (Bit)++;          \
+            if ((Bit) > 7) {  \
+              (Byte)++;       \
+              (Bit) = 0;      \
+            }                 \
+          } while (0)
+
+
+
+/**
+  Initialize the memory management pool for the host controller.
+
+  @param  PciIo               The PciIo that can be used to access the host controller.
+  @param  Check4G             Whether the host controller requires allocated memory
+                              from one 4G address space.
+  @param  Which4G             The 4G memory area each memory allocated should be from.
+
+  @retval EFI_SUCCESS         The memory pool is initialized.
+  @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN BOOLEAN              Check4G,
+  IN UINT32               Which4G
+  );
+
+
+/**
+  Release the memory management pool.
+
+  @param   Pool               The USB memory pool to free.
+
+  @retval EFI_SUCCESS       The memory pool is freed.
+  @retval EFI_DEVICE_ERROR  Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+  IN USBHC_MEM_POOL       *Pool
+  );
+
+
+/**
+  Allocate some memory from the host controller's memory pool
+  which can be used to communicate with host controller.
+
+  @param  Pool  The host controller's memory pool.
+  @param  Size  Size of the memory to allocate.
+
+  @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+  IN  USBHC_MEM_POOL      *Pool,
+  IN  UINTN               Size
+  );
+
+
+/**
+  Free the allocated memory back to the memory pool.
+
+  @param  Pool  The memory pool of the host controller.
+  @param  Mem   The memory to free.
+  @param  Size  The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+  IN USBHC_MEM_POOL       *Pool,
+  IN VOID                 *Mem,
+  IN UINTN                Size
+  );
+
+/**
+  Calculate the corresponding pci bus address according to the Mem parameter.
+
+  @param  Pool           The memory pool of the host controller.
+  @param  Mem            The pointer to host memory.
+  @param  Size           The size of the memory region.
+
+  @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+  IN USBHC_MEM_POOL       *Pool,
+  IN VOID                 *Mem,
+  IN UINTN                Size
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h
new file mode 100644
index 0000000000..4ec60a07a7
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h
@@ -0,0 +1,131 @@
+/** @file
+This file contains the descriptor definination of OHCI spec
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#ifndef _DESCRIPTOR_H
+#define _DESCRIPTOR_H
+
+#define ED_FUNC_ADD     0x0001
+#define ED_ENDPT_NUM    0x0002
+#define ED_DIR          0x0004
+#define ED_SPEED        0x0008
+#define ED_SKIP         0x0010
+#define ED_FORMAT       0x0020
+#define ED_MAX_PACKET   0x0040
+#define ED_TDTAIL_PTR   0x0080
+#define ED_HALTED       0x0100
+#define ED_DTTOGGLE     0x0200
+#define ED_TDHEAD_PTR   0x0400
+#define ED_NEXT_EDPTR   0x0800
+#define ED_PDATA        0x1000
+#define ED_ZERO         0x2000
+
+#define TD_BUFFER_ROUND     0x0001
+#define TD_DIR_PID          0x0002
+#define TD_DELAY_INT        0x0004
+#define TD_DT_TOGGLE        0x0008
+#define TD_ERROR_CNT        0x0010
+#define TD_COND_CODE        0x0020
+#define TD_CURR_BUFFER_PTR  0x0040
+#define TD_NEXT_PTR         0x0080
+#define TD_BUFFER_END_PTR   0x0100
+#define TD_PDATA            0x0200
+
+#define ED_FROM_TD_DIR        0x0
+#define ED_OUT_DIR            0x1
+#define ED_IN_DIR             0x2
+#define ED_FROM_TD_ALSO_DIR   0x3
+
+#define TD_SETUP_PID          0x00
+#define TD_OUT_PID            0x01
+#define TD_IN_PID             0x02
+#define TD_NODATA_PID         0x03
+
+#define HI_SPEED              0
+#define LO_SPEED              1
+
+#define TD_NO_ERROR           0x00
+#define TD_CRC_ERROR          0x01
+#define TD_BITSTUFFING_ERROR  0x02
+#define TD_TOGGLE_ERROR       0x03
+#define TD_DEVICE_STALL       0x04
+#define TD_NO_RESPONSE        0x05
+#define TD_PIDCHK_FAIL        0x06
+#define TD_PID_UNEXPECTED     0x07
+#define TD_DATA_OVERRUN       0x08
+#define TD_DATA_UNDERRUN      0x09
+#define TD_BUFFER_OVERRUN     0x0C
+#define TD_BUFFER_UNDERRUN    0x0D
+#define TD_TOBE_PROCESSED     0x0E
+#define TD_TOBE_PROCESSED_2   0x0F
+
+#define TD_NO_DELAY           0x7
+
+#define TD_INT                0x1
+#define TD_CTL                0x2
+#define TD_BLK                0x3
+
+typedef struct {
+  UINT32 Reserved:18;
+  UINT32 BufferRounding:1;
+  UINT32 DirPID:2;
+  UINT32 DelayInterrupt:3;
+  UINT32 DataToggle:2;
+  UINT32 ErrorCount:2;
+  UINT32 ConditionCode:4;
+} TD_DESCRIPTOR_WORD0;
+
+typedef struct _TD_DESCRIPTOR {
+  TD_DESCRIPTOR_WORD0     Word0;
+  VOID                    *CurrBufferPointer;
+  struct _TD_DESCRIPTOR   *NextTD;
+  VOID                    *BufferEndPointer;
+  struct _TD_DESCRIPTOR   *NextTDPointer;
+  UINT8                   *DataBuffer;
+  UINT32                  ActualSendLength;
+} TD_DESCRIPTOR;
+
+typedef struct {
+  UINT32 FunctionAddress:7;
+  UINT32 EndPointNum:4;
+  UINT32 Direction:2;
+  UINT32 Speed:1;
+  UINT32 Skip:1;
+  UINT32 Format:1;
+  UINT32 MaxPacketSize:11;
+  UINT32 FreeSpace:5;
+} ED_DESCRIPTOR_WORD0;
+
+typedef struct {
+  UINT32 Halted:1;
+  UINT32 ToggleCarry:1;
+  UINT32 Zero:2;
+  UINT32 TdHeadPointer:28;
+} ED_DESCRIPTOR_WORD2;
+
+typedef struct _ED_DESCRIPTOR {
+  ED_DESCRIPTOR_WORD0     Word0;
+  TD_DESCRIPTOR           *TdTailPointer;
+  ED_DESCRIPTOR_WORD2     Word2;
+  struct _ED_DESCRIPTOR   *NextED;
+} ED_DESCRIPTOR;
+
+#define TD_PTR(p)            ((TD_DESCRIPTOR *)((p) << 4))
+#define ED_PTR(p)            ((ED_DESCRIPTOR *)((p) << 4))
+#define RIGHT_SHIFT_4(p)     ((UINT32)(p) >> 4)
+
+typedef enum {
+  CONTROL_LIST,
+  BULK_LIST,
+  INTERRUPT_LIST,
+  ISOCHRONOUS_LIST
+} DESCRIPTOR_LIST_TYPE;
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c
new file mode 100644
index 0000000000..6997e6e387
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c
@@ -0,0 +1,1386 @@
+/** @file
+This file contains the implementation of Usb Hc Protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "OhcPeim.h"
+
+/**
+  Submits control transfer to a target USB device.
+
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.
+  @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  DeviceAddress          The target device address.
+  @param  DeviceSpeed            Target device speed.
+  @param  MaximumPacketLength    Maximum packet size the default control transfer
+                                 endpoint is capable of sending or receiving.
+  @param  Request                USB device request to send.
+  @param  TransferDirection      Specifies the data direction for the data stage.
+  @param  Data                   Data buffer to be transmitted or received from USB device.
+  @param  DataLength             The size (in bytes) of the data buffer.
+  @param  TimeOut                Indicates the maximum timeout, in millisecond.
+  @param  TransferResult         Return the result of this control transfer.
+
+  @retval EFI_SUCCESS            Transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
+  @retval EFI_TIMEOUT            Transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciControlTransfer (
+  IN  EFI_PEI_SERVICES             **PeiServices,
+  IN  PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN  UINT8                        DeviceAddress,
+  IN  UINT8                        DeviceSpeed,
+  IN  UINT8                        MaxPacketLength,
+  IN  EFI_USB_DEVICE_REQUEST       *Request,
+  IN  EFI_USB_DATA_DIRECTION       TransferDirection,
+  IN  OUT VOID                     *Data,
+  IN  OUT UINTN                    *DataLength,
+  IN  UINTN                        TimeOut,
+  OUT UINT32                       *TransferResult
+  )
+{
+  USB_OHCI_HC_DEV               *Ohc;
+  ED_DESCRIPTOR                 *Ed;
+  TD_DESCRIPTOR                 *HeadTd;
+  TD_DESCRIPTOR                 *SetupTd;
+  TD_DESCRIPTOR                 *DataTd;
+  TD_DESCRIPTOR                 *StatusTd;
+  TD_DESCRIPTOR                 *EmptyTd;
+  EFI_STATUS                    Status;
+  UINT32                        DataPidDir;
+  UINT32                        StatusPidDir;
+  UINTN                         TimeCount;
+  UINT32                        ErrorCode;
+
+  UINTN                         ActualSendLength;
+  UINTN                         LeftLength;
+  UINT8                         DataToggle;
+
+  EFI_PHYSICAL_ADDRESS          ReqMapPhyAddr = 0;
+
+  UINTN                         DataMapLength = 0;
+  EFI_PHYSICAL_ADDRESS          DataMapPhyAddr = 0;
+
+  HeadTd = NULL;
+  DataTd = NULL;
+
+  if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn &&
+       TransferDirection != EfiUsbNoData) ||
+      Request == NULL || DataLength == NULL || TransferResult == NULL ||
+      (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) ||
+      (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) ||
+      (DeviceSpeed != EFI_USB_SPEED_LOW && DeviceSpeed != EFI_USB_SPEED_FULL) ||
+      (MaxPacketLength != 8 && MaxPacketLength != 16 &&
+       MaxPacketLength != 32 && MaxPacketLength != 64)) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: EFI_INVALID_PARAMETER\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (*DataLength > MAX_BYTES_PER_TD) {
+    DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS(This);
+
+  if (TransferDirection == EfiUsbDataIn) {
+    DataPidDir = TD_IN_PID;
+    StatusPidDir = TD_OUT_PID;
+  } else {
+    DataPidDir = TD_OUT_PID;
+    StatusPidDir = TD_IN_PID;
+  }
+
+  OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);
+  if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {
+    MicroSecondDelay (HC_1_MILLISECOND);
+    if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {
+      *TransferResult = EFI_USB_ERR_SYSTEM;
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to disable CONTROL transfer\n"));
+      return EFI_DEVICE_ERROR;
+    }
+  }
+  OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+  Ed = OhciCreateED (Ohc);
+  if (Ed == NULL) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  OhciSetEDField (Ed, ED_SKIP, 1);
+  OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+  OhciSetEDField (Ed, ED_ENDPT_NUM, 0);
+  OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+  OhciSetEDField (Ed, ED_SPEED, DeviceSpeed);
+  OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);
+  OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+  OhciSetEDField (Ed, ED_PDATA, 0);
+  OhciSetEDField (Ed, ED_ZERO, 0);
+  OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL);
+  OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL);
+  OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL);
+  OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL);
+  //
+  // Setup Stage
+  //
+  if(Request != NULL) {
+    ReqMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Request;
+  }
+  SetupTd = OhciCreateTD (Ohc);
+  if (SetupTd == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\n"));
+    goto FREE_ED_BUFF;
+  }
+  HeadTd = SetupTd;
+  OhciSetTDField (SetupTd, TD_PDATA, 0);
+  OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1);
+  OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID);
+  OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY);
+  OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2);
+  OhciSetTDField (SetupTd, TD_ERROR_CNT, 0);
+  OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+  OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINTN)ReqMapPhyAddr);
+  OhciSetTDField (SetupTd, TD_NEXT_PTR, (UINT32) NULL);
+  OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINTN)ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1);
+  SetupTd->ActualSendLength = 0;
+  SetupTd->DataBuffer = NULL;
+  SetupTd->NextTDPointer = NULL;
+
+  DataMapLength = *DataLength;
+  if ((Data != NULL) && (DataMapLength != 0)) {
+    DataMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data;
+  }
+  //
+  //Data Stage
+  //
+  LeftLength = DataMapLength;
+  ActualSendLength = DataMapLength;
+  DataToggle = 1;
+  while (LeftLength > 0) {
+    ActualSendLength = LeftLength;
+    if (LeftLength > MaxPacketLength) {
+      ActualSendLength = MaxPacketLength;
+    }
+    DataTd = OhciCreateTD (Ohc);
+    if (DataTd == NULL) {
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Data TD buffer\n"));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto FREE_TD_BUFF;
+    }
+    OhciSetTDField (DataTd, TD_PDATA, 0);
+    OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+    OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+    OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+    OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle);
+    OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+    OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+    OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr);
+    OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) DataMapPhyAddr + ActualSendLength - 1);
+    OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL);
+    DataTd->ActualSendLength = ActualSendLength;
+    DataTd->DataBuffer = (UINT8 *)(UINTN)DataMapPhyAddr;
+    DataTd->NextTDPointer = 0;
+    OhciLinkTD (HeadTd, DataTd);
+    DataToggle ^= 1;
+    DataMapPhyAddr += ActualSendLength;
+    LeftLength -= ActualSendLength;
+  }
+  //
+  // Status Stage
+  //
+  StatusTd = OhciCreateTD (Ohc);
+  if (StatusTd == NULL) {
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Status TD buffer\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto FREE_TD_BUFF;
+  }
+  OhciSetTDField (StatusTd, TD_PDATA, 0);
+  OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1);
+  OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir);
+  OhciSetTDField (StatusTd, TD_DELAY_INT, 7);
+  OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3);
+  OhciSetTDField (StatusTd, TD_ERROR_CNT, 0);
+  OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+  OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, (UINT32) NULL);
+  OhciSetTDField (StatusTd, TD_NEXT_PTR, (UINT32) NULL);
+  OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, (UINT32) NULL);
+  StatusTd->ActualSendLength = 0;
+  StatusTd->DataBuffer = NULL;
+  StatusTd->NextTDPointer = NULL;
+  OhciLinkTD (HeadTd, StatusTd);
+  //
+  // Empty Stage
+  //
+  EmptyTd = OhciCreateTD (Ohc);
+  if (EmptyTd == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Empty TD buffer\n"));
+    goto FREE_TD_BUFF;
+  }
+  OhciSetTDField (EmptyTd, TD_PDATA, 0);
+  OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);
+  OhciSetTDField (EmptyTd, TD_DIR_PID, 0);
+  OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);
+  //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
+  EmptyTd->Word0.DataToggle = 0;
+  OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);
+  OhciSetTDField (EmptyTd, TD_COND_CODE, 0);
+  OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);
+  OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);
+  OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);
+  EmptyTd->ActualSendLength = 0;
+  EmptyTd->DataBuffer = NULL;
+  EmptyTd->NextTDPointer = NULL;
+  OhciLinkTD (HeadTd, EmptyTd);
+  Ed->TdTailPointer = EmptyTd;
+  OhciAttachTDListToED (Ed, HeadTd);
+  //
+  OhciSetEDField (Ed, ED_SKIP, 0);
+  MicroSecondDelay (20 * HC_1_MILLISECOND);
+  OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1);
+  OhciSetHcControl (Ohc, CONTROL_ENABLE, 1);
+  MicroSecondDelay (20 * HC_1_MILLISECOND);
+  if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) {
+  MicroSecondDelay (HC_1_MILLISECOND);
+    if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) {
+      *TransferResult = EFI_USB_ERR_SYSTEM;
+      Status = EFI_DEVICE_ERROR;
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable CONTROL transfer\n"));
+      goto FREE_TD_BUFF;
+    }
+  }
+
+  TimeCount = 0;
+  Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode);
+
+  while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {
+    MicroSecondDelay (HC_1_MILLISECOND);
+    TimeCount++;
+    Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode);
+  }
+  //
+  *TransferResult = ConvertErrorCode (ErrorCode);
+
+  if (ErrorCode != TD_NO_ERROR) {
+    if (ErrorCode == TD_TOBE_PROCESSED) {
+      DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut));
+    } else {
+      DEBUG ((EFI_D_INFO, "Control pipe broken\r\n"));
+    }
+
+    *DataLength = 0;
+  }
+
+  OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);
+  if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {
+  MicroSecondDelay (HC_1_MILLISECOND);
+    if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {
+      *TransferResult = EFI_USB_ERR_SYSTEM;
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Cannot disable CONTROL_ENABLE transfer\n"));
+      goto FREE_TD_BUFF;
+    }
+  }
+
+FREE_TD_BUFF:
+  while (HeadTd) {
+    DataTd = HeadTd;
+    HeadTd = HeadTd->NextTDPointer;
+    UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+  }
+
+FREE_ED_BUFF:
+  UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+  return Status;
+}
+
+/**
+  Submits bulk transfer to a bulk endpoint of a USB device.
+
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  DeviceAddress         Target device address.
+  @param  EndPointAddress       Endpoint number and its direction in bit 7.
+  @param  MaxiPacketLength      Maximum packet size the endpoint is capable of
+                                sending or receiving.
+  @param  Data                  A pointers to the buffers of data to transmit
+                                from or receive into.
+  @param  DataLength            The lenght of the data buffer.
+  @param  DataToggle            On input, the initial data toggle for the transfer;
+                                On output, it is updated to to next data toggle to use of
+                                the subsequent bulk transfer.
+  @param  TimeOut               Indicates the maximum time, in millisecond, which the
+                                transfer is allowed to complete.
+  @param  TransferResult        A pointer to the detailed result information of the
+                                bulk transfer.
+
+  @retval EFI_SUCCESS           The transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciBulkTransfer (
+  IN EFI_PEI_SERVICES             **PeiServices,
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN  UINT8                       DeviceAddress,
+  IN  UINT8                       EndPointAddress,
+  IN  UINT8                       MaxPacketLength,
+  IN  OUT VOID                    *Data,
+  IN  OUT UINTN                   *DataLength,
+  IN  OUT UINT8                   *DataToggle,
+  IN  UINTN                       TimeOut,
+  OUT UINT32                      *TransferResult
+  )
+{
+  USB_OHCI_HC_DEV                *Ohc;
+  ED_DESCRIPTOR                  *Ed;
+  UINT32                         DataPidDir;
+  TD_DESCRIPTOR                  *HeadTd;
+  TD_DESCRIPTOR                  *DataTd;
+  TD_DESCRIPTOR                  *EmptyTd;
+  EFI_STATUS                     Status;
+  UINT8                          EndPointNum;
+  UINTN                          TimeCount;
+  UINT32                         ErrorCode;
+
+  UINT8                          CurrentToggle;
+  UINTN                          MapLength;
+  EFI_PHYSICAL_ADDRESS           MapPyhAddr;
+  UINTN                          LeftLength;
+  UINTN                          ActualSendLength;
+  BOOLEAN                        FirstTD;
+
+  MapLength = 0;
+  MapPyhAddr = 0;
+  LeftLength = 0;
+  Status = EFI_SUCCESS;
+
+  if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||
+      *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||
+      (MaxPacketLength != 8 && MaxPacketLength != 16 &&
+       MaxPacketLength != 32 && MaxPacketLength != 64)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+
+  if ((EndPointAddress & 0x80) != 0) {
+    DataPidDir = TD_IN_PID;
+  } else {
+    DataPidDir = TD_OUT_PID;
+  }
+
+  EndPointNum = (EndPointAddress & 0xF);
+
+  OhciSetHcControl (Ohc, BULK_ENABLE, 0);
+  if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) {
+    MicroSecondDelay (HC_1_MILLISECOND);
+    if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) {
+      *TransferResult = EFI_USB_ERR_SYSTEM;
+      return EFI_DEVICE_ERROR;
+    }
+  }
+
+  OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+
+  Ed = OhciCreateED (Ohc);
+  if (Ed == NULL) {
+    DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate ED buffer\r\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  OhciSetEDField (Ed, ED_SKIP, 1);
+  OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+  OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);
+  OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+  OhciSetEDField (Ed, ED_SPEED, HI_SPEED);
+  OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);
+  OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+  OhciSetEDField (Ed, ED_PDATA, 0);
+  OhciSetEDField (Ed, ED_ZERO, 0);
+  OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL);
+  OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL);
+  OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL);
+  OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);
+
+  if(Data != NULL) {
+    MapLength = *DataLength;
+    MapPyhAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data;
+  }
+  //
+  //Data Stage
+  //
+  LeftLength = MapLength;
+  ActualSendLength = MapLength;
+  CurrentToggle = *DataToggle;
+  HeadTd = NULL;
+  FirstTD = TRUE;
+  while (LeftLength > 0) {
+    ActualSendLength = LeftLength;
+    if (LeftLength > MaxPacketLength) {
+      ActualSendLength = MaxPacketLength;
+    }
+    DataTd = OhciCreateTD (Ohc);
+    if (DataTd == NULL) {
+      DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Data TD buffer\r\n"));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto FREE_TD_BUFF;
+    }
+    OhciSetTDField (DataTd, TD_PDATA, 0);
+    OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+    OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+    OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+    OhciSetTDField (DataTd, TD_DT_TOGGLE, CurrentToggle);
+    OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+    OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+    OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);
+    OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) MapPyhAddr + ActualSendLength - 1);
+    OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL);
+    DataTd->ActualSendLength = ActualSendLength;
+    DataTd->DataBuffer = (UINT8 *)(UINTN)MapPyhAddr;
+    DataTd->NextTDPointer = 0;
+    if (FirstTD) {
+      HeadTd = DataTd;
+      FirstTD = FALSE;
+    } else {
+      OhciLinkTD (HeadTd, DataTd);
+    }
+    CurrentToggle ^= 1;
+    MapPyhAddr += ActualSendLength;
+    LeftLength -= ActualSendLength;
+  }
+  //
+  // Empty Stage
+  //
+  EmptyTd = OhciCreateTD (Ohc);
+  if (EmptyTd == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+      DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Empty TD buffer\r\n"));
+    goto FREE_TD_BUFF;
+  }
+  OhciSetTDField (EmptyTd, TD_PDATA, 0);
+  OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);
+  OhciSetTDField (EmptyTd, TD_DIR_PID, 0);
+  OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);
+  //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
+  EmptyTd->Word0.DataToggle = 0;
+  OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);
+  OhciSetTDField (EmptyTd, TD_COND_CODE, 0);
+  OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);
+  OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);
+  OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);
+  EmptyTd->ActualSendLength = 0;
+  EmptyTd->DataBuffer = NULL;
+  EmptyTd->NextTDPointer = NULL;
+  OhciLinkTD (HeadTd, EmptyTd);
+  Ed->TdTailPointer = EmptyTd;
+  OhciAttachTDListToED (Ed, HeadTd);
+
+  OhciSetEDField (Ed, ED_SKIP, 0);
+  OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);
+  OhciSetHcControl (Ohc, BULK_ENABLE, 1);
+  if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) {
+    MicroSecondDelay (HC_1_MILLISECOND);
+    if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) {
+      *TransferResult = EFI_USB_ERR_SYSTEM;
+      goto FREE_TD_BUFF;
+    }
+  }
+
+  TimeCount = 0;
+  Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode);
+
+  while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {
+    MicroSecondDelay (HC_1_MILLISECOND);
+    TimeCount++;
+    Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode);
+  }
+
+  *TransferResult = ConvertErrorCode (ErrorCode);
+
+  if (ErrorCode != TD_NO_ERROR) {
+    if (ErrorCode == TD_TOBE_PROCESSED) {
+      DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));
+    } else {
+      DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));
+    }
+    *DataLength = 0;
+  }
+    *DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);
+
+FREE_TD_BUFF:
+  while (HeadTd) {
+    DataTd = HeadTd;
+    HeadTd = HeadTd->NextTDPointer;
+    UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+  }
+  UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+  return Status;
+}
+/**
+  Retrieves the number of root hub ports.
+
+  @param[in]  PeiServices       The pointer to the PEI Services Table.
+  @param[in]  This              The pointer to this instance of the
+                                PEI_USB_HOST_CONTROLLER_PPI.
+  @param[out] NumOfPorts        The pointer to the number of the root hub ports.
+
+  @retval EFI_SUCCESS           The port number was retrieved successfully.
+  @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubNumOfPorts (
+  IN EFI_PEI_SERVICES             **PeiServices,
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,
+  OUT UINT8                       *NumOfPorts
+  )
+{
+  USB_OHCI_HC_DEV                *Ohc;
+  if (NumOfPorts == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+  *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);
+
+  return EFI_SUCCESS;
+}
+/**
+  Retrieves the current status of a USB root hub port.
+
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.
+  @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  PortNumber             The root hub port to retrieve the state from.
+  @param  PortStatus             Variable to receive the port state.
+
+  @retval EFI_SUCCESS            The status of the USB root hub port specified.
+                                 by PortNumber was returned in PortStatus.
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubPortStatus (
+  IN  EFI_PEI_SERVICES             **PeiServices,
+  IN  PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN  UINT8                        PortNumber,
+  OUT EFI_USB_PORT_STATUS          *PortStatus
+  )
+{
+  USB_OHCI_HC_DEV  *Ohc;
+  UINT8            NumOfPorts;
+
+  Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+
+  OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);
+  if (PortNumber >= NumOfPorts) {
+    return EFI_INVALID_PARAMETER;
+  }
+  PortStatus->PortStatus = 0;
+  PortStatus->PortChangeStatus = 0;
+
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_RESET;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_POWER;
+  }
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {
+    PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;
+  }
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+  Sets a feature for the specified root hub port.
+
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI
+  @param  PortNumber            Root hub port to set.
+  @param  PortFeature           Feature to set.
+
+  @retval EFI_SUCCESS            The feature specified by PortFeature was set.
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
+  @retval EFI_TIMEOUT            The time out occurred.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciSetRootHubPortFeature (
+  IN EFI_PEI_SERVICES             **PeiServices,
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN UINT8                        PortNumber,
+  IN EFI_USB_PORT_FEATURE         PortFeature
+  )
+{
+  USB_OHCI_HC_DEV         *Ohc;
+  EFI_STATUS              Status;
+  UINT8                   NumOfPorts;
+  UINTN                   RetryTimes;
+
+  OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);
+  if (PortNumber >= NumOfPorts) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+
+  Status = EFI_SUCCESS;
+
+
+  switch (PortFeature) {
+    case EfiUsbPortPower:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortReset:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||
+                OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+
+      OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);
+      break;
+
+    case EfiUsbPortEnable:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);;
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+
+    case EfiUsbPortSuspend:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);;
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  return Status;
+}
+
+/**
+  Clears a feature for the specified root hub port.
+
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  PortNumber            Specifies the root hub port whose feature
+                                is requested to be cleared.
+  @param  PortFeature           Indicates the feature selector associated with the
+                                feature clear request.
+
+  @retval EFI_SUCCESS            The feature specified by PortFeature was cleared
+                                 for the USB root hub port specified by PortNumber.
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciClearRootHubPortFeature (
+  IN EFI_PEI_SERVICES             **PeiServices,
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN UINT8                        PortNumber,
+  IN EFI_USB_PORT_FEATURE         PortFeature
+  )
+{
+  USB_OHCI_HC_DEV         *Ohc;
+  EFI_STATUS              Status;
+  UINT8                   NumOfPorts;
+  UINTN                   RetryTimes;
+
+
+  OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);
+  if (PortNumber >= NumOfPorts) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+
+  Status = EFI_SUCCESS;
+
+  switch (PortFeature) {
+    case EfiUsbPortEnable:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortSuspend:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortReset:
+      break;
+
+    case EfiUsbPortPower:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortConnectChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortResetChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+
+    case EfiUsbPortEnableChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortSuspendChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    case EfiUsbPortOverCurrentChange:
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);
+
+      //
+      // Verify the state
+      //
+      RetryTimes = 0;
+      do {
+        MicroSecondDelay (HC_1_MILLISECOND);
+        RetryTimes++;
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&
+               RetryTimes < MAX_RETRY_TIMES);
+
+      if (RetryTimes >= MAX_RETRY_TIMES) {
+        return EFI_DEVICE_ERROR;
+      }
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  return Status;
+}
+/**
+  Provides software reset for the USB host controller.
+
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.
+  @param  Attributes            A bit mask of the reset operation to perform.
+
+  @retval EFI_SUCCESS           The reset operation succeeded.
+  @retval EFI_INVALID_PARAMETER Attributes is not valid.
+  @retval EFI_UNSUPPOURTED      The type of reset specified by Attributes is
+                                not currently supported by the host controller.
+  @retval EFI_DEVICE_ERROR      Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+InitializeUsbHC (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN USB_OHCI_HC_DEV            *Ohc,
+  IN UINT16                     Attributes
+  )
+{
+  EFI_STATUS              Status;
+  UINT8                   Index;
+  UINT8                   NumOfPorts;
+  UINT32                  PowerOnGoodTime;
+  UINT32                  Data32;
+  BOOLEAN                 Flag = FALSE;
+
+  if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+  Status = EFI_SUCCESS;
+
+  if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {
+    MicroSecondDelay (50 * HC_1_MILLISECOND);
+    Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+    MicroSecondDelay (50 * HC_1_MILLISECOND);
+    //
+    // Wait for host controller reset.
+    //
+    PowerOnGoodTime = 50;
+    do {
+      MicroSecondDelay (HC_1_MILLISECOND);
+      Data32 = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS );
+      if ((Data32 & HC_RESET) == 0) {
+        Flag = TRUE;
+        break;
+      }
+    }while(PowerOnGoodTime--);
+    if (!Flag){
+      return EFI_DEVICE_ERROR;
+    }
+  }
+
+  OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);
+  if ((Attributes &  EFI_USB_HC_RESET_GLOBAL) != 0) {
+    Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);
+    if (EFI_ERROR (Status)) {
+      return EFI_DEVICE_ERROR;
+    }
+    MicroSecondDelay (50 * HC_1_MILLISECOND);
+  }
+  //
+  // Initialize host controller operational registers
+  //
+  OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778);
+  OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);
+  OhciSetPeriodicStart (Ohc, 0x2a2f);
+  OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x0);
+  OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0);
+  OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0);
+  OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1);
+  //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);
+  //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);
+
+  OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0);
+  OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff);
+  OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE);
+  OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER);
+  OhciGetRootHubNumOfPorts (PeiServices, &Ohc->UsbHostControllerPpi, &NumOfPorts);
+  for (Index = 0; Index < NumOfPorts; Index++) {
+    if (!EFI_ERROR (OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset))) {
+      MicroSecondDelay (200 * HC_1_MILLISECOND);
+      OhciClearRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset);
+      MicroSecondDelay (HC_1_MILLISECOND);
+      OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortEnable);
+      MicroSecondDelay (HC_1_MILLISECOND);
+    }
+  }
+
+  Ohc->MemPool = UsbHcInitMemPool(TRUE, 0);
+  if(Ohc->MemPool == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+  OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+  OhciSetHcControl (Ohc, CONTROL_ENABLE | BULK_ENABLE, 1);
+  OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);
+  MicroSecondDelay (50 * HC_1_MILLISECOND);
+  //
+  // Wait till first SOF occurs, and then clear it
+  //
+  while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0);
+  OhciClearInterruptStatus (Ohc, START_OF_FRAME);
+  MicroSecondDelay (HC_1_MILLISECOND);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Submits control transfer to a target USB device.
+
+  Calls underlying OhciControlTransfer to do work. This wrapper routine required
+  on Quark so that USB DMA transfers do not cause an IMR violation.
+
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.
+  @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  DeviceAddress          The target device address.
+  @param  DeviceSpeed            Target device speed.
+  @param  MaximumPacketLength    Maximum packet size the default control transfer
+                                 endpoint is capable of sending or receiving.
+  @param  Request                USB device request to send.
+  @param  TransferDirection      Specifies the data direction for the data stage.
+  @param  Data                   Data buffer to be transmitted or received from USB device.
+  @param  DataLength             The size (in bytes) of the data buffer.
+  @param  TimeOut                Indicates the maximum timeout, in millisecond.
+  @param  TransferResult         Return the result of this control transfer.
+
+  @retval EFI_SUCCESS            Transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
+  @retval EFI_TIMEOUT            Transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+RedirectOhciControlTransfer (
+  IN  EFI_PEI_SERVICES             **PeiServices,
+  IN  PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN  UINT8                        DeviceAddress,
+  IN  UINT8                        DeviceSpeed,
+  IN  UINT8                        MaxPacketLength,
+  IN  EFI_USB_DEVICE_REQUEST       *Request,
+  IN  EFI_USB_DATA_DIRECTION       TransferDirection,
+  IN  OUT VOID                     *Data,
+  IN  OUT UINTN                    *DataLength,
+  IN  UINTN                        TimeOut,
+  OUT UINT32                       *TransferResult
+  )
+{
+  EFI_STATUS              Status;
+  EFI_USB_DEVICE_REQUEST  *NewRequest;
+  VOID                    *NewData;
+  UINT8                   *Alloc;
+
+  //
+  // Allocate memory external to IMR protected region for transfer data.
+  //
+  Status = PeiServicesAllocatePool (
+                             sizeof(EFI_USB_DEVICE_REQUEST) + *DataLength,
+                             (VOID **) &Alloc
+                             );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Setup pointers to transfer buffers.
+  //
+  NewRequest = (EFI_USB_DEVICE_REQUEST *) Alloc;
+  Alloc += sizeof(EFI_USB_DEVICE_REQUEST);
+  NewData = (VOID *) Alloc;
+
+  //
+  // Copy callers request packet into transfer request packet.
+  //
+  if (Request != NULL) {
+    CopyMem (NewRequest,Request,sizeof(EFI_USB_DEVICE_REQUEST));
+  } else {
+    NewRequest = NULL;
+  }
+  //
+  // Copy callers data into transfer data buffer.
+  //
+  if (Data != NULL) {
+    if (DataLength > 0) {
+      CopyMem (NewData,Data,*DataLength);
+    }
+  } else {
+    NewData = NULL;
+  }
+
+  //
+  // Call underlying OhciControlTransfer to do work.
+  //
+  Status = OhciControlTransfer (
+             PeiServices,
+             This,
+             DeviceAddress,
+             DeviceSpeed,
+             MaxPacketLength,
+             NewRequest,
+             TransferDirection,
+             NewData,
+             DataLength,
+             TimeOut,
+             TransferResult
+             );
+
+  //
+  // Copy transfer buffer back into callers buffer.
+  //
+  if (Data != NULL && *DataLength > 0) {
+    CopyMem (Data, NewData, *DataLength);
+  }
+
+  return Status;
+}
+
+/**
+  Submits bulk transfer to a bulk endpoint of a USB device.
+
+  Calls underlying OhciBulkTransfer to do work. This wrapper routine required
+  on Quark so that USB DMA transfers do not cause an IMR violation.
+
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  DeviceAddress         Target device address.
+  @param  EndPointAddress       Endpoint number and its direction in bit 7.
+  @param  MaxiPacketLength      Maximum packet size the endpoint is capable of
+                                sending or receiving.
+  @param  Data                  A pointers to the buffers of data to transmit
+                                from or receive into.
+  @param  DataLength            The lenght of the data buffer.
+  @param  DataToggle            On input, the initial data toggle for the transfer;
+                                On output, it is updated to to next data toggle to use of
+                                the subsequent bulk transfer.
+  @param  TimeOut               Indicates the maximum time, in millisecond, which the
+                                transfer is allowed to complete.
+  @param  TransferResult        A pointer to the detailed result information of the
+                                bulk transfer.
+
+  @retval EFI_SUCCESS           The transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+RedirectOhciBulkTransfer (
+  IN EFI_PEI_SERVICES             **PeiServices,
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN  UINT8                       DeviceAddress,
+  IN  UINT8                       EndPointAddress,
+  IN  UINT8                       MaxPacketLength,
+  IN  OUT VOID                    *Data,
+  IN  OUT UINTN                   *DataLength,
+  IN  OUT UINT8                   *DataToggle,
+  IN  UINTN                       TimeOut,
+  OUT UINT32                      *TransferResult
+  )
+{
+  EFI_STATUS              Status;
+  UINT8                   *NewData;
+
+  //
+  // Allocate memory external to IMR protected region for transfer data.
+  //
+  Status = PeiServicesAllocatePool (
+                             *DataLength,
+                             (VOID **) &NewData
+                             );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Copy callers data into transfer buffer.
+  //
+  if (Data != NULL) {
+    if (DataLength > 0) {
+      CopyMem (NewData,Data,*DataLength);
+    }
+  } else {
+    NewData = NULL;
+  }
+
+  //
+  // Call underlying OhciBulkTransfer to do work.
+  //
+  Status = OhciBulkTransfer (
+             PeiServices,
+             This,
+             DeviceAddress,
+             EndPointAddress,
+             MaxPacketLength,
+             NewData,
+             DataLength,
+             DataToggle,
+             TimeOut,
+             TransferResult
+             );
+
+  //
+  // Copy transfer buffer back into callers buffer.
+  //
+  if (Data != NULL && *DataLength > 0) {
+    CopyMem (Data, NewData, *DataLength);
+  }
+
+  return Status;
+}
+
+/**
+  @param  FileHandle  Handle of the file being invoked.
+  @param  PeiServices Describes the list of possible PEI Services.
+
+  @retval EFI_SUCCESS            PPI successfully installed.
+
+**/
+EFI_STATUS
+OhcPeimEntry (
+  IN EFI_PEI_FILE_HANDLE        FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+
+  PEI_USB_CONTROLLER_PPI  *ChipSetUsbControllerPpi;
+  EFI_STATUS              Status;
+  UINT8                   Index;
+  UINTN                   ControllerType;
+  UINTN                   BaseAddress;
+  UINTN                   MemPages;
+  USB_OHCI_HC_DEV         *Ohc;
+  EFI_PHYSICAL_ADDRESS    TempPtr;
+
+
+  //
+  // Shadow this PEIM to run from memory
+  //
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+    return EFI_SUCCESS;
+  }
+  Status = PeiServicesLocatePpi (
+             &gPeiUsbControllerPpiGuid,
+             0,
+             NULL,
+             (VOID **) &ChipSetUsbControllerPpi
+             );
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Index = 0;
+  while (TRUE) {
+    Status = ChipSetUsbControllerPpi->GetUsbController (
+                                        (EFI_PEI_SERVICES **) PeiServices,
+                                        ChipSetUsbControllerPpi,
+                                        Index,
+                                        &ControllerType,
+                                        &BaseAddress
+                                        );
+    //
+    // When status is error, meant no controller is found
+    //
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+    //
+    // This PEIM is for OHC type controller.
+    //
+    if (ControllerType != PEI_OHCI_CONTROLLER) {
+      Index++;
+      continue;
+    }
+
+    MemPages = sizeof (USB_OHCI_HC_DEV) / PAGESIZE + 1;
+    Status = PeiServicesAllocatePages (
+               EfiBootServicesCode,
+               MemPages,
+               &TempPtr
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to allocate buffer for the %dth OHCI ControllerPpi\n", Index));
+      return EFI_OUT_OF_RESOURCES;
+    }
+    ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);
+    Ohc = (USB_OHCI_HC_DEV *) ((UINTN) TempPtr);
+
+    Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE;
+
+    Ohc->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
+
+    //
+    // Initialize Uhc's hardware
+    //
+    Status = InitializeUsbHC (
+               (EFI_PEI_SERVICES **)PeiServices,
+               Ohc,
+               EFI_USB_HC_RESET_GLOBAL
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to init %dth OHCI ControllerPpi\n", Index));
+      return Status;
+    }
+    //
+    // Control & Bulk transfer services are accessed via their Redirect
+    // routine versions on Quark so that USB DMA transfers do not cause an
+    // IMR violation.
+    //
+    Ohc->UsbHostControllerPpi.ControlTransfer          = RedirectOhciControlTransfer;
+    Ohc->UsbHostControllerPpi.BulkTransfer             = RedirectOhciBulkTransfer;
+    Ohc->UsbHostControllerPpi.GetRootHubPortNumber     = OhciGetRootHubNumOfPorts;
+    Ohc->UsbHostControllerPpi.GetRootHubPortStatus     = OhciGetRootHubPortStatus;
+    Ohc->UsbHostControllerPpi.SetRootHubPortFeature    = OhciSetRootHubPortFeature;
+    Ohc->UsbHostControllerPpi.ClearRootHubPortFeature  = OhciClearRootHubPortFeature;
+
+    Ohc->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+    Ohc->PpiDescriptor.Guid  = &gPeiUsbHostControllerPpiGuid;
+    Ohc->PpiDescriptor.Ppi   = &Ohc->UsbHostControllerPpi;
+
+    Status = PeiServicesInstallPpi (&Ohc->PpiDescriptor);
+    if (EFI_ERROR (Status)) {
+      Index++;
+      continue;
+    }
+    Index++;
+  }
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h
new file mode 100644
index 0000000000..c34f94cdd7
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h
@@ -0,0 +1,252 @@
+/** @file
+Provides the definition of Usb Hc Protocol and OHCI controller
+private data structure.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#ifndef _OHCI_PEIM_H
+#define _OHCI_PEIM_H
+
+#include <PiPei.h>
+
+#include <Ppi/UsbController.h>
+#include <Ppi/UsbHostController.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/IoLib.h>
+
+typedef struct _USB_OHCI_HC_DEV USB_OHCI_HC_DEV;
+
+#include "UsbHcMem.h"
+#include "OhciReg.h"
+#include "OhciSched.h"
+#include "OhciUrb.h"
+#include "Descriptor.h"
+
+#define EFI_USB_SPEED_FULL 0x0000
+#define EFI_USB_SPEED_LOW  0x0001
+#define EFI_USB_SPEED_HIGH 0x0002
+
+#define PAGESIZE                    4096
+
+#define HC_1_MICROSECOND            1
+#define HC_1_MILLISECOND            (1000 * HC_1_MICROSECOND)
+#define HC_1_SECOND                 (1000 * HC_1_MILLISECOND)
+
+
+#define USB_OHCI_HC_DEV_SIGNATURE   SIGNATURE_32('o','h','c','i')
+
+struct _USB_OHCI_HC_DEV {
+  UINTN                        Signature;
+  PEI_USB_HOST_CONTROLLER_PPI  UsbHostControllerPpi;
+  EFI_PEI_PPI_DESCRIPTOR       PpiDescriptor;
+  UINT32                       UsbHostControllerBaseAddress;
+  VOID                         *MemPool;
+};
+
+#define PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS(a)  CR (a, USB_OHCI_HC_DEV, UsbHostControllerPpi, USB_OHCI_HC_DEV_SIGNATURE)
+
+//
+// Func List
+//
+
+/**
+  Provides software reset for the USB host controller.
+
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  Attributes            A bit mask of the reset operation to perform.
+
+  @retval EFI_SUCCESS           The reset operation succeeded.
+  @retval EFI_INVALID_PARAMETER Attributes is not valid.
+  @retval EFI_UNSUPPOURTED      The type of reset specified by Attributes is
+                                not currently supported by the host controller.
+  @retval EFI_DEVICE_ERROR      Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+InitializeUsbHC (
+  IN EFI_PEI_SERVICES   **PeiServices,
+  IN USB_OHCI_HC_DEV    *Ohc,
+  IN UINT16             Attributes
+  );
+
+/**
+  Submits control transfer to a target USB device.
+
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.
+  @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  DeviceAddress          The target device address.
+  @param  DeviceSpeed            Target device speed.
+  @param  MaximumPacketLength    Maximum packet size the default control transfer
+                                 endpoint is capable of sending or receiving.
+  @param  Request                USB device request to send.
+  @param  TransferDirection      Specifies the data direction for the data stage.
+  @param  Data                   Data buffer to be transmitted or received from USB device.
+  @param  DataLength             The size (in bytes) of the data buffer.
+  @param  TimeOut                Indicates the maximum timeout, in millisecond.
+  @param  TransferResult         Return the result of this control transfer.
+
+  @retval EFI_SUCCESS            Transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
+  @retval EFI_TIMEOUT            Transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciControlTransfer (
+  IN  EFI_PEI_SERVICES                    **PeiServices,
+  IN  PEI_USB_HOST_CONTROLLER_PPI         *This,
+  IN  UINT8                               DeviceAddress,
+  IN  UINT8                               DeviceSpeed,
+  IN  UINT8                               MaxPacketLength,
+  IN  EFI_USB_DEVICE_REQUEST              *Request,
+  IN  EFI_USB_DATA_DIRECTION              TransferDirection,
+  IN  OUT VOID                            *Data,
+  IN  OUT UINTN                           *DataLength,
+  IN  UINTN                               TimeOut,
+  OUT UINT32                              *TransferResult
+  );
+/**
+  Submits bulk transfer to a bulk endpoint of a USB device.
+
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  DeviceAddress         Target device address.
+  @param  EndPointAddress       Endpoint number and its direction in bit 7.
+  @param  MaxiPacketLength      Maximum packet size the endpoint is capable of
+                                sending or receiving.
+  @param  Data                  A pointers to the buffers of data to transmit
+                                from or receive into.
+  @param  DataLength            The lenght of the data buffer.
+  @param  DataToggle            On input, the initial data toggle for the transfer;
+                                On output, it is updated to to next data toggle to use of
+                                the subsequent bulk transfer.
+  @param  TimeOut               Indicates the maximum time, in millisecond, which the
+                                transfer is allowed to complete.
+  @param  TransferResult        A pointer to the detailed result information of the
+                                bulk transfer.
+
+  @retval EFI_SUCCESS           The transfer was completed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciBulkTransfer (
+  IN EFI_PEI_SERVICES                     **PeiServices,
+  IN PEI_USB_HOST_CONTROLLER_PPI          *This,
+  IN  UINT8                               DeviceAddress,
+  IN  UINT8                               EndPointAddress,
+  IN  UINT8                               MaxPacketLength,
+  IN  OUT VOID                            *Data,
+  IN  OUT UINTN                           *DataLength,
+  IN  OUT UINT8                           *DataToggle,
+  IN  UINTN                               TimeOut,
+  OUT UINT32                              *TransferResult
+  );
+/**
+  Retrieves the number of root hub ports.
+
+  @param[in]  PeiServices       The pointer to the PEI Services Table.
+  @param[in]  This              The pointer to this instance of the
+                                PEI_USB_HOST_CONTROLLER_PPI.
+  @param[out] NumOfPorts        The pointer to the number of the root hub ports.
+
+  @retval EFI_SUCCESS           The port number was retrieved successfully.
+  @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubNumOfPorts (
+  IN EFI_PEI_SERVICES                       **PeiServices,
+  IN PEI_USB_HOST_CONTROLLER_PPI           *This,
+  OUT UINT8                *NumOfPorts
+  );
+/**
+  Retrieves the current status of a USB root hub port.
+
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.
+  @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  PortNumber             The root hub port to retrieve the state from.
+  @param  PortStatus             Variable to receive the port state.
+
+  @retval EFI_SUCCESS            The status of the USB root hub port specified.
+                                 by PortNumber was returned in PortStatus.
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubPortStatus (
+  IN  EFI_PEI_SERVICES             **PeiServices,
+  IN  PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN  UINT8                        PortNumber,
+  OUT EFI_USB_PORT_STATUS          *PortStatus
+  );
+/**
+
+  Sets a feature for the specified root hub port.
+
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL.
+  @param  PortNumber            Specifies the root hub port whose feature
+                                is requested to be set.
+  @param  PortFeature           Indicates the feature selector associated
+                                with the feature set request.
+
+  @retval EFI_SUCCESS           The feature specified by PortFeature was set for the
+                                USB root hub port specified by PortNumber.
+  @retval EFI_DEVICE_ERROR      Set feature failed because of hardware issue
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+**/
+EFI_STATUS
+EFIAPI
+OhciSetRootHubPortFeature (
+  IN EFI_PEI_SERVICES             **PeiServices,
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN UINT8                        PortNumber,
+  IN EFI_USB_PORT_FEATURE         PortFeature
+  );
+/**
+  Clears a feature for the specified root hub port.
+
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+  @param  PortNumber            Specifies the root hub port whose feature
+                                is requested to be cleared.
+  @param  PortFeature           Indicates the feature selector associated with the
+                                feature clear request.
+
+  @retval EFI_SUCCESS            The feature specified by PortFeature was cleared
+                                 for the USB root hub port specified by PortNumber.
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciClearRootHubPortFeature (
+  IN EFI_PEI_SERVICES             **PeiServices,
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,
+  IN UINT8                        PortNumber,
+  IN EFI_USB_PORT_FEATURE         PortFeature
+  );
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf
new file mode 100644
index 0000000000..b1060d527d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf
@@ -0,0 +1,56 @@
+## @file
+# OHCI USB Host Controller PEIM
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = OhciPei
+  FILE_GUID                      = 332A0926-429B-4624-9211-A36B23DF0389
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = OhcPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  Descriptor.h
+  OhcPeim.c
+  OhcPeim.h
+  OhciSched.c
+  OhciSched.h
+  OhciReg.c
+  OhciReg.h
+  OhciUrb.c
+  OhciUrb.h
+  UsbHcMem.c
+  UsbHcMem.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  IoLib
+  TimerLib
+  BaseMemoryLib
+  PeimEntryPoint
+  PeiServicesLib
+
+[Ppis]
+  gPeiUsbHostControllerPpiGuid                 # PPI ALWAYS_PRODUCED
+  gPeiUsbControllerPpiGuid                      # PPI ALWAYS_CONSUMED
+
+[Depex]
+  gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c
new file mode 100644
index 0000000000..b291cdafa6
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c
@@ -0,0 +1,1386 @@
+/** @file
+The OHCI register operation routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "OhcPeim.h"
+
+/**
+
+  Get OHCI operational reg value
+
+  @param  Ohc                   UHC private data
+  @param  Offset                Offset of the operational reg
+
+  @retval                       Value of the register
+
+**/
+UINT32
+OhciGetOperationalReg (
+  IN USB_OHCI_HC_DEV         *Ohc,
+  IN UINT32                  Offset
+  )
+{
+
+  return MmioRead32 (Ohc->UsbHostControllerBaseAddress + Offset);
+
+}
+/**
+
+  Set OHCI operational reg value
+
+  @param  Ohc                   UHC private data
+  @param  Offset                 Offset of the operational reg
+  @param  Value                  Value to set
+
+  @retval EFI_SUCCESS            Value set to the reg
+
+**/
+
+
+EFI_STATUS
+OhciSetOperationalReg (
+  USB_OHCI_HC_DEV         *Ohc,
+  IN UINT32               Offset,
+  IN UINT32               *Value
+  )
+{
+  MmioWrite32(Ohc->UsbHostControllerBaseAddress + Offset, *Value);
+  return EFI_SUCCESS;
+}
+/**
+
+  Get HcRevision reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of the register
+
+**/
+
+
+UINT32
+OhciGetHcRevision (
+  USB_OHCI_HC_DEV         *Ohc
+  )
+{
+  return OhciGetOperationalReg (Ohc, HC_REVISION);
+}
+/**
+
+  Set HcReset reg value
+
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcReset (
+  IN USB_OHCI_HC_DEV            *Ohc,
+  IN UINT32                     Field,
+  IN UINT32                     Value
+  )
+{
+  HcRESET                       Reset;
+
+  *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR);
+
+  if (Field & RESET_SYSTEM_BUS) {
+    Reset.FSBIR = Value;
+  }
+
+  if (Field & RESET_HOST_CONTROLLER) {
+    Reset.FHR = Value;
+  }
+
+  if (Field & RESET_CLOCK_GENERATION) {
+    Reset.CGR = Value;
+  }
+
+  if (Field & RESET_SSE_GLOBAL) {
+    Reset.SSE = Value;
+  }
+
+  if (Field & RESET_PSPL) {
+    Reset.PSPL = Value;
+  }
+
+  if (Field & RESET_PCPL) {
+    Reset.PCPL = Value;
+  }
+
+  if (Field & RESET_SSEP1) {
+    Reset.SSEP1 = Value;
+  }
+
+  if (Field & RESET_SSEP2) {
+    Reset.SSEP2 = Value;
+  }
+
+  if (Field & RESET_SSEP3) {
+    Reset.SSEP3 = Value;
+  }
+
+  OhciSetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR, (UINT32*)&Reset);
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Get specific field of HcReset reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcReset (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Field
+  )
+{
+  HcRESET                 Reset;
+  UINT32                  Value;
+
+
+  *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR);
+  Value = 0;
+
+  switch (Field) {
+  case RESET_SYSTEM_BUS:
+    Value = Reset.FSBIR;
+    break;
+
+  case RESET_HOST_CONTROLLER:
+    Value = Reset.FHR;
+    break;
+
+  case RESET_CLOCK_GENERATION:
+    Value = Reset.CGR;
+    break;
+
+  case RESET_SSE_GLOBAL:
+    Value = Reset.SSE;
+    break;
+
+  case RESET_PSPL:
+    Value = Reset.PSPL;
+    break;
+
+  case RESET_PCPL:
+    Value = Reset.PCPL;
+    break;
+
+  case RESET_SSEP1:
+    Value = Reset.SSEP1;
+    break;
+
+  case RESET_SSEP2:
+    Value = Reset.SSEP2;
+    break;
+
+  case RESET_SSEP3:
+    Value = Reset.SSEP3;
+    break;
+
+  default:
+    ASSERT (FALSE);
+  }
+
+
+  return Value;
+}
+
+/**
+
+  Set HcControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcCONTROL               Control;
+
+
+
+  *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL);
+
+  if (Field & CONTROL_BULK_RATIO) {
+    Control.ControlBulkRatio = Value;
+  }
+
+  if (Field & HC_FUNCTIONAL_STATE) {
+    Control.FunctionalState = Value;
+  }
+
+  if (Field & PERIODIC_ENABLE) {
+    Control.PeriodicEnable = Value;
+  }
+
+  if (Field & CONTROL_ENABLE) {
+    Control.ControlEnable = Value;
+  }
+
+  if (Field & ISOCHRONOUS_ENABLE) {
+    Control.IsochronousEnable = Value;
+  }
+
+  if (Field & BULK_ENABLE) {
+    Control.BulkEnable = Value;
+  }
+
+  if (Field & INTERRUPT_ROUTING) {
+    Control.InterruptRouting = Value;
+  }
+
+  Status = OhciSetOperationalReg (Ohc, HC_CONTROL, (UINT32*)&Control);
+
+  return Status;
+}
+
+
+/**
+
+  Get specific field of HcControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+
+UINT32
+OhciGetHcControl (
+  IN USB_OHCI_HC_DEV   *Ohc,
+  IN UINTN             Field
+  )
+{
+  HcCONTROL     Control;
+
+  *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL);
+
+  switch (Field) {
+  case CONTROL_BULK_RATIO:
+    return Control.ControlBulkRatio;
+    break;
+  case PERIODIC_ENABLE:
+    return Control.PeriodicEnable;
+    break;
+  case CONTROL_ENABLE:
+    return Control.ControlEnable;
+    break;
+  case BULK_ENABLE:
+    return Control.BulkEnable;
+    break;
+  case ISOCHRONOUS_ENABLE:
+    return Control.IsochronousEnable;
+    break;
+  case HC_FUNCTIONAL_STATE:
+    return Control.FunctionalState;
+    break;
+  case INTERRUPT_ROUTING:
+    return Control.InterruptRouting;
+    break;
+  default:
+    ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set HcCommand reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcCommandStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcCOMMAND_STATUS        CommandStatus;
+
+  ZeroMem (&CommandStatus, sizeof (HcCOMMAND_STATUS));
+
+  if(Field & HC_RESET){
+    CommandStatus.HcReset = Value;
+  }
+
+  if(Field & CONTROL_LIST_FILLED){
+    CommandStatus.ControlListFilled = Value;
+  }
+
+  if(Field & BULK_LIST_FILLED){
+    CommandStatus.BulkListFilled = Value;
+  }
+
+  if(Field & CHANGE_OWNER_REQUEST){
+    CommandStatus.ChangeOwnerRequest = Value;
+  }
+
+  if(Field & SCHEDULE_OVERRUN_COUNT){
+    CommandStatus.ScheduleOverrunCount = Value;
+  }
+
+  Status = OhciSetOperationalReg (Ohc, HC_COMMAND_STATUS, (UINT32*)&CommandStatus);
+
+  return Status;
+}
+
+/**
+
+  Get specific field of HcCommand reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcCommandStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcCOMMAND_STATUS        CommandStatus;
+
+  *(UINT32 *) &CommandStatus = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS);
+
+  switch (Field){
+  case HC_RESET:
+    return CommandStatus.HcReset;
+    break;
+  case CONTROL_LIST_FILLED:
+    return CommandStatus.ControlListFilled;
+    break;
+  case BULK_LIST_FILLED:
+    return CommandStatus.BulkListFilled;
+    break;
+  case CHANGE_OWNER_REQUEST:
+    return CommandStatus.ChangeOwnerRequest;
+    break;
+  case SCHEDULE_OVERRUN_COUNT:
+    return CommandStatus.ScheduleOverrunCount;
+    break;
+  default:
+    ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Clear specific fields of Interrupt Status
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to clear
+
+  @retval EFI_SUCCESS           Fields cleared
+
+**/
+
+EFI_STATUS
+OhciClearInterruptStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  EFI_STATUS              Status;
+  HcINTERRUPT_STATUS      InterruptStatus;
+
+  ZeroMem (&InterruptStatus, sizeof (HcINTERRUPT_STATUS));
+
+  if(Field & SCHEDULE_OVERRUN){
+    InterruptStatus.SchedulingOverrun = 1;
+  }
+
+  if(Field & WRITEBACK_DONE_HEAD){
+    InterruptStatus.WriteBackDone = 1;
+  }
+  if(Field & START_OF_FRAME){
+    InterruptStatus.Sof = 1;
+  }
+
+  if(Field & RESUME_DETECT){
+    InterruptStatus.ResumeDetected = 1;
+  }
+
+  if(Field & UNRECOVERABLE_ERROR){
+    InterruptStatus.UnrecoverableError = 1;
+  }
+
+  if(Field & FRAME_NUMBER_OVERFLOW){
+    InterruptStatus.FrameNumOverflow = 1;
+  }
+
+  if(Field & ROOTHUB_STATUS_CHANGE){
+    InterruptStatus.RHStatusChange = 1;
+  }
+
+  if(Field & OWNERSHIP_CHANGE){
+    InterruptStatus.OwnerChange = 1;
+  }
+
+  Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_STATUS, (UINT32*)&InterruptStatus);
+
+  return Status;
+}
+
+/**
+
+  Get fields of HcInterrupt reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcINTERRUPT_STATUS      InterruptStatus;
+
+  *(UINT32 *) &InterruptStatus = OhciGetOperationalReg (Ohc, HC_INTERRUPT_STATUS);
+
+  switch (Field){
+  case SCHEDULE_OVERRUN:
+    return InterruptStatus.SchedulingOverrun;
+    break;
+
+  case  WRITEBACK_DONE_HEAD:
+    return InterruptStatus.WriteBackDone;
+    break;
+
+  case START_OF_FRAME:
+    return InterruptStatus.Sof;
+    break;
+
+  case RESUME_DETECT:
+    return InterruptStatus.ResumeDetected;
+    break;
+
+  case UNRECOVERABLE_ERROR:
+    return InterruptStatus.UnrecoverableError;
+    break;
+
+  case FRAME_NUMBER_OVERFLOW:
+    return InterruptStatus.FrameNumOverflow;
+    break;
+
+  case ROOTHUB_STATUS_CHANGE:
+    return InterruptStatus.RHStatusChange;
+    break;
+
+  case OWNERSHIP_CHANGE:
+    return InterruptStatus.OwnerChange;
+    break;
+
+  default:
+    ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set Interrupt Control reg value
+
+  @param  Ohc                   UHC private data
+  @param  StatEnable            Enable or Disable
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetInterruptControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN BOOLEAN              StatEnable,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcINTERRUPT_CONTROL     InterruptState;
+
+
+  ZeroMem (&InterruptState, sizeof (HcINTERRUPT_CONTROL));
+
+  if(Field & SCHEDULE_OVERRUN) {
+    InterruptState.SchedulingOverrunInt = Value;
+  }
+
+  if(Field & WRITEBACK_DONE_HEAD) {
+    InterruptState.WriteBackDoneInt = Value;
+  }
+  if(Field & START_OF_FRAME) {
+    InterruptState.SofInt = Value;
+  }
+
+  if(Field & RESUME_DETECT) {
+    InterruptState.ResumeDetectedInt = Value;
+  }
+
+  if(Field & UNRECOVERABLE_ERROR) {
+    InterruptState.UnrecoverableErrorInt = Value;
+  }
+
+  if(Field & FRAME_NUMBER_OVERFLOW) {
+    InterruptState.FrameNumOverflowInt = Value;
+  }
+
+  if(Field & ROOTHUB_STATUS_CHANGE) {
+    InterruptState.RHStatusChangeInt = Value;
+  }
+
+  if(Field & OWNERSHIP_CHANGE) {
+    InterruptState.OwnerChangedInt = Value;
+  }
+
+  if(Field & MASTER_INTERRUPT) {
+    InterruptState.MasterInterruptEnable = Value;
+  }
+
+  if (StatEnable) {
+    Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_ENABLE, (UINT32*)&InterruptState);
+  } else {
+    Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_DISABLE, (UINT32*)&InterruptState);
+  }
+
+  return Status;
+}
+
+/**
+
+  Get field of HcInterruptControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcINTERRUPT_CONTROL     InterruptState;
+
+  *(UINT32 *) &InterruptState = OhciGetOperationalReg (Ohc, HC_INTERRUPT_ENABLE);
+
+  switch (Field){
+    case SCHEDULE_OVERRUN:
+      return InterruptState.SchedulingOverrunInt;
+      break;
+
+    case WRITEBACK_DONE_HEAD:
+      return InterruptState.WriteBackDoneInt;
+      break;
+
+    case START_OF_FRAME:
+      return InterruptState.SofInt;
+      break;
+
+    case RESUME_DETECT:
+      return InterruptState.ResumeDetectedInt;
+      break;
+
+    case UNRECOVERABLE_ERROR:
+      return InterruptState.UnrecoverableErrorInt;
+      break;
+
+    case FRAME_NUMBER_OVERFLOW:
+      return InterruptState.FrameNumOverflowInt;
+      break;
+
+    case ROOTHUB_STATUS_CHANGE:
+      return InterruptState.RHStatusChangeInt;
+      break;
+
+    case OWNERSHIP_CHANGE:
+      return InterruptState.OwnerChangedInt;
+      break;
+
+    case MASTER_INTERRUPT:
+      return InterruptState.MasterInterruptEnable;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set memory pointer of specific type
+
+  @param  Ohc                   UHC private data
+  @param  PointerType           Type of the pointer to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Memory pointer set
+
+**/
+
+EFI_STATUS
+OhciSetMemoryPointer(
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                PointerType,
+  IN VOID                 *Value
+  )
+{
+  EFI_STATUS              Status;
+  UINT32                  Verify;
+
+  Status = OhciSetOperationalReg (Ohc, PointerType, (UINT32*)&Value);
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Verify = OhciGetOperationalReg (Ohc, PointerType);
+
+  while (Verify != (UINT32) Value) {
+    MicroSecondDelay (HC_1_MILLISECOND);
+    Verify = OhciGetOperationalReg (Ohc, PointerType);
+  };
+
+
+  return Status;
+}
+
+/**
+
+  Get memory pointer of specific type
+
+  @param  Ohc                   UHC private data
+  @param  PointerType           Type of pointer
+
+  @retval                       Memory pointer of the specific type
+
+**/
+
+VOID *
+OhciGetMemoryPointer (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                PointerType
+  )
+{
+
+  return (VOID *) OhciGetOperationalReg (Ohc, PointerType);
+}
+
+
+/**
+
+  Set Frame Interval value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameInterval (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcFRM_INTERVAL          FrameInterval;
+
+
+  *(UINT32 *) &FrameInterval = OhciGetOperationalReg(Ohc, HC_FRM_INTERVAL);
+
+  if (Field & FRAME_INTERVAL) {
+    FrameInterval.FrmIntervalToggle = !FrameInterval.FrmIntervalToggle;
+    FrameInterval.FrameInterval = Value;
+  }
+
+  if (Field & FS_LARGEST_DATA_PACKET) {
+    FrameInterval.FSMaxDataPacket = Value;
+  }
+
+  if (Field & FRMINT_TOGGLE) {
+    FrameInterval.FrmIntervalToggle = Value;
+  }
+
+  Status = OhciSetOperationalReg (
+             Ohc,
+             HC_FRM_INTERVAL,
+             (UINT32*)&FrameInterval
+             );
+
+  return Status;
+}
+
+
+/**
+
+  Get field of frame interval reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetFrameInterval (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcFRM_INTERVAL          FrameInterval;
+
+  *(UINT32 *) &FrameInterval = OhciGetOperationalReg (Ohc, HC_FRM_INTERVAL);
+
+  switch (Field){
+    case FRAME_INTERVAL:
+      return FrameInterval.FrameInterval;
+      break;
+
+    case FS_LARGEST_DATA_PACKET:
+      return FrameInterval.FSMaxDataPacket;
+      break;
+
+    case FRMINT_TOGGLE:
+      return FrameInterval.FrmIntervalToggle;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set Frame Remaining reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameRemaining (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcFRAME_REMAINING       FrameRemaining;
+
+
+  *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING);
+
+  FrameRemaining.FrameRemaining = Value;
+  FrameRemaining.FrameRemainingToggle = !FrameRemaining.FrameRemainingToggle;
+
+  Status = OhciSetOperationalReg (Ohc, HC_FRM_REMAINING, (UINT32*)&FrameRemaining);
+
+  return Status;
+}
+/**
+
+  Get value of frame remaining reg
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of frame remaining reg
+
+**/
+UINT32
+OhciGetFrameRemaining (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+
+{
+  HcFRAME_REMAINING       FrameRemaining;
+
+
+  *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING);
+
+  switch (Field){
+    case FRAME_REMAINING:
+      return FrameRemaining.FrameRemaining;
+      break;
+
+    case FRAME_REMAIN_TOGGLE:
+      return FrameRemaining.FrameRemainingToggle;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+/**
+
+  Set frame number reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameNumber(
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+
+  Status = OhciSetOperationalReg (Ohc, HC_FRM_NUMBER, &Value);
+
+  return Status;
+}
+
+/**
+
+  Get frame number reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of frame number reg
+
+**/
+
+UINT32
+OhciGetFrameNumber (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  return OhciGetOperationalReg(Ohc, HC_FRM_NUMBER);
+}
+
+/**
+
+  Set period start reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetPeriodicStart (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+
+
+  Status = OhciSetOperationalReg (Ohc, HC_PERIODIC_START, &Value);
+
+  return Status;
+}
+
+
+/**
+
+  Get periodic start reg value
+
+  @param  Ohc                   UHC private data
+
+  @param                        Value of periodic start reg
+
+**/
+
+UINT32
+OhciGetPeriodicStart (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  return OhciGetOperationalReg(Ohc, HC_PERIODIC_START);
+}
+
+
+/**
+
+  Set Ls Threshold reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetLsThreshold (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+
+
+  Status = OhciSetOperationalReg (Ohc, HC_LS_THREASHOLD, &Value);
+
+  return Status;
+}
+
+
+/**
+
+  Get Ls Threshold reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of Ls Threshold reg
+
+**/
+
+UINT32
+OhciGetLsThreshold (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  return OhciGetOperationalReg(Ohc, HC_LS_THREASHOLD);
+}
+
+/**
+
+  Set Root Hub Descriptor reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetRootHubDescriptor (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  )
+{
+  EFI_STATUS              Status;
+  HcRH_DESC_A             DescriptorA;
+  HcRH_DESC_B             DescriptorB;
+
+
+  if (Field & (RH_DEV_REMOVABLE || RH_PORT_PWR_CTRL_MASK)) {
+    *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B);
+
+    if(Field & RH_DEV_REMOVABLE) {
+      DescriptorB.DeviceRemovable = Value;
+    }
+    if(Field & RH_PORT_PWR_CTRL_MASK) {
+      DescriptorB.PortPowerControlMask = Value;
+    }
+
+    Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_B, (UINT32*)&DescriptorB);
+
+    return Status;
+  }
+
+  *(UINT32 *)&DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A);
+
+  if(Field & RH_NUM_DS_PORTS) {
+    DescriptorA.NumDownStrmPorts = Value;
+  }
+  if(Field & RH_NO_PSWITCH) {
+    DescriptorA.NoPowerSwitch = Value;
+  }
+  if(Field & RH_PSWITCH_MODE) {
+    DescriptorA.PowerSwitchMode = Value;
+  }
+  if(Field & RH_DEVICE_TYPE) {
+    DescriptorA.DeviceType = Value;
+  }
+  if(Field & RH_OC_PROT_MODE) {
+    DescriptorA.OverCurrentProtMode = Value;
+  }
+  if(Field & RH_NOC_PROT) {
+    DescriptorA.NoOverCurrentProtMode = Value;
+  }
+  if(Field & RH_NO_POTPGT) {
+    DescriptorA.PowerOnToPowerGoodTime = Value;
+  }
+
+  Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_A, (UINT32*)&DescriptorA);
+
+  return Status;
+}
+
+
+/**
+
+  Get Root Hub Descriptor reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubDescriptor (
+  IN USB_OHCI_HC_DEV     *Ohc,
+  IN UINTN               Field
+  )
+{
+  HcRH_DESC_A             DescriptorA;
+  HcRH_DESC_B             DescriptorB;
+
+
+  *(UINT32 *) &DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A);
+  *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B);
+
+  switch (Field){
+    case RH_DEV_REMOVABLE:
+      return DescriptorB.DeviceRemovable;
+      break;
+
+    case RH_PORT_PWR_CTRL_MASK:
+      return DescriptorB.PortPowerControlMask;
+      break;
+
+    case RH_NUM_DS_PORTS:
+      return DescriptorA.NumDownStrmPorts;
+      break;
+
+    case RH_NO_PSWITCH:
+      return DescriptorA.NoPowerSwitch;
+      break;
+
+    case RH_PSWITCH_MODE:
+      return DescriptorA.PowerSwitchMode;
+      break;
+
+    case RH_DEVICE_TYPE:
+      return DescriptorA.DeviceType;
+      break;
+
+    case RH_OC_PROT_MODE:
+      return DescriptorA.OverCurrentProtMode;
+      break;
+
+    case RH_NOC_PROT:
+      return DescriptorA.NoOverCurrentProtMode;
+      break;
+
+    case RH_NO_POTPGT:
+      return DescriptorA.PowerOnToPowerGoodTime;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+
+/**
+
+  Set Root Hub Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  EFI_STATUS              Status;
+  HcRH_STATUS             RootHubStatus;
+
+
+  ZeroMem (&RootHubStatus, sizeof(HcRH_STATUS));
+
+  if(Field & RH_LOCAL_PSTAT){
+    RootHubStatus.LocalPowerStat = 1;
+  }
+  if(Field & RH_OC_ID){
+    RootHubStatus.OverCurrentIndicator = 1;
+  }
+  if(Field & RH_REMOTE_WK_ENABLE){
+    RootHubStatus.DevRemoteWakeupEnable = 1;
+  }
+  if(Field & RH_LOCAL_PSTAT_CHANGE){
+    RootHubStatus.LocalPowerStatChange = 1;
+  }
+  if(Field & RH_OC_ID_CHANGE){
+    RootHubStatus.OverCurrentIndicatorChange = 1;
+  }
+  if(Field & RH_CLR_RMT_WK_ENABLE){
+    RootHubStatus.ClearRemoteWakeupEnable = 1;
+  }
+
+  Status = OhciSetOperationalReg (Ohc, HC_RH_STATUS, (UINT32*)&RootHubStatus);
+
+  return Status;
+}
+
+
+/**
+
+  Get Root Hub Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  )
+{
+  HcRH_STATUS             RootHubStatus;
+
+
+  *(UINT32 *) &RootHubStatus = OhciGetOperationalReg (Ohc, HC_RH_STATUS);
+
+  switch (Field) {
+    case RH_LOCAL_PSTAT:
+      return RootHubStatus.LocalPowerStat;
+      break;
+    case RH_OC_ID:
+      return RootHubStatus.OverCurrentIndicator;
+      break;
+    case RH_REMOTE_WK_ENABLE:
+      return RootHubStatus.DevRemoteWakeupEnable;
+      break;
+    case RH_LOCAL_PSTAT_CHANGE:
+      return RootHubStatus.LocalPowerStatChange;
+      break;
+    case RH_OC_ID_CHANGE:
+      return RootHubStatus.OverCurrentIndicatorChange;
+      break;
+    case RH_CLR_RMT_WK_ENABLE:
+      return RootHubStatus.ClearRemoteWakeupEnable;
+      break;
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+
+/**
+
+  Set Root Hub Port Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Index                 Index of the port
+  @param  Field                 Field to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubPortStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Index,
+  IN UINTN                Field
+  )
+{
+  EFI_STATUS              Status;
+  HcRHPORT_STATUS         PortStatus;
+
+
+  ZeroMem (&PortStatus, sizeof(HcRHPORT_STATUS));
+
+  if (Field & RH_CLEAR_PORT_ENABLE) {
+    PortStatus.CurrentConnectStat = 1;
+  }
+  if (Field & RH_SET_PORT_ENABLE) {
+    PortStatus.EnableStat = 1;
+  }
+  if (Field & RH_SET_PORT_SUSPEND) {
+    PortStatus.SuspendStat = 1;
+  }
+  if (Field & RH_CLEAR_SUSPEND_STATUS) {
+    PortStatus.OCIndicator = 1;
+  }
+  if (Field & RH_SET_PORT_RESET) {
+    PortStatus.ResetStat = 1;
+  }
+  if (Field & RH_SET_PORT_POWER) {
+    PortStatus.PowerStat = 1;
+  }
+  if (Field & RH_CLEAR_PORT_POWER) {
+    PortStatus.LsDeviceAttached = 1;
+  }
+  if (Field & RH_CONNECT_STATUS_CHANGE) {
+    PortStatus.ConnectStatChange = 1;
+  }
+  if (Field & RH_PORT_ENABLE_STAT_CHANGE) {
+    PortStatus.EnableStatChange = 1;
+  }
+  if (Field & RH_PORT_SUSPEND_STAT_CHANGE) {
+    PortStatus.SuspendStatChange = 1;
+  }
+  if (Field & RH_OC_INDICATOR_CHANGE) {
+    PortStatus.OCIndicatorChange = 1;
+  }
+  if (Field & RH_PORT_RESET_STAT_CHANGE ) {
+    PortStatus.ResetStatChange = 1;
+  }
+
+  Status = OhciSetOperationalReg (Ohc, HC_RH_PORT_STATUS + (Index * 4), (UINT32*)&PortStatus);
+
+  return Status;
+}
+
+
+/**
+
+  Get Root Hub Port Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Index                 Index of the port
+  @param  Field                 Field to get
+
+  @retval                       Value of the field and index
+
+**/
+
+UINT32
+OhciReadRootHubPortStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Index,
+  IN UINTN                Field
+  )
+{
+  HcRHPORT_STATUS         PortStatus;
+
+  *(UINT32 *) &PortStatus = OhciGetOperationalReg (
+                              Ohc,
+                              HC_RH_PORT_STATUS + (Index * 4)
+                              );
+
+  switch (Field){
+  case RH_CURR_CONNECT_STAT:
+    return PortStatus.CurrentConnectStat;
+    break;
+  case RH_PORT_ENABLE_STAT:
+    return PortStatus.EnableStat;
+    break;
+  case RH_PORT_SUSPEND_STAT:
+    return PortStatus.SuspendStat;
+    break;
+  case RH_PORT_OC_INDICATOR:
+    return PortStatus.OCIndicator;
+    break;
+  case RH_PORT_RESET_STAT:
+    return PortStatus.ResetStat;
+    break;
+  case RH_PORT_POWER_STAT:
+    return PortStatus.PowerStat;
+    break;
+  case RH_LSDEVICE_ATTACHED:
+    return PortStatus.LsDeviceAttached;
+    break;
+  case RH_CONNECT_STATUS_CHANGE:
+    return PortStatus.ConnectStatChange;
+    break;
+  case RH_PORT_ENABLE_STAT_CHANGE:
+    return PortStatus.EnableStatChange;
+    break;
+  case RH_PORT_SUSPEND_STAT_CHANGE:
+    return PortStatus.SuspendStatChange;
+    break;
+  case RH_OC_INDICATOR_CHANGE:
+    return PortStatus.OCIndicatorChange;
+    break;
+  case RH_PORT_RESET_STAT_CHANGE:
+    return PortStatus.ResetStatChange;
+    break;
+  default:
+    ASSERT (FALSE);
+  }
+
+  return 0;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h
new file mode 100644
index 0000000000..9b31bf53ee
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h
@@ -0,0 +1,875 @@
+/** @file
+This file contains the definination for host controller
+register operation routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#ifndef   _OHCI_REGS_H
+#define   _OHCI_REGS_H
+
+#define   HC_STATE_RESET         0x0
+#define   HC_STATE_RESUME        0x1
+#define   HC_STATE_OPERATIONAL   0x2
+#define   HC_STATE_SUSPEND       0x3
+
+#define   PERIODIC_ENABLE               0x01
+#define   ISOCHRONOUS_ENABLE            0x02
+#define   CONTROL_ENABLE                0x04
+#define   BULK_ENABLE                   0x08
+#define   CONTROL_BULK_RATIO            0x10
+
+#define   HC_FUNCTIONAL_STATE    0x20
+#define   INTERRUPT_ROUTING      0x40
+
+#define   HC_RESET               0x01
+#define   CONTROL_LIST_FILLED    0x02
+#define   BULK_LIST_FILLED       0x04
+#define   CHANGE_OWNER_REQUEST   0x08
+
+#define   SCHEDULE_OVERRUN_COUNT 0x10
+
+#define   SCHEDULE_OVERRUN       0x00001
+#define   WRITEBACK_DONE_HEAD    0x00002
+#define   START_OF_FRAME         0x00004
+#define   RESUME_DETECT          0x00008
+#define   UNRECOVERABLE_ERROR    0x00010
+#define   FRAME_NUMBER_OVERFLOW  0x00020
+#define   ROOTHUB_STATUS_CHANGE  0x00040
+#define   OWNERSHIP_CHANGE       0x00080
+
+#define   MASTER_INTERRUPT       0x00400
+
+#define   CONTROL_HEAD           0x001
+#define   BULK_HEAD              0x002
+#define   DONE_HEAD              0x004
+
+#define   Hc_HCCA                0x001
+#define   Hc_PERIODIC_CURRENT    0x002
+#define   Hc_CONTOL_HEAD         0x004
+#define   Hc_CONTROL_CURRENT_PTR 0x008
+#define   Hc_BULK_HEAD           0x010
+#define   Hc_BULK_CURRENT_PTR    0x020
+#define   Hc_DONE_HEAD           0x040
+
+#define   FRAME_INTERVAL         0x008
+#define   FS_LARGEST_DATA_PACKET 0x010
+#define   FRMINT_TOGGLE          0x020
+#define   FRAME_REMAINING        0x040
+#define   FRAME_REMAIN_TOGGLE    0x080
+
+#define   RH_DESC_A              0x00001
+#define   RH_DESC_B              0x00002
+#define   RH_NUM_DS_PORTS        0x00004
+#define   RH_NO_PSWITCH          0x00008
+#define   RH_PSWITCH_MODE        0x00010
+#define   RH_DEVICE_TYPE         0x00020
+#define   RH_OC_PROT_MODE        0x00040
+#define   RH_NOC_PROT            0x00080
+#define   RH_POTPGT              0x00100
+#define   RH_NO_POTPGT           0x00200
+#define   RH_DEV_REMOVABLE       0x00400
+#define   RH_PORT_PWR_CTRL_MASK  0x00800
+
+#define   RH_LOCAL_PSTAT         0x00001
+#define   RH_OC_ID               0x00002
+#define   RH_REMOTE_WK_ENABLE    0x00004
+#define   RH_LOCAL_PSTAT_CHANGE  0x00008
+#define   RH_OC_ID_CHANGE        0x00010
+#define   RH_CLR_RMT_WK_ENABLE   0x00020
+
+#define   RH_CLEAR_PORT_ENABLE        0x0001
+#define   RH_SET_PORT_ENABLE          0x0002
+#define   RH_SET_PORT_SUSPEND         0x0004
+#define   RH_CLEAR_SUSPEND_STATUS     0x0008
+#define   RH_SET_PORT_RESET           0x0010
+#define   RH_SET_PORT_POWER           0x0020
+#define   RH_CLEAR_PORT_POWER         0x0040
+#define   RH_CONNECT_STATUS_CHANGE    0x10000
+#define   RH_PORT_ENABLE_STAT_CHANGE  0x20000
+#define   RH_PORT_SUSPEND_STAT_CHANGE 0x40000
+#define   RH_OC_INDICATOR_CHANGE      0x80000
+#define   RH_PORT_RESET_STAT_CHANGE   0x100000
+
+#define   RH_CURR_CONNECT_STAT        0x0001
+#define   RH_PORT_ENABLE_STAT         0x0002
+#define   RH_PORT_SUSPEND_STAT        0x0004
+#define   RH_PORT_OC_INDICATOR        0x0008
+#define   RH_PORT_RESET_STAT          0x0010
+#define   RH_PORT_POWER_STAT          0x0020
+#define   RH_LSDEVICE_ATTACHED        0x0040
+
+#define   RESET_SYSTEM_BUS            (1 << 0)
+#define   RESET_HOST_CONTROLLER       (1 << 1)
+#define   RESET_CLOCK_GENERATION      (1 << 2)
+#define   RESET_SSE_GLOBAL            (1 << 5)
+#define   RESET_PSPL                  (1 << 6)
+#define   RESET_PCPL                  (1 << 7)
+#define   RESET_SSEP1                 (1 << 9)
+#define   RESET_SSEP2                 (1 << 10)
+#define   RESET_SSEP3                 (1 << 11)
+
+#define ONE_SECOND                      1000000
+#define ONE_MILLI_SEC                   1000
+#define MAX_BYTES_PER_TD                0x1000
+#define MAX_RETRY_TIMES                 100
+#define PORT_NUMBER_ON_MAINSTONE2       1
+
+
+//
+// Operational Register Offsets
+//
+
+//
+// Command & Status Registers Offsets
+//
+#define HC_REVISION             0x00
+#define HC_CONTROL              0x04
+#define HC_COMMAND_STATUS       0x08
+#define HC_INTERRUPT_STATUS     0x0C
+#define HC_INTERRUPT_ENABLE     0x10
+#define HC_INTERRUPT_DISABLE    0x14
+
+//
+// Memory Pointer Offsets
+//
+#define HC_HCCA                 0x18
+#define HC_PERIODIC_CURRENT     0x1C
+#define HC_CONTROL_HEAD         0x20
+#define HC_CONTROL_CURRENT_PTR  0x24
+#define HC_BULK_HEAD            0x28
+#define HC_BULK_CURRENT_PTR     0x2C
+#define HC_DONE_HEAD            0x30
+
+//
+// Frame Register Offsets
+//
+#define HC_FRM_INTERVAL         0x34
+#define HC_FRM_REMAINING        0x38
+#define HC_FRM_NUMBER           0x3C
+#define HC_PERIODIC_START       0x40
+#define HC_LS_THREASHOLD        0x44
+
+//
+// Root Hub Register Offsets
+//
+#define HC_RH_DESC_A            0x48
+#define HC_RH_DESC_B            0x4C
+#define HC_RH_STATUS            0x50
+#define HC_RH_PORT_STATUS       0x54
+
+#define USBHOST_OFFSET_UHCHR         0x64         // Usb Host reset register
+
+#define OHC_BAR_INDEX               0
+
+//
+// Usb Host controller register offset
+//
+#define USBHOST_OFFSET_UHCREV        0x0          // Usb Host revision register
+#define USBHOST_OFFSET_UHCHCON       0x4          // Usb Host control register
+#define USBHOST_OFFSET_UHCCOMS       0x8          // Usb Host Command Status register
+#define USBHOST_OFFSET_UHCINTS       0xC          // Usb Host Interrupt Status register
+#define USBHOST_OFFSET_UHCINTE       0x10         // Usb Host Interrupt Enable register
+#define USBHOST_OFFSET_UHCINTD       0x14         // Usb Host Interrupt Disable register
+#define USBHOST_OFFSET_UHCHCCA       0x18         // Usb Host Controller Communication Area
+#define USBHOST_OFFSET_UHCPCED       0x1C         // Usb Host Period Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCCHED       0x20         // Usb Host Control Head Endpoint Descriptor
+#define USBHOST_OFFSET_UHCCCED       0x24         // Usb Host Control Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCBHED       0x28         // Usb Host Bulk Head Endpoint Descriptor
+#define USBHOST_OFFSET_UHCBCED       0x2C         // Usb Host Bulk Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCDHEAD      0x30         // Usb Host Done Head register
+#define USBHOST_OFFSET_UHCFMI        0x34         // Usb Host Frame Interval register
+#define USBHOST_OFFSET_UHCFMR        0x38         // Usb Host Frame Remaining register
+#define USBHOST_OFFSET_UHCFMN        0x3C         // Usb Host Frame Number register
+#define USBHOST_OFFSET_UHCPERS       0x40         // Usb Host Periodic Start register
+#define USBHOST_OFFSET_UHCLST        0x44         // Usb Host Low-Speed Threshold register
+#define USBHOST_OFFSET_UHCRHDA       0x48         // Usb Host Root Hub Descriptor A register
+#define USBHOST_OFFSET_UHCRHDB       0x4C         // Usb Host Root Hub Descriptor B register
+#define USBHOST_OFFSET_UHCRHS        0x50         // Usb Host Root Hub Status register
+#define USBHOST_OFFSET_UHCRHPS1      0x54         // Usb Host Root Hub Port Status 1 register
+
+//
+// Usb Host controller register bit fields
+//
+#pragma pack(1)
+
+typedef struct {
+  UINT8                   ProgInterface;
+  UINT8                   SubClassCode;
+  UINT8                   BaseCode;
+} USB_CLASSC;
+
+typedef struct {
+    UINT32 Revision:8;
+    UINT32 Rsvd:24;
+} HcREVISION;
+
+typedef struct {
+    UINT32 ControlBulkRatio:2;
+    UINT32 PeriodicEnable:1;
+    UINT32 IsochronousEnable:1;
+    UINT32 ControlEnable:1;
+    UINT32 BulkEnable:1;
+    UINT32 FunctionalState:2;
+    UINT32 InterruptRouting:1;
+    UINT32 RemoteWakeup:1;
+    UINT32 RemoteWakeupEnable:1;
+    UINT32 Reserved:21;
+} HcCONTROL;
+
+typedef struct {
+    UINT32 HcReset:1;
+    UINT32 ControlListFilled:1;
+    UINT32 BulkListFilled:1;
+    UINT32 ChangeOwnerRequest:1;
+    UINT32 Reserved1:12;
+    UINT32 ScheduleOverrunCount:2;
+    UINT32 Reserved:14;
+} HcCOMMAND_STATUS;
+
+typedef struct {
+    UINT32 SchedulingOverrun:1;
+    UINT32 WriteBackDone:1;
+    UINT32 Sof:1;
+    UINT32 ResumeDetected:1;
+    UINT32 UnrecoverableError:1;
+    UINT32 FrameNumOverflow:1;
+    UINT32 RHStatusChange:1;
+    UINT32 Reserved1:23;
+    UINT32 OwnerChange:1;
+    UINT32 Reserved2:1;
+} HcINTERRUPT_STATUS;
+
+typedef struct {
+    UINT32 SchedulingOverrunInt:1;
+    UINT32 WriteBackDoneInt:1;
+    UINT32 SofInt:1;
+    UINT32 ResumeDetectedInt:1;
+    UINT32 UnrecoverableErrorInt:1;
+    UINT32 FrameNumOverflowInt:1;
+    UINT32 RHStatusChangeInt:1;
+    UINT32 Reserved:23;
+    UINT32 OwnerChangedInt:1;
+    UINT32 MasterInterruptEnable:1;
+} HcINTERRUPT_CONTROL;
+
+typedef struct {
+    UINT32 Rerserved:8;
+    UINT32 Hcca:24;
+} HcHCCA;
+
+typedef struct {
+    UINT32 Reserved:4;
+    UINT32 MemoryPtr:28;
+} HcMEMORY_PTR;
+
+typedef struct {
+    UINT32 FrameInterval:14;
+    UINT32 Reserved:2;
+    UINT32 FSMaxDataPacket:15;
+    UINT32 FrmIntervalToggle:1;
+} HcFRM_INTERVAL;
+
+typedef struct {
+    UINT32 FrameRemaining:14;
+    UINT32 Reserved:17;
+    UINT32 FrameRemainingToggle:1;
+} HcFRAME_REMAINING;
+
+typedef struct {
+    UINT32 FrameNumber:16;
+    UINT32 Reserved:16;
+} HcFRAME_NUMBER;
+
+typedef struct {
+    UINT32 PeriodicStart:14;
+    UINT32 Reserved:18;
+} HcPERIODIC_START;
+
+typedef struct {
+    UINT32 LsThreshold:12;
+    UINT32 Reserved:20;
+} HcLS_THRESHOLD;
+
+typedef struct {
+    UINT32 NumDownStrmPorts:8;
+    UINT32 PowerSwitchMode:1;
+    UINT32 NoPowerSwitch:1;
+    UINT32 DeviceType:1;
+    UINT32 OverCurrentProtMode:1;
+    UINT32 NoOverCurrentProtMode:1;
+    UINT32 Reserved:11;
+    UINT32 PowerOnToPowerGoodTime:8;
+} HcRH_DESC_A;
+
+typedef struct {
+    UINT32 DeviceRemovable:16;
+    UINT32 PortPowerControlMask:16;
+} HcRH_DESC_B;
+
+typedef struct {
+    UINT32 LocalPowerStat:1;
+    UINT32 OverCurrentIndicator:1;
+    UINT32 Reserved1:13;
+    UINT32 DevRemoteWakeupEnable:1;
+    UINT32 LocalPowerStatChange:1;
+    UINT32 OverCurrentIndicatorChange:1;
+    UINT32 Reserved2:13;
+    UINT32 ClearRemoteWakeupEnable:1;
+} HcRH_STATUS;
+
+typedef struct {
+    UINT32 CurrentConnectStat:1;
+    UINT32 EnableStat:1;
+    UINT32 SuspendStat:1;
+    UINT32 OCIndicator:1;
+    UINT32 ResetStat:1;
+    UINT32 Reserved1:3;
+    UINT32 PowerStat:1;
+    UINT32 LsDeviceAttached:1;
+    UINT32 Reserved2:6;
+    UINT32 ConnectStatChange:1;
+    UINT32 EnableStatChange:1;
+    UINT32 SuspendStatChange:1;
+    UINT32 OCIndicatorChange:1;
+    UINT32 ResetStatChange:1;
+    UINT32 Reserved3:11;
+} HcRHPORT_STATUS;
+
+typedef struct {
+    UINT32 FSBIR:1;
+    UINT32 FHR:1;
+    UINT32 CGR:1;
+    UINT32 SSDC:1;
+    UINT32 UIT:1;
+    UINT32 SSE:1;
+    UINT32 PSPL:1;
+    UINT32 PCPL:1;
+    UINT32 Reserved0:1;
+    UINT32 SSEP1:1;
+    UINT32 SSEP2:1;
+    UINT32 SSEP3:1;
+    UINT32 Reserved1:20;
+} HcRESET;
+
+#pragma pack()
+
+//
+// Func List
+//
+/**
+
+  Get OHCI operational reg value
+
+  @param  Ohc                   UHC private data
+  @param  Offset                Offset of the operational reg
+
+  @retval                       Value of the register
+
+**/
+UINT32
+OhciGetOperationalReg (
+  IN USB_OHCI_HC_DEV         *Ohc,
+  IN UINT32                  Offset
+  );
+/**
+
+  Set OHCI operational reg value
+
+  @param  Ohc                   UHC private data
+  @param  Offset                 Offset of the operational reg
+  @param  Value                  Value to set
+
+  @retval EFI_SUCCESS            Value set to the reg
+
+**/
+EFI_STATUS
+OhciSetOperationalReg (
+  USB_OHCI_HC_DEV         *Ohc,
+  IN UINT32               Offset,
+  IN UINT32               *Value
+  );
+/**
+
+  Get HcRevision reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of the register
+
+**/
+
+
+UINT32
+OhciGetHcRevision (
+  USB_OHCI_HC_DEV         *Ohc
+  );
+
+/**
+
+  Set HcReset reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcReset (
+  IN USB_OHCI_HC_DEV            *Ohc,
+  IN UINT32                     Field,
+  IN UINT32                     Value
+  );
+/**
+
+  Get specific field of HcReset reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcReset (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Field
+  );
+/**
+
+  Set HcControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+/**
+
+  Get specific field of HcControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+
+UINT32
+OhciGetHcControl (
+  IN USB_OHCI_HC_DEV   *Ohc,
+  IN UINTN             Field
+  );
+/**
+
+  Set HcCommand reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcCommandStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+/**
+
+  Get specific field of HcCommand reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcCommandStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+/**
+
+  Clear specific fields of Interrupt Status
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to clear
+
+  @retval EFI_SUCCESS           Fields cleared
+
+**/
+
+EFI_STATUS
+OhciClearInterruptStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+/**
+
+  Get fields of HcInterrupt reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+/**
+
+  Set Interrupt Control reg value
+
+  @param  Ohc                   UHC private data
+  @param  StatEnable            Enable or Disable
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetInterruptControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN BOOLEAN              StatEnable,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+/**
+
+  Get field of HcInterruptControl reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptControl (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+/**
+
+  Set memory pointer of specific type
+
+  @param  Ohc                   UHC private data
+  @param  PointerType           Type of the pointer to set
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Memory pointer set
+
+**/
+
+EFI_STATUS
+OhciSetMemoryPointer(
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                PointerType,
+  IN VOID                 *Value
+  );
+/**
+
+  Get memory pointer of specific type
+
+  @param  Ohc                   UHC private data
+  @param  PointerType           Type of pointer
+
+  @retval                       Memory pointer of the specific type
+
+**/
+
+VOID *
+OhciGetMemoryPointer (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                PointerType
+  );
+/**
+
+  Set Frame Interval value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameInterval (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+/**
+
+  Get field of frame interval reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetFrameInterval (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+/**
+
+  Set Frame Remaining reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameRemaining (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  );
+/**
+
+  Get value of frame remaining reg
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of frame remaining reg
+
+**/
+UINT32
+OhciGetFrameRemaining (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+/**
+
+  Set frame number reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameNumber(
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  );
+/**
+
+  Get frame number reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of frame number reg
+
+**/
+
+UINT32
+OhciGetFrameNumber (
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+/**
+
+  Set period start reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval EFI_SUCCESS           Value set
+
+**/
+
+EFI_STATUS
+OhciSetPeriodicStart (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  );
+/**
+
+  Get periodic start reg value
+
+  @param  Ohc                   UHC private data
+
+  @param                        Value of periodic start reg
+
+**/
+
+UINT32
+OhciGetPeriodicStart (
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+/**
+
+  Set Ls Threshold reg value
+
+  @param  Ohc                   UHC private data
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetLsThreshold (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Value
+  );
+/**
+
+  Get Ls Threshold reg value
+
+  @param  Ohc                   UHC private data
+
+  @retval                       Value of Ls Threshold reg
+
+**/
+
+UINT32
+OhciGetLsThreshold (
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+/**
+
+  Set Root Hub Descriptor reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+  @param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetRootHubDescriptor (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field,
+  IN UINT32               Value
+  );
+/**
+
+  Get Root Hub Descriptor reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubDescriptor (
+  IN USB_OHCI_HC_DEV     *Ohc,
+  IN UINTN               Field
+  );
+/**
+
+  Set Root Hub Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+/**
+
+  Get Root Hub Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Field                 Field to get
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINTN                Field
+  );
+/**
+
+  Set Root Hub Port Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Index                 Index of the port
+  @param  Field                 Field to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubPortStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Index,
+  IN UINTN                Field
+  );
+/**
+
+  Get Root Hub Port Status reg value
+
+  @param  Ohc                   UHC private data
+  @param  Index                 Index of the port
+  @param  Field                 Field to get
+
+  @retval                       Value of the field and index
+
+**/
+
+UINT32
+OhciReadRootHubPortStatus (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN UINT32               Index,
+  IN UINTN                Field
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c
new file mode 100644
index 0000000000..2ba0133e51
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c
@@ -0,0 +1,223 @@
+/** @file
+OHCI transfer scheduling routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "OhcPeim.h"
+
+/**
+
+  Convert Error code from OHCI format to EFI format
+
+  @Param  ErrorCode             ErrorCode in OHCI format
+
+  @retval                       ErrorCode in EFI format
+
+**/
+UINT32
+ConvertErrorCode (
+  IN  UINT32              ErrorCode
+  )
+{
+  UINT32                  TransferResult;
+
+  switch (ErrorCode) {
+    case TD_NO_ERROR:
+      TransferResult = EFI_USB_NOERROR;
+      break;
+
+    case TD_TOBE_PROCESSED:
+    case TD_TOBE_PROCESSED_2:
+      TransferResult = EFI_USB_ERR_NOTEXECUTE;
+      break;
+
+    case TD_DEVICE_STALL:
+      TransferResult = EFI_USB_ERR_STALL;
+      break;
+
+    case TD_BUFFER_OVERRUN:
+    case TD_BUFFER_UNDERRUN:
+      TransferResult = EFI_USB_ERR_BUFFER;
+      break;
+
+    case TD_CRC_ERROR:
+      TransferResult = EFI_USB_ERR_CRC;
+      break;
+
+    case TD_NO_RESPONSE:
+      TransferResult = EFI_USB_ERR_TIMEOUT;
+      break;
+
+    case TD_BITSTUFFING_ERROR:
+      TransferResult = EFI_USB_ERR_BITSTUFF;
+      break;
+
+    default:
+      TransferResult = EFI_USB_ERR_SYSTEM;
+  }
+
+  return TransferResult;
+}
+
+
+/**
+
+  Check TDs Results
+
+  @Param  Ohc                   UHC private data
+  @Param  Td                    TD_DESCRIPTOR
+  @Param  Result                Result to return
+
+  @retval TRUE                  means OK
+  @retval FLASE                 means Error or Short packet
+
+**/
+BOOLEAN
+OhciCheckTDsResults (
+  IN  USB_OHCI_HC_DEV     *Ohc,
+  IN  TD_DESCRIPTOR       *Td,
+  OUT UINT32              *Result
+  )
+{
+  UINT32                  TdCompletionCode;
+
+  *Result   = EFI_USB_NOERROR;
+
+  while (Td) {
+    TdCompletionCode = Td->Word0.ConditionCode;
+
+    *Result |= ConvertErrorCode(TdCompletionCode);
+    //
+    // if any error encountered, stop processing the left TDs.
+    //
+    if (*Result) {
+      return FALSE;
+    }
+
+    Td = Td->NextTDPointer;
+  }
+  return TRUE;
+
+}
+
+
+/**
+
+  Check the task status on an ED
+
+  @Param  Ed                    Pointer to the ED task that TD hooked on
+  @Param  HeadTd                TD header for current transaction
+
+  @retval                       Task Status Code
+
+**/
+
+UINT32
+CheckEDStatus (
+  IN  ED_DESCRIPTOR       *Ed,
+  IN  TD_DESCRIPTOR       *HeadTd
+  )
+{
+  while(HeadTd != NULL) {
+    if (HeadTd->Word0.ConditionCode != 0) {
+      return HeadTd->Word0.ConditionCode;
+    }
+    HeadTd = HeadTd->NextTDPointer;
+  }
+
+  if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) {
+    return TD_TOBE_PROCESSED;
+  }
+
+  return TD_NO_ERROR;
+}
+
+/**
+
+  Check the task status
+
+  @Param  Ohc                   UHC private data
+  @Param  ListType              Pipe type
+  @Param  Ed                    Pointer to the ED task hooked on
+  @Param  HeadTd                Head of TD corresponding to the task
+  @Param  ErrorCode             return the ErrorCode
+
+  @retval  EFI_SUCCESS          Task done
+  @retval  EFI_NOT_READY        Task on processing
+  @retval  EFI_DEVICE_ERROR     Some error occured
+
+**/
+EFI_STATUS
+CheckIfDone (
+  IN  USB_OHCI_HC_DEV       *Ohc,
+  IN  DESCRIPTOR_LIST_TYPE  ListType,
+  IN  ED_DESCRIPTOR         *Ed,
+  IN  TD_DESCRIPTOR         *HeadTd,
+  OUT UINT32                *ErrorCode
+  )
+{
+  *ErrorCode = TD_TOBE_PROCESSED;
+
+  switch (ListType) {
+    case CONTROL_LIST:
+      if (OhciGetHcCommandStatus (Ohc, CONTROL_LIST_FILLED) != 0) {
+        return EFI_NOT_READY;
+      }
+      break;
+
+    case BULK_LIST:
+      if (OhciGetHcCommandStatus (Ohc, BULK_LIST_FILLED) != 0) {
+        return EFI_NOT_READY;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  *ErrorCode = CheckEDStatus (Ed, HeadTd);
+
+
+  if (*ErrorCode == TD_NO_ERROR) {
+    return EFI_SUCCESS;
+  } else if (*ErrorCode == TD_TOBE_PROCESSED) {
+    return EFI_NOT_READY;
+  } else {
+    return EFI_DEVICE_ERROR;
+  }
+}
+
+
+/**
+
+  Convert TD condition code to Efi Status
+
+  @Param  ConditionCode         Condition code to convert
+
+  @retval  EFI_SUCCESS          No error occured
+  @retval  EFI_NOT_READY        TD still on processing
+  @retval  EFI_DEVICE_ERROR     Error occured in processing TD
+
+**/
+
+EFI_STATUS
+OhciTDConditionCodeToStatus (
+  IN  UINT32              ConditionCode
+  )
+{
+  if (ConditionCode == TD_NO_ERROR) {
+    return EFI_SUCCESS;
+  }
+
+  if (ConditionCode == TD_TOBE_PROCESSED) {
+    return EFI_NOT_READY;
+  }
+
+  return EFI_DEVICE_ERROR;
+}
+
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h
new file mode 100644
index 0000000000..53b4b38d45
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h
@@ -0,0 +1,108 @@
+/** @file
+This file contains the definination for host controller schedule routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#ifndef _OHCI_SCHED_H
+#define _OHCI_SCHED_H
+
+#include "Descriptor.h"
+
+#define HCCA_MEM_SIZE     256
+#define GRID_SIZE         16
+#define GRID_SHIFT        4
+
+/**
+
+  Convert Error code from OHCI format to EFI format
+
+  @Param  ErrorCode             ErrorCode in OHCI format
+
+  @retval                       ErrorCode in EFI format
+
+**/
+UINT32
+ConvertErrorCode (
+  IN  UINT32              ErrorCode
+  );
+/**
+
+  Check TDs Results
+
+  @Param  Ohc                   UHC private data
+  @Param  Td                    TD_DESCRIPTOR
+  @Param  Result                Result to return
+
+  @retval TRUE                  means OK
+  @retval FLASE                 means Error or Short packet
+
+**/
+BOOLEAN
+OhciCheckTDsResults (
+  IN  USB_OHCI_HC_DEV     *Ohc,
+  IN  TD_DESCRIPTOR       *Td,
+  OUT UINT32              *Result
+  );
+/**
+
+  Check the task status on an ED
+
+  @Param  Ed                    Pointer to the ED task that TD hooked on
+  @Param  HeadTd                TD header for current transaction
+
+  @retval                       Task Status Code
+
+**/
+
+UINT32
+CheckEDStatus (
+  IN  ED_DESCRIPTOR       *Ed,
+  IN  TD_DESCRIPTOR       *HeadTd
+  );
+/**
+
+  Check the task status
+
+  @Param  Ohc                   UHC private data
+  @Param  ListType              Pipe type
+  @Param  Ed                    Pointer to the ED task hooked on
+  @Param  HeadTd                Head of TD corresponding to the task
+  @Param  ErrorCode             return the ErrorCode
+
+  @retval  EFI_SUCCESS          Task done
+  @retval  EFI_NOT_READY        Task on processing
+  @retval  EFI_DEVICE_ERROR     Some error occured
+
+**/
+EFI_STATUS
+CheckIfDone (
+  IN  USB_OHCI_HC_DEV       *Ohc,
+  IN  DESCRIPTOR_LIST_TYPE  ListType,
+  IN  ED_DESCRIPTOR         *Ed,
+  IN  TD_DESCRIPTOR         *HeadTd,
+  OUT UINT32                *ErrorCode
+  );
+/**
+
+  Convert TD condition code to Efi Status
+
+  @Param  ConditionCode         Condition code to convert
+
+  @retval  EFI_SUCCESS          No error occured
+  @retval  EFI_NOT_READY        TD still on processing
+  @retval  EFI_DEVICE_ERROR     Error occured in processing TD
+
+**/
+
+EFI_STATUS
+OhciTDConditionCodeToStatus (
+  IN  UINT32              ConditionCode
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c
new file mode 100644
index 0000000000..96d036c706
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c
@@ -0,0 +1,560 @@
+/** @file
+This file contains URB request, each request is warpped in a
+URB (Usb Request Block).
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+
+#include "OhcPeim.h"
+
+
+/**
+
+  Create a TD
+
+  @Param  Ohc                   UHC private data
+
+  @retval                       TD structure pointer
+
+**/
+TD_DESCRIPTOR *
+OhciCreateTD (
+  IN USB_OHCI_HC_DEV      *Ohc
+  )
+{
+  TD_DESCRIPTOR           *Td;
+
+  Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR));
+  if (Td == NULL) {
+    return NULL;
+  }
+  Td->CurrBufferPointer = NULL;
+  Td->NextTD = NULL;
+  Td->BufferEndPointer = NULL;
+  Td->NextTDPointer = NULL;
+
+  return Td;
+}
+
+
+/**
+
+  Free a TD
+
+  @Param  Ohc                   UHC private data
+  @Param  Td                    Pointer to a TD to free
+
+  @retval  EFI_SUCCESS          TD freed
+
+**/
+EFI_STATUS
+OhciFreeTD (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN TD_DESCRIPTOR        *Td
+  )
+{
+  if (Td == NULL) {
+    return EFI_SUCCESS;
+  }
+  UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Create a ED
+
+  @Param   Ohc                  Device private data
+
+  @retval  ED                   descriptor pointer
+
+**/
+ED_DESCRIPTOR *
+OhciCreateED (
+  USB_OHCI_HC_DEV          *Ohc
+  )
+{
+  ED_DESCRIPTOR   *Ed;
+  Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR));
+  if (Ed == NULL) {
+    return NULL;
+  }
+  Ed->Word0.Skip = 1;
+  Ed->TdTailPointer = NULL;
+  Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) NULL);
+  Ed->NextED = NULL;
+
+  return Ed;
+}
+
+/**
+
+  Free a ED
+
+  @Param  Ohc                   UHC private data
+  @Param  Ed                    Pointer to a ED to free
+
+  @retval  EFI_SUCCESS          ED freed
+
+**/
+
+EFI_STATUS
+OhciFreeED (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *Ed
+  )
+{
+  if (Ed == NULL) {
+    return EFI_SUCCESS;
+  }
+  UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Free  ED
+
+  @Param  Ohc                    Device private data
+  @Param  Ed                     Pointer to a ED to free
+
+  @retval  EFI_SUCCESS           ED freed
+
+**/
+EFI_STATUS
+OhciFreeAllTDFromED (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *Ed
+  )
+{
+  TD_DESCRIPTOR           *HeadTd;
+  TD_DESCRIPTOR           *TailTd;
+  TD_DESCRIPTOR           *Td;
+  TD_DESCRIPTOR           *TempTd;
+
+  if (Ed == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  HeadTd = TD_PTR (Ed->Word2.TdHeadPointer);
+  TailTd = Ed->TdTailPointer;
+
+  Td = HeadTd;
+  while (Td != TailTd) {
+    TempTd = Td;
+    Td = Td->NextTDPointer;
+    OhciFreeTD (Ohc, TempTd);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Attach an ED
+
+  @Param  Ed                    Ed to be attached
+  @Param  NewEd                 Ed to attach
+
+  @retval EFI_SUCCESS           NewEd attached to Ed
+  @retval EFI_INVALID_PARAMETER Ed is NULL
+
+**/
+EFI_STATUS
+OhciAttachED (
+  IN ED_DESCRIPTOR        *Ed,
+  IN ED_DESCRIPTOR        *NewEd
+  )
+{
+  ED_DESCRIPTOR           *Temp;
+
+  if (Ed == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Ed->NextED == NULL){
+    Ed->NextED = NewEd;
+  } else {
+    Temp = Ed->NextED;
+    Ed->NextED = NewEd;
+    NewEd->NextED = Temp;
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+
+  Attach an ED to an ED list
+
+  @Param  OHC                   UHC private data
+  @Param  ListType              Type of the ED list
+  @Param  Ed                    ED to attach
+  @Param  EdList                ED list to be attached
+
+  @retval  EFI_SUCCESS          ED attached to ED list
+
+**/
+EFI_STATUS
+OhciAttachEDToList (
+  IN USB_OHCI_HC_DEV       *Ohc,
+  IN DESCRIPTOR_LIST_TYPE  ListType,
+  IN ED_DESCRIPTOR         *Ed,
+  IN ED_DESCRIPTOR         *EdList
+  )
+{
+  ED_DESCRIPTOR            *HeadEd;
+
+  switch(ListType) {
+    case CONTROL_LIST:
+      HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD);
+      if (HeadEd == NULL) {
+        OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed);
+      } else {
+        OhciAttachED (HeadEd, Ed);
+      }
+    break;
+
+    case BULK_LIST:
+      HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD);
+      if (HeadEd == NULL) {
+        OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed);
+      } else {
+        OhciAttachED (HeadEd, Ed);
+      }
+    break;
+
+    case INTERRUPT_LIST:
+      OhciAttachED (EdList, Ed);
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return EFI_SUCCESS;
+}
+/**
+
+  Link Td2 to the end of Td1
+
+  @Param Td1                    TD to be linked
+  @Param Td2                    TD to link
+
+  @retval EFI_SUCCESS           TD successfully linked
+  @retval EFI_INVALID_PARAMETER Td1 is NULL
+
+**/
+EFI_STATUS
+OhciLinkTD (
+  IN TD_DESCRIPTOR        *Td1,
+  IN TD_DESCRIPTOR        *Td2
+  )
+{
+  TD_DESCRIPTOR           *TempTd;
+
+  if (Td1 == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Td1 == Td2) {
+    return EFI_SUCCESS;
+  }
+
+  TempTd = Td1;
+  while (TempTd->NextTD != NULL) {
+    TempTd = TempTd->NextTD;
+  }
+
+  TempTd->NextTD = Td2;
+  TempTd->NextTDPointer = Td2;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Attach TD list to ED
+
+  @Param  Ed                    ED which TD list attach on
+  @Param  HeadTd                Head of the TD list to attach
+
+  @retval  EFI_SUCCESS          TD list attached on the ED
+
+**/
+EFI_STATUS
+OhciAttachTDListToED (
+  IN ED_DESCRIPTOR        *Ed,
+  IN TD_DESCRIPTOR        *HeadTd
+  )
+{
+  TD_DESCRIPTOR           *TempTd;
+
+  TempTd = TD_PTR (Ed->Word2.TdHeadPointer);
+
+  if (TempTd != NULL) {
+    while (TempTd->NextTD != NULL) {
+      TempTd = TempTd->NextTD;
+    }
+    TempTd->NextTD = HeadTd;
+    TempTd->NextTDPointer = HeadTd;
+  } else {
+    Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) HeadTd);
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Set value to ED specific field
+
+  @Param  Ed                    ED to be set
+  @Param  Field                 Field to be set
+  @Param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetEDField (
+  IN ED_DESCRIPTOR        *Ed,
+  IN UINT32               Field,
+  IN UINT32               Value
+  )
+{
+  if (Field & ED_FUNC_ADD) {
+    Ed->Word0.FunctionAddress = Value;
+  }
+  if (Field & ED_ENDPT_NUM) {
+    Ed->Word0.EndPointNum = Value;
+  }
+  if (Field & ED_DIR) {
+    Ed->Word0.Direction = Value;
+  }
+  if (Field & ED_SPEED) {
+    Ed->Word0.Speed = Value;
+  }
+  if (Field & ED_SKIP) {
+    Ed->Word0.Skip = Value;
+  }
+  if (Field & ED_FORMAT) {
+    Ed->Word0.Format = Value;
+  }
+  if (Field & ED_MAX_PACKET) {
+    Ed->Word0.MaxPacketSize = Value;
+  }
+  if (Field & ED_PDATA) {
+    Ed->Word0.FreeSpace = Value;
+  }
+  if (Field & ED_ZERO) {
+    Ed->Word2.Zero = Value;
+  }
+  if (Field & ED_TDTAIL_PTR) {
+    Ed->TdTailPointer = (VOID *) Value;
+  }
+
+  if (Field & ED_HALTED) {
+    Ed->Word2.Halted = Value;
+  }
+  if (Field & ED_DTTOGGLE) {
+    Ed->Word2.ToggleCarry = Value;
+  }
+  if (Field & ED_TDHEAD_PTR) {
+    Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value);
+  }
+
+  if (Field & ED_NEXT_EDPTR) {
+    Ed->NextED = (VOID *) Value;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Get value from an ED's specific field
+
+  @Param  Ed                    ED pointer
+  @Param  Field                 Field to get value from
+
+  @retval                       Value of the field
+
+**/
+UINT32
+OhciGetEDField (
+  IN ED_DESCRIPTOR        *Ed,
+  IN UINT32               Field
+  )
+{
+  switch (Field) {
+    case ED_FUNC_ADD:
+      return Ed->Word0.FunctionAddress;
+      break;
+    case ED_ENDPT_NUM:
+      return Ed->Word0.EndPointNum;
+      break;
+    case ED_DIR:
+      return Ed->Word0.Direction;
+      break;
+    case ED_SPEED:
+      return Ed->Word0.Speed;
+      break;
+    case ED_SKIP:
+      return Ed->Word0.Skip;
+      break;
+    case ED_FORMAT:
+      return Ed->Word0.Format;
+      break;
+    case ED_MAX_PACKET:
+      return Ed->Word0.MaxPacketSize;
+      break;
+
+    case ED_TDTAIL_PTR:
+      return (UINT32) Ed->TdTailPointer;
+      break;
+
+    case ED_HALTED:
+      return Ed->Word2.Halted;
+      break;
+
+    case ED_DTTOGGLE:
+      return Ed->Word2.ToggleCarry;
+      break;
+
+    case ED_TDHEAD_PTR:
+      return Ed->Word2.TdHeadPointer << 4;
+      break;
+
+    case ED_NEXT_EDPTR:
+      return (UINT32) Ed->NextED;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
+
+
+/**
+
+  Set value to TD specific field
+
+  @Param  Td                    TD to be set
+  @Param  Field                 Field to be set
+  @Param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetTDField (
+  IN TD_DESCRIPTOR        *Td,
+  IN UINT32               Field,
+  IN UINT32               Value
+  )
+{
+  if (Field & TD_PDATA) {
+    Td->Word0.Reserved = Value;
+  }
+  if (Field & TD_BUFFER_ROUND) {
+    Td->Word0.BufferRounding = Value;
+  }
+  if (Field & TD_DIR_PID) {
+    Td->Word0.DirPID = Value;
+  }
+  if (Field & TD_DELAY_INT) {
+    Td->Word0.DelayInterrupt = Value;
+  }
+  if (Field & TD_DT_TOGGLE) {
+    Td->Word0.DataToggle = Value | 0x2;
+  }
+  if (Field & TD_ERROR_CNT) {
+    Td->Word0.ErrorCount = Value;
+  }
+  if (Field & TD_COND_CODE) {
+    Td->Word0.ConditionCode = Value;
+  }
+
+  if (Field & TD_CURR_BUFFER_PTR) {
+    Td->CurrBufferPointer = (VOID *) Value;
+  }
+
+
+  if (Field & TD_NEXT_PTR) {
+    Td->NextTD = (VOID *) Value;
+  }
+
+  if (Field & TD_BUFFER_END_PTR) {
+    Td->BufferEndPointer = (VOID *) Value;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+
+  Get value from ED specific field
+
+  @Param  Td                    TD pointer
+  @Param  Field                 Field to get value from
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetTDField (
+  IN TD_DESCRIPTOR      *Td,
+  IN UINT32             Field
+  )
+{
+  switch (Field){
+    case TD_BUFFER_ROUND:
+      return Td->Word0.BufferRounding;
+      break;
+    case TD_DIR_PID:
+      return Td->Word0.DirPID;
+      break;
+    case TD_DELAY_INT:
+      return Td->Word0.DelayInterrupt;
+      break;
+    case TD_DT_TOGGLE:
+      return Td->Word0.DataToggle;
+      break;
+    case TD_ERROR_CNT:
+      return Td->Word0.ErrorCount;
+      break;
+    case TD_COND_CODE:
+      return Td->Word0.ConditionCode;
+      break;
+    case TD_CURR_BUFFER_PTR:
+      return (UINT32) Td->CurrBufferPointer;
+      break;
+
+    case TD_NEXT_PTR:
+      return (UINT32) Td->NextTD;
+      break;
+
+    case TD_BUFFER_END_PTR:
+      return (UINT32) Td->BufferEndPointer;
+      break;
+
+    default:
+      ASSERT (FALSE);
+  }
+
+  return 0;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h
new file mode 100644
index 0000000000..5172fbd1b5
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h
@@ -0,0 +1,231 @@
+/** @file
+Provides some data struct used by OHCI controller driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _OHCI_URB_H
+#define _OHCI_URB_H
+
+#include "Descriptor.h"
+
+
+//
+// Func List
+//
+
+
+/**
+
+  Create a TD
+
+  @Param  Ohc                   UHC private data
+
+  @retval                       TD structure pointer
+
+**/
+TD_DESCRIPTOR *
+OhciCreateTD (
+  IN USB_OHCI_HC_DEV      *Ohc
+  );
+
+/**
+
+  Free a TD
+
+  @Param  Ohc                   UHC private data
+  @Param  Td                    Pointer to a TD to free
+
+  @retval  EFI_SUCCESS          TD freed
+
+**/
+EFI_STATUS
+OhciFreeTD (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN TD_DESCRIPTOR        *Td
+  );
+
+/**
+
+  Create a ED
+
+  @Param   Ohc                  Device private data
+
+  @retval  ED                   descriptor pointer
+
+**/
+ED_DESCRIPTOR *
+OhciCreateED (
+  USB_OHCI_HC_DEV          *Ohc
+  );
+
+
+/**
+
+  Free a ED
+
+  @Param  Ohc                   UHC private data
+  @Param  Ed                    Pointer to a ED to free
+
+  @retval  EFI_SUCCESS          ED freed
+
+**/
+
+EFI_STATUS
+OhciFreeED (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *Ed
+  );
+
+/**
+
+  Free  ED
+
+  @Param  Ohc                    Device private data
+  @Param  Ed                     Pointer to a ED to free
+
+  @retval  EFI_SUCCESS           ED freed
+
+**/
+EFI_STATUS
+OhciFreeAllTDFromED (
+  IN USB_OHCI_HC_DEV      *Ohc,
+  IN ED_DESCRIPTOR        *Ed
+  );
+
+/**
+
+  Attach an ED
+
+  @Param  Ed                    Ed to be attached
+  @Param  NewEd                 Ed to attach
+
+  @retval EFI_SUCCESS           NewEd attached to Ed
+  @retval EFI_INVALID_PARAMETER Ed is NULL
+
+**/
+EFI_STATUS
+OhciAttachED (
+  IN ED_DESCRIPTOR        *Ed,
+  IN ED_DESCRIPTOR        *NewEd
+  );
+/**
+
+  Attach an ED to an ED list
+
+  @Param  OHC                   UHC private data
+  @Param  ListType              Type of the ED list
+  @Param  Ed                    ED to attach
+  @Param  EdList                ED list to be attached
+
+  @retval  EFI_SUCCESS          ED attached to ED list
+
+**/
+EFI_STATUS
+OhciAttachEDToList (
+  IN USB_OHCI_HC_DEV       *Ohc,
+  IN DESCRIPTOR_LIST_TYPE  ListType,
+  IN ED_DESCRIPTOR         *Ed,
+  IN ED_DESCRIPTOR         *EdList
+  );
+EFI_STATUS
+OhciLinkTD (
+  IN TD_DESCRIPTOR        *Td1,
+  IN TD_DESCRIPTOR        *Td2
+  );
+
+
+/**
+
+  Attach TD list to ED
+
+  @Param  Ed                    ED which TD list attach on
+  @Param  HeadTd                Head of the TD list to attach
+
+  @retval  EFI_SUCCESS          TD list attached on the ED
+
+**/
+EFI_STATUS
+OhciAttachTDListToED (
+  IN ED_DESCRIPTOR        *Ed,
+  IN TD_DESCRIPTOR        *HeadTd
+  );
+
+
+/**
+
+  Set value to ED specific field
+
+  @Param  Ed                    ED to be set
+  @Param  Field                 Field to be set
+  @Param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetEDField (
+  IN ED_DESCRIPTOR        *Ed,
+  IN UINT32               Field,
+  IN UINT32               Value
+  );
+
+
+/**
+
+  Get value from an ED's specific field
+
+  @Param  Ed                    ED pointer
+  @Param  Field                 Field to get value from
+
+  @retval                       Value of the field
+
+**/
+UINT32
+OhciGetEDField (
+  IN ED_DESCRIPTOR        *Ed,
+  IN UINT32               Field
+  );
+
+
+/**
+
+  Set value to TD specific field
+
+  @Param  Td                    TD to be set
+  @Param  Field                 Field to be set
+  @Param  Value                 Value to set
+
+  @retval  EFI_SUCCESS          Value set
+
+**/
+EFI_STATUS
+OhciSetTDField (
+  IN TD_DESCRIPTOR        *Td,
+  IN UINT32               Field,
+  IN UINT32               Value
+  );
+
+
+/**
+
+  Get value from ED specific field
+
+  @Param  Td                    TD pointer
+  @Param  Field                 Field to get value from
+
+  @retval                       Value of the field
+
+**/
+
+UINT32
+OhciGetTDField (
+  IN TD_DESCRIPTOR      *Td,
+  IN UINT32             Field
+  );
+
+#endif
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c
new file mode 100644
index 0000000000..a9c05523b4
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c
@@ -0,0 +1,491 @@
+/** @file
+Routine procedures for memory allocate/free.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "OhcPeim.h"
+
+
+/**
+  Allocate a block of memory to be used by the buffer pool.
+
+  Use Redirect memory services to allocate memmory so that USB DMA transfers do
+  not cause IMR violations on Quark.
+
+  @param  Pool           The buffer pool to allocate memory for.
+  @param  Pages          How many pages to allocate.
+
+  @return The allocated memory block or NULL if failed.
+
+**/
+USBHC_MEM_BLOCK *
+UsbHcAllocMemBlock (
+  IN  USBHC_MEM_POOL      *Pool,
+  IN  UINTN               Pages
+  )
+{
+  USBHC_MEM_BLOCK         *Block;
+  VOID                    *BufHost;
+  VOID                    *Mapping;
+  EFI_PHYSICAL_ADDRESS    MappedAddr;
+  EFI_STATUS              Status;
+  UINTN                   PageNumber;
+  EFI_PHYSICAL_ADDRESS    TempPtr;
+
+  Mapping = NULL;
+  PageNumber =  sizeof(USBHC_MEM_BLOCK)/PAGESIZE +1;
+  Status = PeiServicesAllocatePages (
+             EfiBootServicesCode,
+             PageNumber,
+             &TempPtr
+             );
+
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+  ZeroMem ((VOID   *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
+
+  //
+  // each bit in the bit array represents USBHC_MEM_UNIT
+  // bytes of memory in the memory block.
+  //
+  ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+  Block = (USBHC_MEM_BLOCK*)(UINTN)TempPtr;
+  Block->BufLen   = EFI_PAGES_TO_SIZE (Pages);
+  Block->BitsLen  = Block->BufLen / (USBHC_MEM_UNIT * 8);
+
+  PageNumber =  (Block->BitsLen)/PAGESIZE +1;
+  Status = PeiServicesAllocatePages (
+             EfiBootServicesCode,
+             PageNumber,
+             &TempPtr
+             );
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+  ZeroMem ((VOID   *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
+
+  Block->Bits  = (UINT8 *)(UINTN)TempPtr;
+
+  Status = PeiServicesAllocatePages (
+             EfiBootServicesCode,
+             Pages,
+             &TempPtr
+             );
+  ZeroMem ((VOID   *)(UINTN)TempPtr, Pages*EFI_PAGE_SIZE);
+
+  BufHost  = (VOID *)(UINTN)TempPtr;
+  MappedAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) BufHost;
+  //
+  // Check whether the data structure used by the host controller
+  // should be restricted into the same 4G
+  //
+  if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
+    return NULL;
+  }
+
+  Block->BufHost  = BufHost;
+  Block->Buf      = (UINT8 *) ((UINTN) MappedAddr);
+  Block->Mapping  = Mapping;
+  Block->Next     = NULL;
+
+  return Block;
+
+}
+
+
+/**
+  Free the memory block from the memory pool.
+
+  @param  Pool           The memory pool to free the block from.
+  @param  Block          The memory block to free.
+
+**/
+VOID
+UsbHcFreeMemBlock (
+  IN USBHC_MEM_POOL       *Pool,
+  IN USBHC_MEM_BLOCK      *Block
+  )
+{
+
+  ASSERT ((Pool != NULL) && (Block != NULL));
+}
+
+
+/**
+  Alloc some memory from the block.
+
+  @param  Block          The memory block to allocate memory from.
+  @param  Units          Number of memory units to allocate.
+
+  @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+          the return value is NULL.
+
+**/
+VOID *
+UsbHcAllocMemFromBlock (
+  IN  USBHC_MEM_BLOCK     *Block,
+  IN  UINTN               Units
+  )
+{
+  UINTN                   Byte;
+  UINT8                   Bit;
+  UINTN                   StartByte;
+  UINT8                   StartBit;
+  UINTN                   Available;
+  UINTN                   Count;
+
+  ASSERT ((Block != 0) && (Units != 0));
+
+  StartByte  = 0;
+  StartBit   = 0;
+  Available  = 0;
+
+  for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+    //
+    // If current bit is zero, the corresponding memory unit is
+    // available, otherwise we need to restart our searching.
+    // Available counts the consective number of zero bit.
+    //
+    if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+      Available++;
+
+      if (Available >= Units) {
+        break;
+      }
+
+      NEXT_BIT (Byte, Bit);
+
+    } else {
+      NEXT_BIT (Byte, Bit);
+
+      Available  = 0;
+      StartByte  = Byte;
+      StartBit   = Bit;
+    }
+  }
+
+  if (Available < Units) {
+    return NULL;
+  }
+
+  //
+  // Mark the memory as allocated
+  //
+  Byte  = StartByte;
+  Bit   = StartBit;
+
+  for (Count = 0; Count < Units; Count++) {
+    ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+    Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));
+    NEXT_BIT (Byte, Bit);
+  }
+
+  return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
+}
+
+/**
+  Insert the memory block to the pool's list of the blocks.
+
+  @param  Head           The head of the memory pool's block list.
+  @param  Block          The memory block to insert.
+
+**/
+VOID
+UsbHcInsertMemBlockToPool (
+  IN USBHC_MEM_BLOCK      *Head,
+  IN USBHC_MEM_BLOCK      *Block
+  )
+{
+  ASSERT ((Head != NULL) && (Block != NULL));
+  Block->Next = Head->Next;
+  Head->Next  = Block;
+}
+
+
+/**
+  Is the memory block empty?
+
+  @param  Block   The memory block to check.
+
+  @retval TRUE    The memory block is empty.
+  @retval FALSE   The memory block isn't empty.
+
+**/
+BOOLEAN
+UsbHcIsMemBlockEmpty (
+  IN USBHC_MEM_BLOCK     *Block
+  )
+{
+  UINTN                   Index;
+
+  for (Index = 0; Index < Block->BitsLen; Index++) {
+    if (Block->Bits[Index] != 0) {
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+
+/**
+  Unlink the memory block from the pool's list.
+
+  @param  Head           The block list head of the memory's pool.
+  @param  BlockToUnlink  The memory block to unlink.
+
+**/
+VOID
+UsbHcUnlinkMemBlock (
+  IN USBHC_MEM_BLOCK      *Head,
+  IN USBHC_MEM_BLOCK      *BlockToUnlink
+  )
+{
+  USBHC_MEM_BLOCK         *Block;
+
+  ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
+
+  for (Block = Head; Block != NULL; Block = Block->Next) {
+    if (Block->Next == BlockToUnlink) {
+      Block->Next         = BlockToUnlink->Next;
+      BlockToUnlink->Next = NULL;
+      break;
+    }
+  }
+}
+
+
+/**
+  Initialize the memory management pool for the host controller.
+
+  @param  PciIo                The PciIo that can be used to access the host controller.
+  @param  Check4G              Whether the host controller requires allocated memory
+                               from one 4G address space.
+  @param  Which4G              The 4G memory area each memory allocated should be from.
+
+  @retval EFI_SUCCESS          The memory pool is initialized.
+  @retval EFI_OUT_OF_RESOURCE  Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+  IN BOOLEAN              Check4G,
+  IN UINT32               Which4G
+  )
+{
+  USBHC_MEM_POOL          *Pool;
+  UINTN                   PageNumber;
+  EFI_STATUS              Status;
+  EFI_PHYSICAL_ADDRESS    TempPtr;
+
+  PageNumber =  sizeof(USBHC_MEM_POOL)/PAGESIZE +1;
+  Status = PeiServicesAllocatePages (
+             EfiBootServicesCode,
+             PageNumber,
+             &TempPtr
+             );
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+  ZeroMem ((VOID   *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
+
+  Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);
+  Pool->Check4G = Check4G;
+  Pool->Which4G = Which4G;
+  Pool->Head    = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
+
+  if (Pool->Head == NULL) {
+    Pool = NULL;
+  }
+
+  return Pool;
+}
+
+
+/**
+  Release the memory management pool.
+
+  @param  Pool              The USB memory pool to free.
+
+  @retval EFI_SUCCESS       The memory pool is freed.
+  @retval EFI_DEVICE_ERROR  Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+  IN USBHC_MEM_POOL       *Pool
+  )
+{
+  USBHC_MEM_BLOCK *Block;
+
+  ASSERT (Pool->Head != NULL);
+
+  //
+  // Unlink all the memory blocks from the pool, then free them.
+  // UsbHcUnlinkMemBlock can't be used to unlink and free the
+  // first block.
+  //
+  for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+    UsbHcFreeMemBlock (Pool, Block);
+  }
+
+  UsbHcFreeMemBlock (Pool, Pool->Head);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Allocate some memory from the host controller's memory pool
+  which can be used to communicate with host controller.
+
+  @param  Pool           The host controller's memory pool.
+  @param  Size           Size of the memory to allocate.
+
+  @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+  IN  USBHC_MEM_POOL      *Pool,
+  IN  UINTN               Size
+  )
+{
+  USBHC_MEM_BLOCK         *Head;
+  USBHC_MEM_BLOCK         *Block;
+  USBHC_MEM_BLOCK         *NewBlock;
+  VOID                    *Mem;
+  UINTN                   AllocSize;
+  UINTN                   Pages;
+
+  Mem       = NULL;
+  AllocSize = USBHC_MEM_ROUND (Size);
+  Head      = Pool->Head;
+  ASSERT (Head != NULL);
+
+  //
+  // First check whether current memory blocks can satisfy the allocation.
+  //
+  for (Block = Head; Block != NULL; Block = Block->Next) {
+    Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
+
+    if (Mem != NULL) {
+      ZeroMem (Mem, Size);
+      break;
+    }
+  }
+
+  if (Mem != NULL) {
+    return Mem;
+  }
+
+  //
+  // Create a new memory block if there is not enough memory
+  // in the pool. If the allocation size is larger than the
+  // default page number, just allocate a large enough memory
+  // block. Otherwise allocate default pages.
+  //
+  if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
+    Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+  } else {
+    Pages = USBHC_MEM_DEFAULT_PAGES;
+  }
+
+  NewBlock = UsbHcAllocMemBlock (Pool, Pages);
+
+  if (NewBlock == NULL) {
+    DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));
+    return NULL;
+  }
+
+  //
+  // Add the new memory block to the pool, then allocate memory from it
+  //
+  UsbHcInsertMemBlockToPool (Head, NewBlock);
+  Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
+
+  if (Mem != NULL) {
+    ZeroMem (Mem, Size);
+  }
+
+  return Mem;
+}
+
+
+/**
+  Free the allocated memory back to the memory pool.
+
+  @param  Pool           The memory pool of the host controller.
+  @param  Mem            The memory to free.
+  @param  Size           The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+  IN USBHC_MEM_POOL       *Pool,
+  IN VOID                 *Mem,
+  IN UINTN                Size
+  )
+{
+  USBHC_MEM_BLOCK         *Head;
+  USBHC_MEM_BLOCK         *Block;
+  UINT8                   *ToFree;
+  UINTN                   AllocSize;
+  UINTN                   Byte;
+  UINTN                   Bit;
+  UINTN                   Count;
+
+  Head      = Pool->Head;
+  AllocSize = USBHC_MEM_ROUND (Size);
+  ToFree    = (UINT8 *) Mem;
+
+  for (Block = Head; Block != NULL; Block = Block->Next) {
+    //
+    // scan the memory block list for the memory block that
+    // completely contains the memory to free.
+    //
+    if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+      //
+      // compute the start byte and bit in the bit array
+      //
+      Byte  = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
+      Bit   = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
+
+      //
+      // reset associated bits in bit arry
+      //
+      for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
+        ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+        Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
+        NEXT_BIT (Byte, Bit);
+      }
+
+      break;
+    }
+  }
+
+  //
+  // If Block == NULL, it means that the current memory isn't
+  // in the host controller's pool. This is critical because
+  // the caller has passed in a wrong memory point
+  //
+  ASSERT (Block != NULL);
+
+  //
+  // Release the current memory block if it is empty and not the head
+  //
+  if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
+    UsbHcFreeMemBlock (Pool, Block);
+  }
+
+  return ;
+}
diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h
new file mode 100644
index 0000000000..ad0d73e64d
--- /dev/null
+++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h
@@ -0,0 +1,134 @@
+/** @file
+This file contains the definination for host controller memory
+management routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _USB_HC_MEM_H_
+#define _USB_HC_MEM_H_
+
+#define USB_HC_BIT(a)                  ((UINTN)(1 << (a)))
+
+#define USB_HC_BIT_IS_SET(Data, Bit)   \
+          ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
+
+#define USB_HC_HIGH_32BIT(Addr64)    \
+          ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
+struct _USBHC_MEM_BLOCK {
+  UINT8                   *Bits;    // Bit array to record which unit is allocated
+  UINTN                   BitsLen;
+  UINT8                   *Buf;
+  UINT8                   *BufHost;
+  UINTN                   BufLen;   // Memory size in bytes
+  VOID                    *Mapping;
+  USBHC_MEM_BLOCK         *Next;
+};
+
+//
+// USBHC_MEM_POOL is used to manage the memory used by USB
+// host controller. EHCI requires the control memory and transfer
+// data to be on the same 4G memory.
+//
+typedef struct _USBHC_MEM_POOL {
+  BOOLEAN                 Check4G;
+  UINT32                  Which4G;
+  USBHC_MEM_BLOCK         *Head;
+} USBHC_MEM_POOL;
+
+//
+// Memory allocation unit, must be 2^n, n>4
+//
+#define USBHC_MEM_UNIT           64
+
+#define USBHC_MEM_UNIT_MASK      (USBHC_MEM_UNIT - 1)
+#define USBHC_MEM_DEFAULT_PAGES  16
+
+#define USBHC_MEM_ROUND(Len)  (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define NEXT_BIT(Byte, Bit)   \
+          do {                \
+            (Bit)++;          \
+            if ((Bit) > 7) {  \
+              (Byte)++;       \
+              (Bit) = 0;      \
+            }                 \
+          } while (0)
+
+
+
+/**
+  Initialize the memory management pool for the host controller.
+
+  @param  PciIo               The PciIo that can be used to access the host controller.
+  @param  Check4G             Whether the host controller requires allocated memory
+                              from one 4G address space.
+  @param  Which4G             The 4G memory area each memory allocated should be from.
+
+  @retval EFI_SUCCESS         The memory pool is initialized.
+  @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+  IN BOOLEAN              Check4G,
+  IN UINT32               Which4G
+  );
+
+
+/**
+  Release the memory management pool.
+
+  @param   Pool               The USB memory pool to free.
+
+  @retval EFI_SUCCESS       The memory pool is freed.
+  @retval EFI_DEVICE_ERROR  Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+  IN USBHC_MEM_POOL       *Pool
+  );
+
+
+/**
+  Allocate some memory from the host controller's memory pool
+  which can be used to communicate with host controller.
+
+  @param  Pool  The host controller's memory pool.
+  @param  Size  Size of the memory to allocate.
+
+  @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+  IN  USBHC_MEM_POOL      *Pool,
+  IN  UINTN               Size
+  );
+
+
+/**
+  Free the allocated memory back to the memory pool.
+
+  @param  Pool  The memory pool of the host controller.
+  @param  Mem   The memory to free.
+  @param  Size  The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+  IN USBHC_MEM_POOL       *Pool,
+  IN VOID                 *Mem,
+  IN UINTN                Size
+  );
+
+#endif
-- 
2.21.0.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#40399): https://edk2.groups.io/g/devel/message/40399
Mute This Topic: https://groups.io/mt/31573402/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list