Browse Source

QuarkSocPkg: Add new package for Quark SoC X1000

Changes for V4
==============
1) Remove Unicode character from C source file
2) Move delete of QuarkSocPkg\QuarkNorthCluster\Binary\QuarkMicrocode
   from QuarkPlatformPkg commit to QuarkSocPkg commit

Changes for V2
==============
1) Sync with new APIs in SmmCpuFeaturesLib class
2) Use new generic PCI serial driver PciSioSerialDxe in MdeModulePkg
3) Remove PCI serial driver from QuarkSocPkg
4) Apply optimizations to MtrrLib from MtrrLib in UefiCpuPkg
5) Convert all UNI files to utf-8
6) Replace tabs with spaces and remove trailing spaces
7) Add License.txt

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Michael Kinney <michael.d.kinney@intel.com>
Acked-by: Jordan Justen <jordan.l.justen@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19286 6f19259b-4bc3-4df7-8a09-765794883524
Michael Kinney 8 years ago
parent
commit
9b6bbcdbfd
100 changed files with 26319 additions and 0 deletions
  1. 47 0
      QuarkPlatformPkg/Library/PlatformPcieHelperLib/PlatformPcieHelperLib.inf
  2. 218 0
      QuarkSocPkg/Contributions.txt
  3. 25 0
      QuarkSocPkg/License.txt
  4. 257 0
      QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h
  5. 23 0
      QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h
  6. 106 0
      QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h
  7. 23 0
      QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h
  8. 23 0
      QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h
  9. 54 0
      QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h
  10. 290 0
      QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h
  11. 167 0
      QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h
  12. 63 0
      QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h
  13. 42 0
      QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h
  14. 54 0
      QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h
  15. 37 0
      QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h
  16. 90 0
      QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h
  17. 121 0
      QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h
  18. 351 0
      QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h
  19. 183 0
      QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h
  20. 356 0
      QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h
  21. 757 0
      QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h
  22. 38 0
      QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h
  23. 777 0
      QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c
  24. 63 0
      QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf
  25. 949 0
      QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c
  26. 2117 0
      QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c
  27. 48 0
      QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf
  28. 24 0
      QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni
  29. 34 0
      QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c
  30. 333 0
      QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c
  31. 43 0
      QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf
  32. 148 0
      QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c
  33. 49 0
      QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf
  34. 322 0
      QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c
  35. 51 0
      QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf
  36. 322 0
      QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c
  37. 52 0
      QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf
  38. 31 0
      QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h
  39. 803 0
      QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c
  40. 53 0
      QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf
  41. 438 0
      QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
  42. 34 0
      QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
  43. 18 0
      QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni
  44. 65 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c
  45. 41 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h
  46. 76 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf
  47. 49 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h
  48. 744 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h
  49. 90 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h
  50. 542 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c
  51. 72 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h
  52. 138 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h
  53. 388 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c
  54. 2645 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c
  55. 28 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h
  56. 1580 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c
  57. 97 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h
  58. 83 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h
  59. 46 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c
  60. 166 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h
  61. 192 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c
  62. 193 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c
  63. 21 0
      QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h
  64. 55 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h
  65. 618 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c
  66. 211 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h
  67. 243 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c
  68. 204 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h
  69. 527 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c
  70. 55 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h
  71. 98 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf
  72. 82 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c
  73. 86 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h
  74. 252 0
      QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c
  75. 423 0
      QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c
  76. 123 0
      QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h
  77. 70 0
      QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf
  78. 54 0
      QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf
  79. 395 0
      QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c
  80. 235 0
      QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h
  81. 366 0
      QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
  82. 61 0
      QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf
  83. 51 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h
  84. 38 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c
  85. 555 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
  86. 430 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c
  87. 217 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c
  88. 96 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c
  89. 153 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c
  90. 871 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h
  91. 800 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c
  92. 87 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf
  93. 373 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c
  94. 225 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h
  95. 19 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h
  96. 184 0
      QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h
  97. 382 0
      QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c
  98. 51 0
      QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf
  99. 282 0
      QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c
  100. 57 0
      QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf

+ 47 - 0
QuarkPlatformPkg/Library/PlatformPcieHelperLib/PlatformPcieHelperLib.inf

@@ -0,0 +1,47 @@
+## @file
+# Library producing Pci Express Helper routines.
+#
+# Copyright (c) 2013 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PlatformPcieHelperLib
+  FILE_GUID                      = C153F460-5D8A-4d44-83BB-A8AF5CEF132C
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PlatformPcieHelperLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32
+#
+
+[Sources]
+  PlatformPcieHelperLib.c
+  SocUnit.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+  QuarkPlatformPkg/QuarkPlatformPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  PcdLib
+  IoLib
+  DebugLib
+  TimerLib
+  QNCAccessLib
+  IntelQNCLib

+ 218 - 0
QuarkSocPkg/Contributions.txt

@@ -0,0 +1,218 @@
+
+======================
+= Code Contributions =
+======================
+
+To make a contribution to a TianoCore project, follow these steps.
+1. Create a change description in the format specified below to
+   use in the source control commit log.
+2. Your commit message must include your "Signed-off-by" signature,
+   and "Contributed-under" message.
+3. Your "Contributed-under" message explicitly states that the
+   contribution is made under the terms of the specified
+   contribution agreement.  Your "Contributed-under" message
+   must include the name of contribution agreement and version.
+   For example: Contributed-under: TianoCore Contribution Agreement 1.0
+   The "TianoCore Contribution Agreement" is included below in
+   this document.
+4. Submit your code to the TianoCore project using the process
+   that the project documents on its web page.  If the process is
+   not documented, then submit the code on development email list
+   for the project.
+5. It is preferred that contributions are submitted using the same
+   copyright license as the base project. When that is not possible,
+   then contributions using the following licenses can be accepted:
+   * BSD (2-clause): http://opensource.org/licenses/BSD-2-Clause
+   * BSD (3-clause): http://opensource.org/licenses/BSD-3-Clause
+   * MIT: http://opensource.org/licenses/MIT
+   * Python-2.0: http://opensource.org/licenses/Python-2.0
+   * Zlib: http://opensource.org/licenses/Zlib
+
+   Contributions of code put into the public domain can also be
+   accepted.
+
+   Contributions using other licenses might be accepted, but further
+   review will be required.
+
+=====================================================
+= Change Description / Commit Message / Patch Email =
+=====================================================
+
+Your change description should use the standard format for a
+commit message, and must include your "Signed-off-by" signature
+and the "Contributed-under" message.
+
+== Sample Change Description / Commit Message =
+
+=== Start of sample patch email message ===
+
+From: Contributor Name <contributor@example.com>
+Subject: [PATCH] CodeModule: Brief-single-line-summary
+
+Full-commit-message
+
+Contributed-under: TianoCore Contribution Agreement 1.0
+Signed-off-by: Contributor Name <contributor@example.com>
+---
+
+An extra message for the patch email which will not be considered part
+of the commit message can be added here.
+
+Patch content inline or attached
+
+=== End of sample patch email message ===
+
+=== Notes for sample patch email ===
+
+* The first line of commit message is taken from the email's subject
+  line following [PATCH]. The remaining portion of the commit message
+  is the email's content until the '---' line.
+* git format-patch is one way to create this format
+
+=== Definitions for sample patch email ===
+
+* "CodeModule" is a short idenfier for the affected code.  For
+  example MdePkg, or MdeModulePkg UsbBusDxe.
+* "Brief-single-line-summary" is a short summary of the change.
+* The entire first line should be less than ~70 characters.
+* "Full-commit-message" a verbose multiple line comment describing
+  the change.  Each line should be less than ~70 characters.
+* "Contributed-under" explicitely states that the contribution is
+  made under the terms of the contribtion agreement.  This
+  agreement is included below in this document.
+* "Signed-off-by" is the contributor's signature identifying them
+  by their real/legal name and their email address.
+
+========================================
+= TianoCore Contribution Agreement 1.0 =
+========================================
+
+INTEL CORPORATION ("INTEL") MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+INFORMATION AND/OR OTHER MATERIALS FOR USE IN THE TIANOCORE OPEN SOURCE
+PROJECT (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE
+TERMS AND CONDITIONS OF THIS AGREEMENT BETWEEN YOU AND INTEL AND/OR THE
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR
+REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE
+CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS
+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+USE THE CONTENT.
+
+Unless otherwise indicated, all Content made available on the TianoCore
+site is provided to you under the terms and conditions of the BSD
+License ("BSD"). A copy of the BSD License is available at
+http://opensource.org/licenses/bsd-license.php
+or when applicable, in the associated License.txt file.
+
+Certain other content may be made available under other licenses as
+indicated in or with such Content. (For example, in a License.txt file.)
+
+You accept and agree to the following terms and conditions for Your
+present and future Contributions submitted to TianoCore site. Except
+for the license granted to Intel hereunder, You reserve all right,
+title, and interest in and to Your Contributions.
+
+== SECTION 1: Definitions ==
+* "You" or "Contributor" shall mean the copyright owner or legal
+  entity authorized by the copyright owner that is making a
+  Contribution hereunder. All other entities that control, are
+  controlled by, or are under common control with that entity are
+  considered to be a single Contributor. For the purposes of this
+  definition, "control" means (i) the power, direct or indirect, to
+  cause the direction or management of such entity, whether by
+  contract or otherwise, or (ii) ownership of fifty percent (50%)
+  or more of the outstanding shares, or (iii) beneficial ownership
+  of such entity.
+* "Contribution" shall mean any original work of authorship,
+  including any modifications or additions to an existing work,
+  that is intentionally submitted by You to the TinaoCore site for
+  inclusion in, or documentation of, any of the Content. For the
+  purposes of this definition, "submitted" means any form of
+  electronic, verbal, or written communication sent to the
+  TianoCore site or its representatives, including but not limited
+  to communication on electronic mailing lists, source code
+  control systems, and issue tracking systems that are managed by,
+  or on behalf of, the TianoCore site for the purpose of
+  discussing and improving the Content, but excluding
+  communication that is conspicuously marked or otherwise
+  designated in writing by You as "Not a Contribution."
+
+== SECTION 2: License for Contributions ==
+* Contributor hereby agrees that redistribution and use of the
+  Contribution in source and binary forms, with or without
+  modification, are permitted provided that the following
+  conditions are met:
+** Redistributions of source code must retain the Contributor's
+   copyright notice, this list of conditions and the following
+   disclaimer.
+** Redistributions in binary form must reproduce the Contributor's
+   copyright notice, this list of conditions and the following
+   disclaimer in the documentation and/or other materials provided
+   with the distribution.
+* Disclaimer. None of the names of Contributor, Intel, or the names
+  of their respective contributors may be used to endorse or
+  promote products derived from this software without specific
+  prior written permission.
+* Contributor grants a license (with the right to sublicense) under
+  claims of Contributor's patents that Contributor can license that
+  are infringed by the Contribution (as delivered by Contributor) to
+  make, use, distribute, sell, offer for sale, and import the
+  Contribution and derivative works thereof solely to the minimum
+  extent necessary for licensee to exercise the granted copyright
+  license; this patent license applies solely to those portions of
+  the Contribution that are unmodified. No hardware per se is
+  licensed.
+* EXCEPT AS EXPRESSLY SET FORTH IN SECTION 3 BELOW, THE
+  CONTRIBUTION IS PROVIDED BY THE CONTRIBUTOR "AS IS" AND ANY
+  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+  CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+  CONTRIBUTION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGE.
+
+== SECTION 3: Representations ==
+* You represent that You are legally entitled to grant the above
+  license. If your employer(s) has rights to intellectual property
+  that You create that includes Your Contributions, You represent
+  that You have received permission to make Contributions on behalf
+  of that employer, that Your employer has waived such rights for
+  Your Contributions.
+* You represent that each of Your Contributions is Your original
+  creation (see Section 4 for submissions on behalf of others).
+  You represent that Your Contribution submissions include complete
+  details of any third-party license or other restriction
+  (including, but not limited to, related patents and trademarks)
+  of which You are personally aware and which are associated with
+  any part of Your Contributions.
+
+== SECTION 4: Third Party Contributions ==
+* Should You wish to submit work that is not Your original creation,
+  You may submit it to TianoCore site separately from any
+  Contribution, identifying the complete details of its source
+  and of any license or other restriction (including, but not
+  limited to, related patents, trademarks, and license agreements)
+  of which You are personally aware, and conspicuously marking the
+  work as "Submitted on behalf of a third-party: [named here]".
+
+== SECTION 5: Miscellaneous ==
+* Applicable Laws. Any claims arising under or relating to this
+  Agreement shall be governed by the internal substantive laws of
+  the State of Delaware or federal courts located in Delaware,
+  without regard to principles of conflict of laws.
+* Language. This Agreement is in the English language only, which
+  language shall be controlling in all respects, and all versions
+  of this Agreement in any other language shall be for accommodation
+  only and shall not be binding. All communications and notices made
+  or given pursuant to this Agreement, and all documentation and
+  support to be provided, unless otherwise noted, shall be in the
+  English language.
+

+ 25 - 0
QuarkSocPkg/License.txt

@@ -0,0 +1,25 @@
+Copyright (c) 2012, Intel Corporation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in
+  the documentation and/or other materials provided with the
+  distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.

+ 257 - 0
QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h

@@ -0,0 +1,257 @@
+/** @file
+Memory controller configuration.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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

+ 23 - 0
QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h

@@ -0,0 +1,23 @@
+/** @file
+Public include file for the QNC Base
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __INTEL_QNC_BASE_H__
+#define __INTEL_QNC_BASE_H__
+
+#include <IntelQNCRegs.h>
+#include <IntelQNCConfig.h>
+
+#endif
+

+ 106 - 0
QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h

@@ -0,0 +1,106 @@
+/** @file
+Some configuration of QNC Package
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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
+

+ 23 - 0
QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h

@@ -0,0 +1,23 @@
+/** @file
+Public include file for the QNC Dxe
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __INTEL_QNC_DXE_H__
+#define __INTEL_QNC_DXE_H__
+
+#include <IntelQNCRegs.h>
+#include <IntelQNCConfig.h>
+
+#endif
+

+ 23 - 0
QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h

@@ -0,0 +1,23 @@
+/** @file
+Public include file for the QNC Pei
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __INTEL_QNC_PEIM_H__
+#define __INTEL_QNC_PEIM_H__
+
+#include <IntelQNCRegs.h>
+#include <IntelQNCConfig.h>
+
+#endif
+

+ 54 - 0
QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h

@@ -0,0 +1,54 @@
+/** @file
+Registers definition for Intel QuarkNcSocId.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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__

+ 290 - 0
QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h

@@ -0,0 +1,290 @@
+/** @file
+Library that provides QNC specific library services in PEI phase
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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
+

+ 167 - 0
QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h

@@ -0,0 +1,167 @@
+/** @file
+Library functions for Setting QNC internal network port
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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

+ 63 - 0
QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h

@@ -0,0 +1,63 @@
+/** @file
+QNC Smm Library Services header file.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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
+

+ 42 - 0
QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h

@@ -0,0 +1,42 @@
+/** @file
+Memory Initialization PPI used in EFI PEI interface
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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

+ 54 - 0
QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h

@@ -0,0 +1,54 @@
+/** @file
+This file defines the QNC Info Protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+#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

+ 37 - 0
QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h

@@ -0,0 +1,37 @@
+/** @file
+Protocol used for Platform Policy definition.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#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

+ 90 - 0
QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h

@@ -0,0 +1,90 @@
+/** @file
+This file defines the QNC S3 support Protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+#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

+ 121 - 0
QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h

@@ -0,0 +1,121 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#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

+ 351 - 0
QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h

@@ -0,0 +1,351 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+#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

+ 183 - 0
QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h

@@ -0,0 +1,183 @@
+/** @file
+Macros to simplify and abstract the interface to PCI configuration.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#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
+

+ 356 - 0
QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h

@@ -0,0 +1,356 @@
+/** @file
+This header file provides common definitions just for MCH using to avoid including extra module's file.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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

+ 757 - 0
QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h

@@ -0,0 +1,757 @@
+/** @file
+QuarkNcSocId Register Definitions
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+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

+ 38 - 0
QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h

@@ -0,0 +1,38 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#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

+ 777 - 0
QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c

@@ -0,0 +1,777 @@
+/** @file
+Lib function for Pei QNC.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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);
+}

+ 63 - 0
QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf

@@ -0,0 +1,63 @@
+## @file
+# Intel QNC Library Instance
+#
+# Intel QNC Library Instance
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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 IPF 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

+ 949 - 0
QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c

@@ -0,0 +1,949 @@
+/** @file
+QNC PCI Express initialization entry
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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    EndPointVendorId;
+  UINT16    EndPointDeviceId;
+  UINT8     EndPointRevId;
+  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;
+
+  //
+  // Mask APMC with values from lookup table.
+  // RevID of 0xFF applies to all steppings.
+  //
+
+  EndPointVendorId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 0);
+  EndPointDeviceId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 2);
+  EndPointRevId    = QNCMmPci8 (0, EndpointBus, EndpointDevice, EndpointFunction, 8);
+
+  // 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;
+  UINT64            LpcBase;
+  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);
+  LpcBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + (31 << 3) + (0 << 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                            QNCGpioBase;
+  UINT32                            QNCPmioBase;
+  UINT32                            QNCGpeBase;
+  UINTN                             RpEnableMask;
+  PCIEXP_ROOT_PORT_CONFIGURATION    *mRootPortConfig;
+  QNC_DEVICE_ENABLES                mQNCDeviceEnables;
+
+  //
+  // Get BAR registers
+  //
+  QNCRootComplexBar  = QNC_RCRB_BASE;
+  QNCGpioBase        = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;
+  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;
+}
+

+ 2117 - 0
QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c

@@ -0,0 +1,2117 @@
+/** @file
+MTRR setting library
+
+Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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
+
+//
+// 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) & MTRR_LIB_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  TempQword;
+  UINT64  OrMask;
+  UINT64  ClearMask;
+
+  TempQword = 0;
+  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 & MTRR_LIB_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 paramter 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) | MTRR_LIB_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;
+
+    *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;
+    *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
+  } else {
+    *MtrrValidBitsMask    = MTRR_LIB_MSR_VALID_MASK;
+    *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
+  }
+}
+
+
+/**
+  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 & MTRR_LIB_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 & MTRR_LIB_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 |= MTRR_LIB_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 & MTRR_LIB_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 & MTRR_LIB_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 & MTRR_LIB_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 & MTRR_LIB_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 |= MTRR_LIB_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;
+}

+ 48 - 0
QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf

@@ -0,0 +1,48 @@
+## @file
+#  MTRR library provides APIs for MTRR operation.
+#
+#  Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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
+

+ 24 - 0
QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni

@@ -0,0 +1,24 @@
+// /** @file
+// MtrrLib Module Localized Abstract and Description Content
+//
+// Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution.  The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#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."
+

+ 34 - 0
QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c

@@ -0,0 +1,34 @@
+/** @file
+Base Lib function for QNC internal network access.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// 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);
+}

+ 333 - 0
QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c

@@ -0,0 +1,333 @@
+/** @file
+Common Lib function for QNC internal network access.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// 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);
+}

+ 43 - 0
QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf

@@ -0,0 +1,43 @@
+## @file
+# Base Intel QNC Library Instance
+#
+# Intel QNC internal network access Library Instance
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+[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

+ 148 - 0
QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c

@@ -0,0 +1,148 @@
+/** @file
+Runtime Lib function for QNC internal network access.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#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;
+}
+

+ 49 - 0
QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf

@@ -0,0 +1,49 @@
+## @file
+# DXE Runtime Intel QNC Library Instance
+#
+# Intel QNC internal network access Library Instance.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+[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

+ 322 - 0
QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c

@@ -0,0 +1,322 @@
+/** @file
+QNC Smm Library Services that implements SMM Region access, S/W SMI generation and detection.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <Base.h>
+#include <IntelQNCRegs.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Uefi/UefiBaseType.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        PM1BLK_Base;
+  UINT16        GPE0BLK_Base;
+  UINT32        NewValue;
+
+  //
+  // Get PM1BLK_Base & GPE0BLK_Base
+  //
+  PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
+  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;
+}

+ 51 - 0
QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf

@@ -0,0 +1,51 @@
+## @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-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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 IPF EBC
+#
+
+[Sources]
+  QNCSmmLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+  PcdLib
+  IoLib
+  DebugLib
+  QNCAccessLib
+
+[Pcd]
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort
+  gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationData

+ 322 - 0
QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c

@@ -0,0 +1,322 @@
+/** @file
+System reset Library Services.  This library class provides a set of
+methods to reset whole system with manipulate QNC.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 ();
+  }
+}
+

+ 52 - 0
QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf

@@ -0,0 +1,52 @@
+## @file
+# Component description file for Intel QuarkNcSocId Reset System Library.
+#
+# Reset System Library implementation that bases on QNC.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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

+ 31 - 0
QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h

@@ -0,0 +1,31 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#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

+ 803 - 0
QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c

@@ -0,0 +1,803 @@
+/** @file
+Intel QNC SMBUS library implementation built upon I/O library.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// 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;
+}

+ 53 - 0
QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf

@@ -0,0 +1,53 @@
+## @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-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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 IPF 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

+ 438 - 0
QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c

@@ -0,0 +1,438 @@
+/** @file
+The Quark CPU specific programming for PiSmmCpuDxeSmm module.
+
+Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiSmm.h>
+#include <Library/SmmCpuFeaturesLib.h>
+#include <Register/SmramSaveStateMap.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];
+
+  //
+  // 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;
+}

+ 34 - 0
QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf

@@ -0,0 +1,34 @@
+## @file
+#  The CPU specific programming for PiSmmCpuDxeSmm module.
+#
+#  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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]
+  QNCAccessLib
+

+ 18 - 0
QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni

@@ -0,0 +1,18 @@
+// /** @file
+// The CPU specific programming for PiSmmCpuDxeSmm module.
+//
+// Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution.  The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#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."

+ 65 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c

@@ -0,0 +1,65 @@
+/** @file
+Framework PEIM to initialize memory on a QuarkNcSocId Memory Controller.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// 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);
+}

+ 41 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h

@@ -0,0 +1,41 @@
+/** @file
+Framework PEIM to initialize memory on an DDR2 SDRAM Memory Controller.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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

+ 76 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf

@@ -0,0 +1,76 @@
+## @file
+# This is the Memory Initialization Driver for Quark
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+################################################################################
+#
+# 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 IPF 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

+ 49 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h

@@ -0,0 +1,49 @@
+/** @file
+Core types used in Mrc.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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
+

+ 744 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h

@@ -0,0 +1,744 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ * 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

+ 90 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h

@@ -0,0 +1,90 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#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

+ 542 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c

@@ -0,0 +1,542 @@
+/** @file
+HTE handling routines for MRC use.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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();
+}
+

+ 72 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h

@@ -0,0 +1,72 @@
+/** @file
+HTE handling routines for MRC use.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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

+ 138 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h

@@ -0,0 +1,138 @@
+/** @file
+Declaration of IO handling routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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

+ 388 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c

@@ -0,0 +1,388 @@
+/** @file
+Serial conole output and string formating.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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

+ 2645 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c

@@ -0,0 +1,2645 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ * 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, TRFC, 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);
+  TRFC = MCEIL(tRFC[mrc_params->params.DENSITY], 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;
+}

+ 28 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h

@@ -0,0 +1,28 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#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_

+ 1580 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c

@@ -0,0 +1,1580 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ***************************************************************************/
+
+#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;
+}
+

+ 97 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h

@@ -0,0 +1,97 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ***************************************************************************/
+#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
+void *memset(void *d, int c, size_t n);
+void *memcpy(void *d, const void *s, size_t n);
+#endif
+
+#endif // _MEMINIT_UTILS_H_

+ 83 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h

@@ -0,0 +1,83 @@
+/** @file
+Common definitions and compilation switches for MRC
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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

+ 46 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c

@@ -0,0 +1,46 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#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;
+}
+

+ 166 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h

@@ -0,0 +1,166 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#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_

+ 192 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c

@@ -0,0 +1,192 @@
+/** @file
+The interface layer for memory controller access.
+It is supporting both real hardware platform and simulation environment.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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));
+}
+

+ 193 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c

@@ -0,0 +1,193 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+
+#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;
+}
+

+ 21 - 0
QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h

@@ -0,0 +1,21 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution.  The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#ifndef __PREMEMINIT_H_
+#define __PREMEMINIT_H_
+
+// Function prototypes
+void PreMemInit(MRCParams_t *mrc_params);
+
+
+#endif // _PREMEMINIT_H_

+ 55 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#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

+ 618 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c

@@ -0,0 +1,618 @@
+/** @file
+Implementation for SMBus DXE driver entry point and SMBus Host
+Controller protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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;
+}

+ 211 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h

@@ -0,0 +1,211 @@
+/** @file
+Header file for the defintions used in SMBus DXE driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#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

+ 243 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c

@@ -0,0 +1,243 @@
+/** @file
+QNC Legacy Region Driver
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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;
+}

+ 204 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h

@@ -0,0 +1,204 @@
+/** @file
+The header file legacy region initialization in QNC DXE component.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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_

+ 527 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c

@@ -0,0 +1,527 @@
+/** @file
+QuarkNcSocId module initialization module
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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 (
+  )
+{
+  UINT8        RevisionID;
+  UINT32       PciD31F0RegBase;  // LPC
+
+  RevisionID = LpcPciCfg8(R_QNC_LPC_REV_ID);
+
+  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;
+}

+ 55 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h

@@ -0,0 +1,55 @@
+/** @file
+Header file for QNC Initialization Driver.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+#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

+ 98 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf

@@ -0,0 +1,98 @@
+## @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-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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 IPF 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

+ 82 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c

@@ -0,0 +1,82 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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;
+}

+ 86 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h

@@ -0,0 +1,86 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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

+ 252 - 0
QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c

@@ -0,0 +1,252 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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;
+}
+

+ 423 - 0
QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c

@@ -0,0 +1,423 @@
+/** @file
+This is the driver that implements the QNC S3 Support protocol
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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 boundry
+  //
+  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);
+}
+

+ 123 - 0
QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h

@@ -0,0 +1,123 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#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

+ 70 - 0
QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf

@@ -0,0 +1,70 @@
+## @file
+#    Component description file for Qnc Initialization driver
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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

+ 54 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf

@@ -0,0 +1,54 @@
+## @file
+# Component description file for SmmAccess module
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[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
+  PcdLib
+  SmmLib
+
+[Protocols]
+  gEfiPciRootBridgeIoProtocolGuid
+  gEfiSmmAccess2ProtocolGuid
+
+[Guids]
+  gEfiSmmPeiSmramMemoryReserveGuid
+
+[Depex]
+  gEfiPciRootBridgeIoProtocolGuid

+ 395 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c

@@ -0,0 +1,395 @@
+/** @file
+This is the driver that publishes the SMM Access Protocol
+instance for the Tylersburg chipset.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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.
+
+--*/
+{
+  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;
+  }
+
+  //
+  // 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;
+    }
+  }
+}

+ 235 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h

@@ -0,0 +1,235 @@
+/** @file
+Header file for SMM Access Driver.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#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/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

+ 366 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c

@@ -0,0 +1,366 @@
+/** @file
+This module produces the SMM COntrol2 Protocol for QNC
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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                       PM1BLK_Base;
+  UINT16                       GPE0BLK_Base;
+
+  //
+  // Get PM1BLK_Base & GPE0BLK_Base
+  //
+  PM1BLK_Base  = PcdGet16 (PcdPm1blkIoBaseAddress);
+  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;
+}

+ 61 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf

@@ -0,0 +1,61 @@
+## @file
+# QNC SmmControl driver to install EFI_SMM_CONTROL_PROTOCOL.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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

+ 51 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h

@@ -0,0 +1,51 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#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

+ 38 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c

@@ -0,0 +1,38 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// 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
+  }
+  }
+};
+

+ 555 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c

@@ -0,0 +1,555 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// 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;
+  };
+}

+ 430 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c

@@ -0,0 +1,430 @@
+/** @file
+File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// 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;
+    *HwContext = Record->ChildContext;
+  }
+}
+
+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);
+  }
+}
+

+ 217 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c

@@ -0,0 +1,217 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm QNCn dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// 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);
+}

+ 96 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c

@@ -0,0 +1,96 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm Sw dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// 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;
+}

+ 153 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c

@@ -0,0 +1,153 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm Sx dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// 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);
+}

+ 871 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h

@@ -0,0 +1,871 @@
+/** @file
+Prototypes and defines for the QNC SMM Dispatcher.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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;
+
+  //
+  // Status and Enable bit description
+  //
+  QNC_SMM_SOURCE_DESC   SrcDesc;
+
+  //
+  // Callback function
+  //
+  EFI_SMM_HANDLER_ENTRY_POINT2      Callback;
+  QNC_SMM_CONTEXT       ChildContext;
+  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

+ 800 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c

@@ -0,0 +1,800 @@
+/** @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.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// 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->ChildContext      = *RegisterContext;
+
+  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
+      //
+      Record->ChildContext = *RegisterContext;
+    }
+
+    //
+    // 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;
+  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;
+
+  //
+  // 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);
+
+        //
+        // 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);
+
+            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);
+                Context       = RecordToExhaust->ChildContext;
+                ContextsMatch = 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,
+                                   &Context,
+                                   CommunicationBuffer,
+                                   &BufferSize
+                                   );
+
+                ChildWasDispatched = TRUE;
+                if (RecordToExhaust->ProtocolType == SxType) {
+                  SxChildWasDispatched = TRUE;
+                }
+              }
+            }
+            //
+            // Get next record in DB
+            //
+            LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link);
+          }
+
+          if (RecordInDb->ClearSource == NULL) {
+            //
+            // Clear the SMI associated w/ the source using the default function
+            //
+            QNCSmmClearSource (&ActiveSource);
+          } else {
+            //
+            // This source requires special handling to clear
+            //
+            RecordInDb->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;
+}

+ 87 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf

@@ -0,0 +1,87 @@
+## @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-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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 IPF 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

+ 373 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c

@@ -0,0 +1,373 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// 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.
+        //
+      }
+    }
+  }
+}

+ 225 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h

@@ -0,0 +1,225 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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

+ 19 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h

@@ -0,0 +1,19 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef QNC_SMM_REGISTERS_H
+#define QNC_SMM_REGISTERS_H
+#include "CommonHeader.h"
+
+#endif

+ 184 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h

@@ -0,0 +1,184 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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

+ 382 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c

@@ -0,0 +1,382 @@
+/** @file
+This is the driver that publishes the SMM Access Ppi
+instance for the Quark SOC.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#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;
+}
+

+ 51 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf

@@ -0,0 +1,51 @@
+## @file
+# Component description file for SmmAccessPei module
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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

+ 282 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c

@@ -0,0 +1,282 @@
+/** @file
+This module provides an implementation of the SMM Control PPI for use with
+the QNC.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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                       PM1BLK_Base;
+  UINT16                       GPE0BLK_Base;
+
+  //
+  // Get PM1BLK_Base & GPE0BLK_Base
+  //
+  PM1BLK_Base  = PcdGet16 (PcdPm1blkIoBaseAddress);
+  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;
+}

+ 57 - 0
QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf

@@ -0,0 +1,57 @@
+## @file
+# Component description file for SmmControlPei module.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[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

Some files were not shown because too many files changed in this diff