summaryrefslogtreecommitdiffstats
path: root/QuarkSocPkg
diff options
context:
space:
mode:
Diffstat (limited to 'QuarkSocPkg')
-rw-r--r--QuarkSocPkg/Contributions.txt218
-rw-r--r--QuarkSocPkg/License.txt25
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h257
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h23
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h106
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h23
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h23
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h54
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h290
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h167
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h63
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h42
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h54
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h37
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h90
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h121
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h351
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h183
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h356
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h757
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h38
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c777
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf63
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c949
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c2117
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf48
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni24
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c34
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c333
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf43
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c148
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf49
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c322
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf51
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c322
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf52
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h31
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c803
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf53
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c438
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf34
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni18
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c65
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h41
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf76
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h49
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h744
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h90
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c542
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h72
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h138
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c388
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c2645
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h28
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c1580
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h97
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h83
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c46
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h166
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c192
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c193
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h21
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h55
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c618
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h211
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c243
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h204
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c527
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h55
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf98
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c82
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h86
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c252
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c423
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h123
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf70
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf54
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c395
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h235
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c366
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf61
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h51
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c38
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c555
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c430
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c217
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c96
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c153
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h871
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c800
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf87
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c373
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h225
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h19
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h184
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c382
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf51
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c282
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf57
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c956
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h323
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf90
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf56
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c211
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h85
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c129
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h53
-rw-r--r--QuarkSocPkg/QuarkSocPkg.dec240
-rw-r--r--QuarkSocPkg/QuarkSocPkg.dsc259
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h120
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h101
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h254
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h24
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h348
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h158
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h42
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/MMC.h280
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h152
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h339
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h61
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h89
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c48
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c43
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf82
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h220
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c1004
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf68
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h35
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c105
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf55
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c233
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h147
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c1789
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h322
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf62
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c656
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c396
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c221
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h145
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c544
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c1716
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c323
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h468
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf66
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c326
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h44
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf59
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c225
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h147
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h138
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c2488
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h669
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c84
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h48
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf77
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c1399
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h926
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c534
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h231
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c895
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h393
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c566
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h158
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h137
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c1402
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h258
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf62
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c1394
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h881
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c229
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h114
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c566
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h237
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c497
-rw-r--r--QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h140
175 files changed, 54714 insertions, 0 deletions
diff --git a/QuarkSocPkg/Contributions.txt b/QuarkSocPkg/Contributions.txt
new file mode 100644
index 0000000000..f87cbd73c6
--- /dev/null
+++ b/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.
+
diff --git a/QuarkSocPkg/License.txt b/QuarkSocPkg/License.txt
new file mode 100644
index 0000000000..be68999be6
--- /dev/null
+++ b/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.
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h b/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h
new file mode 100644
index 0000000000..de777c564a
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h b/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h
new file mode 100644
index 0000000000..92ad948943
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h b/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h
new file mode 100644
index 0000000000..77360121a6
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h b/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h
new file mode 100644
index 0000000000..c2665958a0
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h b/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h
new file mode 100644
index 0000000000..5b27b1d098
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h b/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h
new file mode 100644
index 0000000000..63dd04cd55
--- /dev/null
+++ b/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__
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h b/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h
new file mode 100644
index 0000000000..7cda8b1b00
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h b/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h
new file mode 100644
index 0000000000..4496167a8f
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h b/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h
new file mode 100644
index 0000000000..731aebc0a9
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h b/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h
new file mode 100644
index 0000000000..2d99bff19c
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h b/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h
new file mode 100644
index 0000000000..26c78ef63d
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h b/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h
new file mode 100644
index 0000000000..e080bcc825
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h b/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h
new file mode 100644
index 0000000000..9d39932f58
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h b/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h
new file mode 100644
index 0000000000..e3f72919a7
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h b/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h
new file mode 100644
index 0000000000..137f9b376c
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h b/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h
new file mode 100644
index 0000000000..b77d3c9365
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h b/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h
new file mode 100644
index 0000000000..88d3d88810
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h b/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h
new file mode 100644
index 0000000000..a9f3eddbc6
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h b/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h
new file mode 100644
index 0000000000..ba25fd146a
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c b/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c
new file mode 100644
index 0000000000..142b508a74
--- /dev/null
+++ b/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);
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf b/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf
new file mode 100644
index 0000000000..691a7e42a8
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c b/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c
new file mode 100644
index 0000000000..5cb0fb8554
--- /dev/null
+++ b/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;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c b/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c
new file mode 100644
index 0000000000..4a88dff21a
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf b/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf
new file mode 100644
index 0000000000..d0c2d5a511
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni b/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni
new file mode 100644
index 0000000000..85afa9c9ef
--- /dev/null
+++ b/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."
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c b/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c
new file mode 100644
index 0000000000..ccf64f7f1b
--- /dev/null
+++ b/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);
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c b/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c
new file mode 100644
index 0000000000..4e77cc2640
--- /dev/null
+++ b/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);
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf b/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf
new file mode 100644
index 0000000000..6fb2d66054
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c b/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c
new file mode 100644
index 0000000000..a421759902
--- /dev/null
+++ b/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;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf b/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf
new file mode 100644
index 0000000000..e734aed451
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c b/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c
new file mode 100644
index 0000000000..6ddc09973a
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf b/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf
new file mode 100644
index 0000000000..00f80312c2
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c b/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c
new file mode 100644
index 0000000000..c2ad7f3e1d
--- /dev/null
+++ b/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 ();
+ }
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf b/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf
new file mode 100644
index 0000000000..f82fd49a0e
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h b/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h
new file mode 100644
index 0000000000..11eaa0fbfc
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c b/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c
new file mode 100644
index 0000000000..c80348b10d
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf b/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf
new file mode 100644
index 0000000000..fef03aa334
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c b/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
new file mode 100644
index 0000000000..6c46645531
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf b/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
new file mode 100644
index 0000000000..473ece0d49
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni b/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni
new file mode 100644
index 0000000000..322aa8bb5a
--- /dev/null
+++ b/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."
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c
new file mode 100644
index 0000000000..782a2d13a7
--- /dev/null
+++ b/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);
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h
new file mode 100644
index 0000000000..5d61c4d71c
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf
new file mode 100644
index 0000000000..e32768446e
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h
new file mode 100644
index 0000000000..78807a0958
--- /dev/null
+++ b/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
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h
new file mode 100644
index 0000000000..a8083a1f98
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h
new file mode 100644
index 0000000000..c5f92b3b5d
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c
new file mode 100644
index 0000000000..92ec4ba1f6
--- /dev/null
+++ b/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();
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h
new file mode 100644
index 0000000000..eeb6192ca0
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h
new file mode 100644
index 0000000000..7419c593dc
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c
new file mode 100644
index 0000000000..f77db8b78b
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c
new file mode 100644
index 0000000000..26c56e6037
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h
new file mode 100644
index 0000000000..e2c126672f
--- /dev/null
+++ b/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_
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c
new file mode 100644
index 0000000000..f0c8757b22
--- /dev/null
+++ b/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;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h
new file mode 100644
index 0000000000..04c59f5af0
--- /dev/null
+++ b/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_
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h
new file mode 100644
index 0000000000..8452b98814
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c
new file mode 100644
index 0000000000..ae7e239c8c
--- /dev/null
+++ b/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;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h
new file mode 100644
index 0000000000..05055db57c
--- /dev/null
+++ b/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_
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c
new file mode 100644
index 0000000000..cb6eb99f74
--- /dev/null
+++ b/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));
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c
new file mode 100644
index 0000000000..f34eb4a6c1
--- /dev/null
+++ b/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;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h
new file mode 100644
index 0000000000..78cca36f75
--- /dev/null
+++ b/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_
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h
new file mode 100644
index 0000000000..e0fa485640
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c
new file mode 100644
index 0000000000..a5927ecc40
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h
new file mode 100644
index 0000000000..306576bd8b
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c
new file mode 100644
index 0000000000..28c79b0ebb
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h
new file mode 100644
index 0000000000..7bcb884a33
--- /dev/null
+++ b/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_
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c
new file mode 100644
index 0000000000..c434067f72
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h
new file mode 100644
index 0000000000..c6d8592cae
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf
new file mode 100644
index 0000000000..0bafdd8515
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c
new file mode 100644
index 0000000000..e87d1f45fc
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h
new file mode 100644
index 0000000000..d0c3e577df
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c b/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c
new file mode 100644
index 0000000000..3fda2a38d5
--- /dev/null
+++ b/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;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c b/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c
new file mode 100644
index 0000000000..9290311ab2
--- /dev/null
+++ b/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);
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h b/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h
new file mode 100644
index 0000000000..140167e0ad
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf b/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf
new file mode 100644
index 0000000000..f9d3c69acf
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf
new file mode 100644
index 0000000000..c50ac5329d
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c
new file mode 100644
index 0000000000..51432b6dcf
--- /dev/null
+++ b/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;
+ }
+ }
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h
new file mode 100644
index 0000000000..26db976992
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
new file mode 100644
index 0000000000..72ba79767f
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf
new file mode 100644
index 0000000000..e498463f31
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h
new file mode 100644
index 0000000000..3a5b15220a
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c
new file mode 100644
index 0000000000..eb9c6df5fa
--- /dev/null
+++ b/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
+ }
+ }
+};
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
new file mode 100644
index 0000000000..9784359de1
--- /dev/null
+++ b/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;
+ };
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c
new file mode 100644
index 0000000000..1d1030c0ae
--- /dev/null
+++ b/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);
+ }
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c
new file mode 100644
index 0000000000..53ee3eadf6
--- /dev/null
+++ b/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);
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c
new file mode 100644
index 0000000000..b4f56e899d
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c
new file mode 100644
index 0000000000..9d0de36b63
--- /dev/null
+++ b/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);
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h
new file mode 100644
index 0000000000..892294fa71
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c
new file mode 100644
index 0000000000..ba8c721773
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf
new file mode 100644
index 0000000000..ed948253e9
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c
new file mode 100644
index 0000000000..db6102981b
--- /dev/null
+++ b/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.
+ //
+ }
+ }
+ }
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h
new file mode 100644
index 0000000000..d2572d3e92
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h
new file mode 100644
index 0000000000..3474c56ae2
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h
new file mode 100644
index 0000000000..53027c4bf4
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c
new file mode 100644
index 0000000000..70fdf09611
--- /dev/null
+++ b/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;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf
new file mode 100644
index 0000000000..a1e4af7725
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c
new file mode 100644
index 0000000000..8c82611056
--- /dev/null
+++ b/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;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf
new file mode 100644
index 0000000000..6b1dd1bcfd
--- /dev/null
+++ b/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
diff --git a/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c b/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c
new file mode 100644
index 0000000000..e3d9b8f7de
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c
@@ -0,0 +1,956 @@
+/** @file
+PCH SPI Common Driver implements the 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.
+
+**/
+
+#include "PchSpi.h"
+
+VOID
+FillOutPublicInfoStruct (
+ SPI_INSTANCE *SpiInstance
+ )
+/*++
+
+Routine Description:
+
+ Fillout SpiInstance->InitInfo;
+
+Arguments:
+
+ SpiInstance - Pointer to SpiInstance to initialize
+
+Returns:
+
+ NONE
+
+--*/
+{
+ UINT8 Index;
+
+ SpiInstance->InitInfo.InitTable = &SpiInstance->SpiInitTable;
+
+ //
+ // Give invalid index in case operation not supported.
+ //
+ SpiInstance->InitInfo.JedecIdOpcodeIndex = 0xff;
+ SpiInstance->InitInfo.OtherOpcodeIndex = 0xff;
+ SpiInstance->InitInfo.WriteStatusOpcodeIndex = 0xff;
+ SpiInstance->InitInfo.ProgramOpcodeIndex = 0xff;
+ SpiInstance->InitInfo.ReadOpcodeIndex = 0xff;
+ SpiInstance->InitInfo.EraseOpcodeIndex = 0xff;
+ SpiInstance->InitInfo.ReadStatusOpcodeIndex = 0xff;
+ SpiInstance->InitInfo.FullChipEraseOpcodeIndex = 0xff;
+ for (Index = 0; Index < SPI_NUM_OPCODE; Index++) {
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) {
+ SpiInstance->InitInfo.JedecIdOpcodeIndex = Index;
+ }
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationOther) {
+ SpiInstance->InitInfo.OtherOpcodeIndex = Index;
+ }
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) {
+ SpiInstance->InitInfo.WriteStatusOpcodeIndex = Index;
+ }
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_1_Byte ||
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_64_Byte) {
+ SpiInstance->InitInfo.ProgramOpcodeIndex = Index;
+ }
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadData ||
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFastRead ||
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDualOutputFastRead) {
+ SpiInstance->InitInfo.ReadOpcodeIndex = Index;
+ }
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_256_Byte ||
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_4K_Byte ||
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_8K_Byte ||
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_64K_Byte) {
+ SpiInstance->InitInfo.EraseOpcodeIndex = Index;
+ }
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadStatus) {
+ SpiInstance->InitInfo.ReadStatusOpcodeIndex = Index;
+ }
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFullChipErase) {
+ SpiInstance->InitInfo.FullChipEraseOpcodeIndex = Index;
+ }
+ }
+}
+
+EFI_STATUS
+SpiProtocolConstructor (
+ SPI_INSTANCE *SpiInstance
+ )
+/*++
+
+Routine Description:
+
+ Initialize an SPI protocol instance.
+ The function will assert in debug if PCH RCBA has not been initialized
+
+Arguments:
+
+ SpiInstance - Pointer to SpiInstance to initialize
+
+Returns:
+
+ EFI_SUCCESS The protocol instance was properly initialized
+ EFI_UNSUPPORTED The PCH is not supported by this module
+
+--*/
+{
+ SpiInstance->InitDone = FALSE; // Indicate NOT READY.
+
+ //
+ // Check if the current PCH is known and supported by this code
+ //
+ if (!IsQncSupported ()) {
+ DEBUG ((DEBUG_ERROR, "PCH SPI Protocol not supported due to no proper QNC LPC found!\n"));
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Initialize the SPI protocol instance
+ //
+ SpiInstance->Signature = PCH_SPI_PRIVATE_DATA_SIGNATURE;
+ SpiInstance->Handle = NULL;
+ SpiInstance->SpiProtocol.Init = SpiProtocolInit;
+ SpiInstance->SpiProtocol.Lock = SpiProtocolLock;
+ SpiInstance->SpiProtocol.Execute = SpiProtocolExecute;
+ SpiInstance->SpiProtocol.Info = SpiProtocolInfo;
+
+ //
+ // Sanity check to ensure PCH RCBA initialization has occurred previously.
+ //
+ SpiInstance->PchRootComplexBar = MmioRead32 (
+ PciDeviceMmBase (PCI_BUS_NUMBER_QNC,
+ PCI_DEVICE_NUMBER_QNC_LPC,
+ PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_RCBA
+ ) & B_QNC_LPC_RCBA_MASK;
+ ASSERT (SpiInstance->PchRootComplexBar != 0);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UnlockFlashComponents (
+ IN EFI_SPI_PROTOCOL *This,
+ IN UINT8 UnlockCmdOpcodeIndex
+ )
+/*++
+
+Routine Description:
+
+ Issue unlock command to disable block protection, this only needs to be done once per SPI power on
+
+Arguments:
+
+ This A pointer to "EFI_SPI_PROTOCOL" for issuing commands
+ UnlockCmdOpcodeIndex The index of the Unlock command
+
+Returns:
+
+ EFI_SUCCESS UnLock operation succeed.
+ EFI_DEVICE_ERROR Device error, operation failed.
+
+--*/
+{
+ EFI_STATUS Status;
+ SPI_INSTANCE *SpiInstance;
+ UINT8 SpiStatus;
+ UINTN PchRootComplexBar;
+
+ if (UnlockCmdOpcodeIndex >= SPI_NUM_OPCODE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;
+
+ //
+ // Issue unlock command to disable block protection, this only needs to be done once per SPI power on
+ //
+ SpiStatus = 0;
+ //
+ // Issue unlock command to the flash component 1 at first
+ //
+ Status = SpiProtocolExecute (
+ This,
+ UnlockCmdOpcodeIndex,
+ SpiInstance->SpiInitTable.PrefixOpcode[0] == PCH_SPI_COMMAND_WRITE_ENABLE ? 0 : 1,
+ TRUE,
+ TRUE,
+ TRUE,
+ (UINTN) 0,
+ sizeof (SpiStatus),
+ &SpiStatus,
+ EnumSpiRegionAll
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Unlock flash component 1 fail!\n"));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiProtocolInit (
+ IN EFI_SPI_PROTOCOL *This,
+ IN SPI_INIT_TABLE *InitTable
+ )
+/*++
+
+Routine Description:
+
+ Initialize the host controller to execute SPI command.
+
+Arguments:
+
+ This Pointer to the EFI_SPI_PROTOCOL instance.
+ InitTable Initialization data to be programmed into the SPI host controller.
+
+Returns:
+
+ EFI_SUCCESS Initialization completed.
+ EFI_ACCESS_DENIED The SPI static configuration interface has been locked-down.
+ EFI_INVALID_PARAMETER Bad input parameters.
+ EFI_UNSUPPORTED Can't get Descriptor mode VSCC values
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT16 OpcodeType;
+ SPI_INSTANCE *SpiInstance;
+ BOOLEAN MultiPartitionIsSupported;
+ UINTN PchRootComplexBar;
+ UINT8 SFDPCmdOpcodeIndex;
+ UINT8 UnlockCmdOpcodeIndex;
+ UINT8 ReadDataCmdOpcodeIndex;
+ UINT8 FlashPartId[3];
+
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;
+
+ if (InitTable != NULL) {
+ //
+ // Copy table into SPI driver Private data structure
+ //
+ CopyMem (
+ &SpiInstance->SpiInitTable,
+ InitTable,
+ sizeof (SPI_INIT_TABLE)
+ );
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check if the SPI interface has been locked-down.
+ //
+ if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {
+ ASSERT_EFI_ERROR (EFI_ACCESS_DENIED);
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Clear all the status bits for status regs.
+ //
+ MmioOr16 (
+ (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS),
+ (UINT16) ((B_QNC_RCRB_SPIS_CDS | B_QNC_RCRB_SPIS_BAS))
+ );
+ MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS);
+
+ //
+ // Set the Prefix Opcode registers.
+ //
+ MmioWrite16 (
+ PchRootComplexBar + R_QNC_RCRB_SPIPREOP,
+ (SpiInstance->SpiInitTable.PrefixOpcode[1] << 8) | InitTable->PrefixOpcode[0]
+ );
+ MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIPREOP);
+
+ //
+ // Set Opcode Type Configuration registers.
+ //
+ for (Index = 0, OpcodeType = 0; Index < SPI_NUM_OPCODE; Index++) {
+ switch (SpiInstance->SpiInitTable.OpcodeMenu[Index].Type) {
+ case EnumSpiOpcodeRead:
+ OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_READ << (Index * 2));
+ break;
+ case EnumSpiOpcodeWrite:
+ OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_WRITE << (Index * 2));
+ break;
+ case EnumSpiOpcodeWriteNoAddr:
+ OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE << (Index * 2));
+ break;
+ default:
+ OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_READ << (Index * 2));
+ break;
+ }
+ }
+ MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE, OpcodeType);
+ MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE);
+
+ //
+ // Setup the Opcode Menu registers.
+ //
+ ReadDataCmdOpcodeIndex = SPI_NUM_OPCODE;
+ SFDPCmdOpcodeIndex = SPI_NUM_OPCODE;
+ UnlockCmdOpcodeIndex = SPI_NUM_OPCODE;
+ for (Index = 0; Index < SPI_NUM_OPCODE; Index++) {
+ MmioWrite8 (
+ PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index,
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Code
+ );
+ MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index);
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) {
+ Status = SpiProtocolExecute (
+ This,
+ Index,
+ 0,
+ TRUE,
+ TRUE,
+ FALSE,
+ (UINTN) 0,
+ 3,
+ FlashPartId,
+ EnumSpiRegionDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (FlashPartId[0] != SpiInstance->SpiInitTable.VendorId ||
+ FlashPartId[1] != SpiInstance->SpiInitTable.DeviceId0 ||
+ FlashPartId[2] != SpiInstance->SpiInitTable.DeviceId1) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadData ||
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFastRead ||
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDualOutputFastRead) {
+ ReadDataCmdOpcodeIndex = Index;
+ }
+
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDiscoveryParameters) {
+ SFDPCmdOpcodeIndex = Index;
+ }
+
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) {
+ UnlockCmdOpcodeIndex = Index;
+ }
+ }
+
+ MultiPartitionIsSupported = FALSE;
+
+ Status = UnlockFlashComponents (
+ This,
+ UnlockCmdOpcodeIndex
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Unlock flash components fail!\n"));
+ }
+
+ SpiPhaseInit ();
+ FillOutPublicInfoStruct (SpiInstance);
+ SpiInstance->InitDone = TRUE;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiProtocolLock (
+ IN EFI_SPI_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ Lock the SPI Static Configuration Interface.
+ Once locked, the interface can not be changed and can only be clear by system reset.
+
+Arguments:
+
+ This Pointer to the EFI_SPI_PROTOCOL instance.
+
+Returns:
+
+ EFI_SUCCESS Lock operation succeed.
+ EFI_DEVICE_ERROR Device error, operation failed.
+ EFI_ACCESS_DENIED The interface has already been locked.
+
+--*/
+{
+ SPI_INSTANCE *SpiInstance;
+ UINTN PchRootComplexBar;
+
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;
+
+ //
+ // Check if the SPI interface has been locked-down.
+ //
+ if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Lock-down the configuration interface.
+ //
+ MmioOr16 ((UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS), (UINT16) (B_QNC_RCRB_SPIS_SCL));
+
+ //
+ // Verify if it's really locked.
+ //
+ if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) == 0) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ //
+ // Save updated register in S3 Boot script.
+ //
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint16,
+ (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS),
+ 1,
+ (VOID *) (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS)
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiProtocolExecute (
+ IN EFI_SPI_PROTOCOL *This,
+ IN UINT8 OpcodeIndex,
+ IN UINT8 PrefixOpcodeIndex,
+ IN BOOLEAN DataCycle,
+ IN BOOLEAN Atomic,
+ IN BOOLEAN ShiftOut,
+ IN UINTN Address,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer,
+ IN SPI_REGION_TYPE SpiRegionType
+ )
+/*++
+
+Routine Description:
+
+ Execute SPI commands from the host controller.
+ This function would be called by runtime driver, please do not use any MMIO marco here
+
+Arguments:
+
+ This Pointer to the EFI_SPI_PROTOCOL instance.
+ OpcodeIndex Index of the command in the OpCode Menu.
+ PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
+ DataCycle TRUE if the SPI cycle contains data
+ Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+ ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+ Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+ Region, this value specifies the offset from the Region Base; for BIOS Region,
+ this value specifies the offset from the start of the BIOS Image. In Non
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+ the flash (in Non Descriptor Mode)
+ DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the
+ data transfer into multiple operations. This function ensures each operation does
+ not cross 256 byte flash address boundary.
+ *NOTE: if there is some SPI chip that has a stricter address boundary requirement
+ (e.g., its write page size is < 256 byte), then the caller cannot rely on this
+ function to cut the data transfer at proper address boundaries, and it's the
+ caller's reponsibility to pass in a properly cut DataByteCount parameter.
+ Buffer Pointer to caller-allocated buffer containing the dada received or sent during the
+ SPI cycle.
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+Returns:
+
+ EFI_SUCCESS Command succeed.
+ EFI_INVALID_PARAMETER The parameters specified are not valid.
+ EFI_UNSUPPORTED Command not supported.
+ EFI_DEVICE_ERROR Device error, command aborts abnormally.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT16 BiosCtlSave;
+ UINT32 SmiEnSave;
+
+ BiosCtlSave = 0;
+ SmiEnSave = 0;
+
+ //
+ // Check if the parameters are valid.
+ //
+ if ((OpcodeIndex >= SPI_NUM_OPCODE) || (PrefixOpcodeIndex >= SPI_NUM_PREFIX_OPCODE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Make sure it's safe to program the command.
+ //
+ if (!WaitForSpiCycleComplete (This, FALSE)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Acquire access to the SPI interface is not required any more.
+ //
+ //
+ // Disable SMIs to make sure normal mode flash access is not interrupted by an SMI
+ // whose SMI handler accesses flash (e.g. for error logging)
+ //
+ SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));
+
+ //
+ // Save BIOS Ctrl register
+ //
+ BiosCtlSave = PciRead16 (
+ PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
+ PCI_DEVICE_NUMBER_QNC_LPC,
+ PCI_FUNCTION_NUMBER_QNC_LPC,
+ R_QNC_LPC_BIOS_CNTL)
+ ) & (B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP);
+
+ //
+ // Enable flash writing
+ //
+ PciOr16 (
+ PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
+ PCI_DEVICE_NUMBER_QNC_LPC,
+ PCI_FUNCTION_NUMBER_QNC_LPC,
+ R_QNC_LPC_BIOS_CNTL),
+ (UINT16) (B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)
+ );
+
+ //
+ // If shifts the data out, disable Prefetching and Caching.
+ //
+ if (ShiftOut) {
+ PciAndThenOr16 (
+ PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
+ PCI_DEVICE_NUMBER_QNC_LPC,
+ PCI_FUNCTION_NUMBER_QNC_LPC,
+ R_QNC_LPC_BIOS_CNTL),
+ (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE)),
+ (UINT16) ((B_QNC_LPC_BIOS_CNTL_BCD))
+ );
+ }
+ //
+ // Sends the command to the SPI interface to execute.
+ //
+ Status = SendSpiCmd (
+ This,
+ OpcodeIndex,
+ PrefixOpcodeIndex,
+ DataCycle,
+ Atomic,
+ ShiftOut,
+ Address,
+ DataByteCount,
+ Buffer,
+ SpiRegionType
+ );
+
+ //
+ // Restore BIOS Ctrl register
+ //
+ PciAndThenOr16 (
+ PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
+ PCI_DEVICE_NUMBER_QNC_LPC,
+ PCI_FUNCTION_NUMBER_QNC_LPC,
+ R_QNC_LPC_BIOS_CNTL),
+ (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)),
+ (UINT16) (BiosCtlSave)
+ );
+ //
+ // Restore SMIs.
+ //
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, SmiEnSave);
+
+ return Status;
+}
+
+VOID
+SpiOffset2Physical (
+ IN EFI_SPI_PROTOCOL *This,
+ IN UINTN SpiRegionOffset,
+ IN SPI_REGION_TYPE SpiRegionType,
+ OUT UINTN *HardwareSpiAddress,
+ OUT UINTN *BaseAddress,
+ OUT UINTN *LimitAddress
+ )
+/*++
+
+Routine Description:
+
+ Convert SPI offset to Physical address of SPI hardware
+
+Arguments:
+
+ This Pointer to the EFI_SPI_PROTOCOL instance.
+ SpiRegionOffset In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+ Region, this value specifies the offset from the Region Base; for BIOS Region,
+ this value specifies the offset from the start of the BIOS Image. In Non
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+ the flash (in Non Descriptor Mode)
+ BaseAddress Base Address of the region.
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).
+ HardwareSpiAddress Return absolution SPI address (i.e., Flash Linear Address)
+ BaseAddress Return base address of the region type
+ LimitAddress Return limit address of the region type
+
+Returns:
+
+ EFI_SUCCESS Command succeed.
+
+--*/
+{
+ SPI_INSTANCE *SpiInstance;
+ UINTN PchRootComplexBar;
+
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;
+
+ if (SpiRegionType == EnumSpiRegionAll) {
+ //
+ // EnumSpiRegionAll indicates address is relative to flash device (i.e., address is Flash
+ // Linear Address)
+ //
+ *HardwareSpiAddress = SpiRegionOffset;
+ } else {
+ //
+ // Otherwise address is relative to BIOS image
+ //
+ *HardwareSpiAddress = SpiRegionOffset + SpiInstance->SpiInitTable.BiosStartOffset;
+ }
+}
+
+EFI_STATUS
+SendSpiCmd (
+ IN EFI_SPI_PROTOCOL *This,
+ IN UINT8 OpcodeIndex,
+ IN UINT8 PrefixOpcodeIndex,
+ IN BOOLEAN DataCycle,
+ IN BOOLEAN Atomic,
+ IN BOOLEAN ShiftOut,
+ IN UINTN Address,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer,
+ IN SPI_REGION_TYPE SpiRegionType
+ )
+/*++
+
+Routine Description:
+
+ This function sends the programmed SPI command to the slave device.
+
+Arguments:
+
+ OpcodeIndex Index of the command in the OpCode Menu.
+ PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
+ DataCycle TRUE if the SPI cycle contains data
+ Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+ ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+ Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+ Region, this value specifies the offset from the Region Base; for BIOS Region,
+ this value specifies the offset from the start of the BIOS Image. In Non
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+ the flash (in Non Descriptor Mode)
+ DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the
+ data transfer into multiple operations. This function ensures each operation does
+ not cross 256 byte flash address boundary.
+ *NOTE: if there is some SPI chip that has a stricter address boundary requirement
+ (e.g., its write page size is < 256 byte), then the caller cannot rely on this
+ function to cut the data transfer at proper address boundaries, and it's the
+ caller's reponsibility to pass in a properly cut DataByteCount parameter.
+ Buffer Data received or sent during the SPI cycle.
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+Returns:
+
+ EFI_SUCCESS SPI command completes successfully.
+ EFI_DEVICE_ERROR Device error, the command aborts abnormally.
+ EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode
+ EFI_INVALID_PARAMETER The parameters specified are not valid.
+
+--*/
+{
+ UINT32 Index;
+ SPI_INSTANCE *SpiInstance;
+ UINTN HardwareSpiAddr;
+ UINTN SpiBiosSize;
+ UINTN BaseAddress;
+ UINTN LimitAddress;
+ UINT32 SpiDataCount;
+ UINT8 OpCode;
+ SPI_OPERATION Operation;
+ UINTN PchRootComplexBar;
+
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;
+ SpiBiosSize = SpiInstance->SpiInitTable.BiosSize;
+ Operation = SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex].Operation;
+ OpCode = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + OpcodeIndex);
+
+ //
+ // Check if the value of opcode register is 0 or the BIOS Size of SpiInitTable is 0
+ //
+ if (OpCode == 0 || SpiBiosSize == 0) {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SpiOffset2Physical (This, Address, SpiRegionType, &HardwareSpiAddr, &BaseAddress, &LimitAddress);
+ //
+ // Have direct access to BIOS region in Descriptor mode,
+ //
+ if (SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex].Type == EnumSpiOpcodeRead &&
+ SpiRegionType == EnumSpiRegionBios) {
+ CopyMem (
+ Buffer,
+ (UINT8 *) ((HardwareSpiAddr - BaseAddress) + (UINT32) (~(SpiBiosSize - 1))),
+ DataByteCount
+ );
+ return EFI_SUCCESS;
+ }
+ //
+ // DEBUG((EFI_D_ERROR, "SPIADDR %x, %x, %x, %x\n", Address, HardwareSpiAddr, BaseAddress,
+ // LimitAddress));
+ //
+ if ((DataCycle == FALSE) && (DataByteCount > 0)) {
+ DataByteCount = 0;
+ }
+
+ do {
+ //
+ // Trim at 256 byte boundary per operation,
+ // - PCH SPI controller requires trimming at 4KB boundary
+ // - Some SPI chips require trimming at 256 byte boundary for write operation
+ // - Trimming has limited performance impact as we can read / write atmost 64 byte
+ // per operation
+ //
+ if (HardwareSpiAddr + DataByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 - 1))) {
+ SpiDataCount = (((UINT32) (HardwareSpiAddr) + BIT8) &~(BIT8 - 1)) - (UINT32) (HardwareSpiAddr);
+ } else {
+ SpiDataCount = DataByteCount;
+ }
+ //
+ // Calculate the number of bytes to shift in/out during the SPI data cycle.
+ // Valid settings for the number of bytes duing each data portion of the
+ // PCH SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64
+ //
+ if (SpiDataCount >= 64) {
+ SpiDataCount = 64;
+ } else if ((SpiDataCount &~0x07) != 0) {
+ SpiDataCount = SpiDataCount &~0x07;
+ }
+ //
+ // If shifts data out, load data into the SPI data buffer.
+ //
+ if (ShiftOut) {
+ for (Index = 0; Index < SpiDataCount; Index++) {
+ MmioWrite8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index, Buffer[Index]);
+ MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);
+ }
+ }
+
+ MmioWrite32 (
+ (PchRootComplexBar + R_QNC_RCRB_SPIA),
+ (UINT32) (HardwareSpiAddr & B_QNC_RCRB_SPIA_MASK)
+ );
+ MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIA);
+
+ //
+ // Execute the command on the SPI compatible mode
+ //
+
+ //
+ // Clear error flags
+ //
+ MmioOr16 ((PchRootComplexBar + R_QNC_RCRB_SPIS), B_QNC_RCRB_SPIS_BAS);
+
+ //
+ // Initialte the SPI cycle
+ //
+ if (DataCycle) {
+ MmioWrite16 (
+ (PchRootComplexBar + R_QNC_RCRB_SPIC),
+ ( (UINT16) (B_QNC_RCRB_SPIC_DC) | (UINT16) (((SpiDataCount - 1) << 8) & B_QNC_RCRB_SPIC_DBC) |
+ (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |
+ (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |
+ (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |
+ (UINT16) (B_QNC_RCRB_SPIC_SCGO)));
+ } else {
+ MmioWrite16 (
+ (PchRootComplexBar + R_QNC_RCRB_SPIC),
+ ( (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |
+ (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |
+ (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |
+ (UINT16) (B_QNC_RCRB_SPIC_SCGO)));
+ }
+
+ MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIC);
+
+ //
+ // end of command execution
+ //
+ // Wait the SPI cycle to complete.
+ //
+ if (!WaitForSpiCycleComplete (This, TRUE)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // If shifts data in, get data from the SPI data buffer.
+ //
+ if (!ShiftOut) {
+ for (Index = 0; Index < SpiDataCount; Index++) {
+ Buffer[Index] = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);
+ }
+ }
+
+ HardwareSpiAddr += SpiDataCount;
+ Buffer += SpiDataCount;
+ DataByteCount -= SpiDataCount;
+ } while (DataByteCount > 0);
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+WaitForSpiCycleComplete (
+ IN EFI_SPI_PROTOCOL *This,
+ IN BOOLEAN ErrorCheck
+ )
+/*++
+
+Routine Description:
+
+ Wait execution cycle to complete on the SPI interface. Check both Hardware
+ and Software Sequencing status registers
+
+Arguments:
+
+ This - The SPI protocol instance
+ UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation
+ ErrorCheck - TRUE if the SpiCycle needs to do the error check
+
+Returns:
+
+ TRUE SPI cycle completed on the interface.
+ FALSE Time out while waiting the SPI cycle to complete.
+ It's not safe to program the next command on the SPI interface.
+
+--*/
+{
+ UINT64 WaitTicks;
+ UINT64 WaitCount;
+ UINT16 Data16;
+ SPI_INSTANCE *SpiInstance;
+ UINTN PchRootComplexBar;
+
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;
+
+ //
+ // Convert the wait period allowed into to tick count
+ //
+ WaitCount = WAIT_TIME / WAIT_PERIOD;
+
+ //
+ // Wait for the SPI cycle to complete.
+ //
+ for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) {
+ Data16 = MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS);
+ if ((Data16 & B_QNC_RCRB_SPIS_SCIP) == 0) {
+ MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIS, (B_QNC_RCRB_SPIS_BAS | B_QNC_RCRB_SPIS_CDS));
+ if ((Data16 & B_QNC_RCRB_SPIS_BAS) && (ErrorCheck == TRUE)) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+ }
+
+ MicroSecondDelay (WAIT_PERIOD);
+ }
+
+ return FALSE;
+}
+
+EFI_STATUS
+EFIAPI
+SpiProtocolInfo (
+ IN EFI_SPI_PROTOCOL *This,
+ OUT SPI_INIT_INFO **InitInfoPtr
+ )
+/*++
+
+Routine Description:
+
+ Return info about SPI host controller, to help callers usage of Execute
+ service.
+
+ If 0xff is returned as an opcode index in init info struct
+ then device does not support the operation.
+
+Arguments:
+
+ This Pointer to the EFI_SPI_PROTOCOL instance.
+ InitInfoPtr Pointer to init info written to this memory location.
+
+Returns:
+
+ EFI_SUCCESS Information returned.
+ EFI_INVALID_PARAMETER Invalid parameter.
+ EFI_NOT_READY Required resources not setup.
+ Others Unexpected error happened.
+
+--*/
+{
+ SPI_INSTANCE *SpiInstance;
+
+ if (This == NULL || InitInfoPtr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+ if (SpiInstance->Signature != PCH_SPI_PRIVATE_DATA_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!SpiInstance->InitDone) {
+ *InitInfoPtr = NULL;
+ return EFI_NOT_READY;
+ }
+ *InitInfoPtr = &SpiInstance->InitInfo;
+ return EFI_SUCCESS;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h b/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h
new file mode 100644
index 0000000000..b8c1903be3
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h
@@ -0,0 +1,323 @@
+/** @file
+Header file for the PCH SPI Common 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 _SPI_COMMON_H_
+#define _SPI_COMMON_H_
+
+#include "Protocol/Spi.h"
+#include <Library/PciLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IntelQNCLib.h>
+#include <Library/QNCAccessLib.h>
+#include <Uefi/UefiBaseType.h>
+
+//
+// Maximum time allowed while waiting the SPI cycle to complete
+// Wait Time = 6 seconds = 6000000 microseconds
+// Wait Period = 10 microseconds
+//
+#define WAIT_TIME 6000000
+#define WAIT_PERIOD 10
+//
+// PCH Required SPI Commands -------- COMMAND SET I ------------
+// SPI flash device must support in order to be compatible with PCH
+//
+#define PCH_SPI_COMMAND_PROGRAM_BYTE 0x02
+#define PCH_SPI_COMMAND_READ_DATA 0x03
+#define PCH_SPI_COMMAND_WRITE_DISABLE 0x04
+#define PCH_SPI_COMMAND_READ_STATUS 0x05
+#define PCH_SPI_COMMAND_WRITE_ENABLE 0x06
+#define PCH_SPI_COMMAND_FAST_READ 0x0B
+#define PCH_SPI_COMMAND_READ_ID 0x9F
+#define PCH_SPI_COMMAND_DUAL_FAST_READ 0x3B // Dual Output Fast Read
+
+//
+// Need to support at least one of the following two kinds of size of sector for erasing
+//
+#define PCH_SPI_COMMAND_4KB_ERASE 0x20
+#define PCH_SPI_COMMAND_64KB_ERASE 0xD8
+//
+// Recommended SPI Commands -------- COMMAND SET II ------------
+// SPI flash device best to support
+//
+#define PCH_SPI_COMMAND_WRITE_STATUS 0x01
+#define PCH_SPI_COMMAND_FULL_CHIP_ERASE 0xC7
+
+//
+// Private data structure definitions for the driver
+//
+#define PCH_SPI_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'S', 'P', 'I')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_SPI_PROTOCOL SpiProtocol;
+ SPI_INIT_TABLE SpiInitTable;
+ UINTN PchRootComplexBar;
+ BOOLEAN InitDone; // Set to TRUE on SpiProtocolInit SUCCESS.
+ SPI_INIT_INFO InitInfo;
+} SPI_INSTANCE;
+
+#define SPI_INSTANCE_FROM_SPIPROTOCOL(a) CR (a, SPI_INSTANCE, SpiProtocol, PCH_SPI_PRIVATE_DATA_SIGNATURE)
+
+//
+// Function prototypes used by the SPI protocol.
+//
+EFI_STATUS
+SpiProtocolConstructor (
+ SPI_INSTANCE *SpiInstance
+ )
+/*++
+
+Routine Description:
+
+ Initialize an SPI protocol instance.
+ The function will assert in debug if PCH RCBA has not been initialized
+
+Arguments:
+
+ SpiInstance - Pointer to SpiInstance to initialize
+
+Returns:
+
+ EFI_SUCCESS The protocol instance was properly initialized
+ EFI_UNSUPPORTED The PCH is not supported by this module
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SpiProtocolInit (
+ IN EFI_SPI_PROTOCOL *This,
+ IN SPI_INIT_TABLE *InitTable
+ )
+/*++
+
+Routine Description:
+
+ Initialize the host controller to execute SPI command.
+
+Arguments:
+
+ This Pointer to the EFI_SPI_PROTOCOL instance.
+ InitTable Initialization data to be programmed into the SPI host controller.
+
+Returns:
+
+ EFI_SUCCESS Initialization completed.
+ EFI_ACCESS_DENIED The SPI static configuration interface has been locked-down.
+ EFI_INVALID_PARAMETER Bad input parameters.
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SpiProtocolLock (
+ IN EFI_SPI_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ Lock the SPI Static Configuration Interface.
+ Once locked, the interface can not be changed and can only be clear by system reset.
+
+Arguments:
+
+ This Pointer to the EFI_SPI_PROTOCOL instance.
+
+Returns:
+
+ EFI_SUCCESS Lock operation succeed.
+ EFI_DEVICE_ERROR Device error, operation failed.
+ EFI_ACCESS_DENIED The interface has already been locked.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SpiProtocolExecute (
+ IN EFI_SPI_PROTOCOL *This,
+ IN UINT8 OpcodeIndex,
+ IN UINT8 PrefixOpcodeIndex,
+ IN BOOLEAN DataCycle,
+ IN BOOLEAN Atomic,
+ IN BOOLEAN ShiftOut,
+ IN UINTN Address,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer,
+ IN SPI_REGION_TYPE SpiRegionType
+ )
+/*++
+
+Routine Description:
+
+ Execute SPI commands from the host controller.
+
+Arguments:
+
+ This Pointer to the EFI_SPI_PROTOCOL instance.
+ OpcodeIndex Index of the command in the OpCode Menu.
+ PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
+ DataCycle TRUE if the SPI cycle contains data
+ Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+ ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+ Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+ Region, this value specifies the offset from the Region Base; for BIOS Region,
+ this value specifies the offset from the start of the BIOS Image. In Non
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+ the flash (in Non Descriptor Mode)
+ DataByteCount Number of bytes in the data portion of the SPI cycle.
+ Buffer Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle.
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+Returns:
+
+ EFI_SUCCESS Command succeed.
+ EFI_INVALID_PARAMETER The parameters specified are not valid.
+ EFI_UNSUPPORTED Command not supported.
+ EFI_DEVICE_ERROR Device error, command aborts abnormally.
+
+--*/
+;
+
+EFI_STATUS
+SendSpiCmd (
+ IN EFI_SPI_PROTOCOL *This,
+ IN UINT8 OpcodeIndex,
+ IN UINT8 PrefixOpcodeIndex,
+ IN BOOLEAN DataCycle,
+ IN BOOLEAN Atomic,
+ IN BOOLEAN ShiftOut,
+ IN UINTN Address,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer,
+ IN SPI_REGION_TYPE SpiRegionType
+ )
+/*++
+
+Routine Description:
+
+ This function sends the programmed SPI command to the slave device.
+
+Arguments:
+
+ OpcodeIndex Index of the command in the OpCode Menu.
+ PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
+ DataCycle TRUE if the SPI cycle contains data
+ Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+ ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+ Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+ Region, this value specifies the offset from the Region Base; for BIOS Region,
+ this value specifies the offset from the start of the BIOS Image. In Non
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+ the flash (in Non Descriptor Mode)
+ DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the
+ data transfer into multiple operations. This function ensures each operation does
+ not cross 256 byte flash address boundary.
+ *NOTE: if there is some SPI chip that has a stricter address boundary requirement
+ (e.g., its write page size is < 256 byte), then the caller cannot rely on this
+ function to cut the data transfer at proper address boundaries, and it's the
+ caller's reponsibility to pass in a properly cut DataByteCount parameter.
+ Buffer Data received or sent during the SPI cycle.
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+Returns:
+
+ EFI_SUCCESS SPI command completes successfully.
+ EFI_DEVICE_ERROR Device error, the command aborts abnormally.
+ EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode
+ EFI_INVALID_PARAMETER The parameters specified are not valid.
+
+--*/
+;
+
+BOOLEAN
+WaitForSpiCycleComplete (
+ IN EFI_SPI_PROTOCOL *This,
+ IN BOOLEAN ErrorCheck
+ )
+/*++
+
+Routine Description:
+
+ Wait execution cycle to complete on the SPI interface. Check both Hardware
+ and Software Sequencing status registers
+
+Arguments:
+
+ This - The SPI protocol instance
+ UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation
+ ErrorCheck - TRUE if the SpiCycle needs to do the error check
+
+Returns:
+
+ TRUE SPI cycle completed on the interface.
+ FALSE Time out while waiting the SPI cycle to complete.
+ It's not safe to program the next command on the SPI interface.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SpiProtocolInfo (
+ IN EFI_SPI_PROTOCOL *This,
+ OUT SPI_INIT_INFO **InitInfoPtr
+ )
+/*++
+
+Routine Description:
+
+ Return info about SPI host controller, to help callers usage of Execute
+ service.
+
+ If 0xff is returned as an opcode index in init info struct
+ then device does not support the operation.
+
+Arguments:
+
+ This Pointer to the EFI_SPI_PROTOCOL instance.
+ InitInfoPtr Pointer to init info written to this memory location.
+
+Returns:
+
+ EFI_SUCCESS Information returned.
+ EFI_INVALID_PARAMETER Invalid parameter.
+ EFI_NOT_READY Required resources not setup.
+ Others Unexpected error happened.
+
+--*/
+;
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf b/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf
new file mode 100644
index 0000000000..0a9beeef2f
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf
@@ -0,0 +1,90 @@
+## @file
+# Component description file for the SPI Runtime 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 Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PchSpiRuntime
+ FILE_GUID = C194C6EA-B68C-4981-B64B-9BD271474B20
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InstallPchSpi
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+################################################################################
+#
+# Sources Section - list of files that are required for the build to succeed.
+#
+################################################################################
+[Sources]
+ RuntimeDxe/PchSpi.h
+ RuntimeDxe/PchSpi.c
+ Common/SpiCommon.c
+ Common/SpiCommon.h
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+[Packages]
+ MdePkg/MdePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+################################################################################
+#
+# Library Class Section - list of Library Classes that are required for
+# this module.
+#
+################################################################################
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiRuntimeLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ IntelQNCLib
+ QNCAccessLib
+ TimerLib
+ DxeServicesTableLib
+ UefiLib
+ DebugLib
+ MemoryAllocationLib
+ S3BootScriptLib
+ PciExpressLib
+
+################################################################################
+#
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names
+# that this module uses or produces.
+#
+################################################################################
+[Protocols]
+ gEfiSpiProtocolGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioSize
+
+[Depex]
+ TRUE
diff --git a/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf b/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf
new file mode 100644
index 0000000000..3fde4fd7a9
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf
@@ -0,0 +1,56 @@
+## @file
+# Spi smm driver
+#
+# Component description file for the SPI SMM 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 = PchSpiSmm
+ FILE_GUID = 27F4917B-A707-4aad-9676-26DF168CBF0D
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = InstallPchSpi
+
+[Sources]
+ Smm/PchSpi.h
+ Smm/PchSpi.c
+ Common/SpiCommon.c
+ Common/SpiCommon.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ IoLib
+ IntelQNCLib
+ QNCAccessLib
+ TimerLib
+ S3BootScriptLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ BaseLib
+ SmmServicesTableLib
+
+[Protocols]
+ gEfiSmmSpiProtocolGuid # PRODUCES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+
+[Depex]
+ gEfiSmmBase2ProtocolGuid
diff --git a/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c b/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c
new file mode 100644
index 0000000000..bf52732b48
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c
@@ -0,0 +1,211 @@
+/** @file
+PCH SPI Runtime Driver implements the 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.
+
+**/
+#include "PchSpi.h"
+
+extern EFI_GUID gEfiEventVirtualAddressChangeGuid;
+
+//
+// Global variables
+//
+SPI_INSTANCE *mSpiInstance;
+CONST UINT32 mSpiRegister[] = {
+ R_QNC_RCRB_SPIS,
+ R_QNC_RCRB_SPIPREOP,
+ R_QNC_RCRB_SPIOPMENU,
+ R_QNC_RCRB_SPIOPMENU + 4
+ };
+
+//
+// Function implementations
+//
+VOID
+PchSpiVirtualddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ Fixup internal data pointers so that the services can be called in virtual mode.
+
+Arguments:
+
+ Event The event registered.
+ Context Event context. Not used in this event handler.
+
+Returns:
+
+ None.
+
+--*/
+{
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->PchRootComplexBar));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Init));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Lock));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Execute));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance));
+}
+
+EFI_STATUS
+EFIAPI
+InstallPchSpi (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ Entry point for the SPI host controller driver.
+
+Arguments:
+
+ ImageHandle Image handle of this driver.
+ SystemTable Global system service table.
+
+Returns:
+
+ EFI_SUCCESS Initialization complete.
+ EFI_UNSUPPORTED The chipset is unsupported by this driver.
+ EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver.
+ EFI_DEVICE_ERROR Device error, driver exits abnormally.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT64 BaseAddress;
+ UINT64 Length;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdMemorySpaceDescriptor;
+ UINT64 Attributes;
+ EFI_EVENT Event;
+
+ DEBUG ((DEBUG_INFO, "InstallPchSpi() Start\n"));
+
+ //
+ // Allocate Runtime memory for the SPI protocol instance.
+ //
+ mSpiInstance = AllocateRuntimeZeroPool (sizeof (SPI_INSTANCE));
+ if (mSpiInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Initialize the SPI protocol instance
+ //
+ Status = SpiProtocolConstructor (mSpiInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Install the EFI_SPI_PROTOCOL interface
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &(mSpiInstance->Handle),
+ &gEfiSpiProtocolGuid,
+ &(mSpiInstance->SpiProtocol),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (mSpiInstance);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set RCBA space in GCD to be RUNTIME so that the range will be supported in
+ // virtual address mode in EFI aware OS runtime.
+ // It will assert if RCBA Memory Space is not allocated
+ // The caller is responsible for the existence and allocation of the RCBA Memory Spaces
+ //
+ BaseAddress = (EFI_PHYSICAL_ADDRESS) (mSpiInstance->PchRootComplexBar);
+ Length = PcdGet64 (PcdRcbaMmioSize);
+
+ Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdMemorySpaceDescriptor);
+ ASSERT_EFI_ERROR (Status);
+
+ Attributes = GcdMemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;
+
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ BaseAddress,
+ Length,
+ EFI_MEMORY_RUNTIME | EFI_MEMORY_UC
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ Status = gDS->SetMemorySpaceAttributes (
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ PchSpiVirtualddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "InstallPchSpi() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+VOID
+EFIAPI
+SpiPhaseInit (
+ VOID
+ )
+/*++
+Routine Description:
+
+ This function is a a hook for Spi Dxe phase specific initialization
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+{
+ UINTN Index;
+
+ //
+ // Disable SMM BIOS write protect if it's not a SMM protocol
+ //
+ MmioAnd8 (
+ PciDeviceMmBase (PCI_BUS_NUMBER_QNC,
+ PCI_DEVICE_NUMBER_QNC_LPC,
+ PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_BIOS_CNTL,
+ (UINT8) (~B_QNC_LPC_BIOS_CNTL_SMM_BWP)
+ );
+
+ //
+ // Save SPI Registers for S3 resume usage
+ //
+ for (Index = 0; Index < sizeof (mSpiRegister) / sizeof (UINT32); Index++) {
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]),
+ 1,
+ (VOID *) (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index])
+ );
+ }
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h b/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h
new file mode 100644
index 0000000000..50dd60ce2b
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h
@@ -0,0 +1,85 @@
+/** @file
+Header file for the PCH SPI Runtime 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 _PCH_SPI_H_
+#define _PCH_SPI_H_
+
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/Spi.h>
+#include "SpiCommon.h"
+#include <Library/PciExpressLib.h>
+#include <IntelQNCRegs.h>
+#include <Library/IntelQNCLib.h>
+#include <Library/QNCAccessLib.h>
+#include <Library/TimerLib.h>
+
+#define EFI_INTERNAL_POINTER 0x00000004
+
+
+//
+// Function prototypes used by the SPI protocol.
+//
+VOID
+PchSpiVirtualddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ Fixup internal data pointers so that the services can be called in virtual mode.
+
+Arguments:
+
+ Event The event registered.
+ Context Event context. Not used in this event handler.
+
+Returns:
+
+ None.
+
+--*/
+;
+
+VOID
+EFIAPI
+SpiPhaseInit (
+ VOID
+ )
+/*++
+Routine Description:
+
+ This function is a hook for Spi Dxe phase specific initialization
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+;
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c b/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c
new file mode 100644
index 0000000000..3b11fdf084
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c
@@ -0,0 +1,129 @@
+/** @file
+
+PCH SPI SMM Driver implements the 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.
+
+
+**/
+#include "PchSpi.h"
+
+SPI_INSTANCE *mSpiInstance;
+
+CONST UINT32 mSpiRegister[] = {
+ R_QNC_RCRB_SPIS,
+ R_QNC_RCRB_SPIPREOP,
+ R_QNC_RCRB_SPIOPMENU,
+ R_QNC_RCRB_SPIOPMENU + 4
+ };
+
+EFI_STATUS
+EFIAPI
+InstallPchSpi (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ Entry point for the SPI host controller driver.
+
+Arguments:
+
+ ImageHandle Image handle of this driver.
+ SystemTable Global system service table.
+
+Returns:
+
+ EFI_SUCCESS Initialization complete.
+ EFI_UNSUPPORTED The chipset is unsupported by this driver.
+ EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver.
+ EFI_DEVICE_ERROR Device error, driver exits abnormally.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ //
+ // Allocate pool for SPI protocol instance
+ //
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData, // MemoryType don't care
+ sizeof (SPI_INSTANCE),
+ (VOID **) &mSpiInstance
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (mSpiInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem ((VOID *) mSpiInstance, sizeof (SPI_INSTANCE));
+ //
+ // Initialize the SPI protocol instance
+ //
+ Status = SpiProtocolConstructor (mSpiInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install the SMM EFI_SPI_PROTOCOL interface
+ //
+ Status = gSmst->SmmInstallProtocolInterface (
+ &(mSpiInstance->Handle),
+ &gEfiSmmSpiProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &(mSpiInstance->SpiProtocol)
+ );
+ if (EFI_ERROR (Status)) {
+ gSmst->SmmFreePool (mSpiInstance);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+EFIAPI
+SpiPhaseInit (
+ VOID
+ )
+/*++
+Routine Description:
+
+ This function is a a hook for Spi Smm phase specific initialization
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+{
+ UINTN Index;
+
+ //
+ // Save SPI Registers for S3 resume usage
+ //
+ for (Index = 0; Index < sizeof (mSpiRegister) / sizeof (UINT32); Index++) {
+ S3BootScriptSaveMemWrite (
+ S3BootScriptWidthUint32,
+ (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]),
+ 1,
+ (VOID *) (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index])
+ );
+ }
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h b/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h
new file mode 100644
index 0000000000..64831ee45e
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h
@@ -0,0 +1,53 @@
+/** @file
+Header file for the PCH SPI SMM 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 _PCH_SPI_H_
+#define _PCH_SPI_H_
+
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Protocol/Spi.h>
+#include "SpiCommon.h"
+#include <Library/SmmServicesTableLib.h>
+#include <IntelQNCRegs.h>
+#include <Library/IntelQNCLib.h>
+#include <Library/QNCAccessLib.h>
+#include <Library/TimerLib.h>
+
+VOID
+EFIAPI
+SpiPhaseInit (
+ VOID
+ )
+/*++
+Routine Description:
+
+ This function is a hook for Spi Smm phase specific initialization
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+;
+#endif
diff --git a/QuarkSocPkg/QuarkSocPkg.dec b/QuarkSocPkg/QuarkSocPkg.dec
new file mode 100644
index 0000000000..ee25d12e44
--- /dev/null
+++ b/QuarkSocPkg/QuarkSocPkg.dec
@@ -0,0 +1,240 @@
+## @file
+# INTEL Quark SoC Module Package Reference Implementations
+#
+# This Module provides FRAMEWORK reference implementation for INTEL 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.
+#
+##
+
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = QuarkSocPkg
+ PACKAGE_GUID = 28DECF17-6C75-448f-87DC-BDE4BD579919
+ PACKAGE_VERSION = 0.1
+
+
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+# Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+# SEC PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER BASE
+#
+################################################################################
+[Includes]
+ #
+ # North Cluster
+ #
+ QuarkNorthCluster/Include
+ QuarkNorthCluster/MemoryInit/Pei
+
+ #
+ # South Cluster
+ #
+ QuarkSouthCluster/Include
+
+################################################################################
+#
+# Library Class Header section - list of Library Class header files that are
+# provided by this package.
+#
+################################################################################
+[LibraryClasses]
+ #
+ # North Cluster
+ #
+ QNCAccessLib|QuarkNorthCluster/Include/Library/QNCAccessLib.h
+ IntelQNCLib|QuarkNorthCluster/Include/Library/IntelQNCLib.h
+ IohLib|QuarkSouthCluster/Include/Library/IohLib.h
+ I2cLib|QuarkSouthCluster/Include/Library/I2cLib.h
+
+################################################################################
+#
+# Global Guid Definition section - list of Global Guid C Name Data Structures
+# that are provided by this package.
+#
+################################################################################
+[Guids]
+ #
+ # North Cluster
+ #
+ gEfiQuarkNcSocIdTokenSpaceGuid = { 0xca452c6a, 0xdf0c, 0x4dc9, { 0x82, 0xfb, 0xea, 0xe2, 0xab, 0x31, 0x29, 0x46 }}
+ gQncS3CodeInLockBoxGuid = { 0x1f18c5b3, 0x29ed, 0x4d9e, {0xa5, 0x4, 0x6d, 0x97, 0x8e, 0x7e, 0xd5, 0x69}}
+ gQncS3ContextInLockBoxGuid = { 0xe5769ea9, 0xe706, 0x454b, {0x95, 0x7f, 0xaf, 0xc6, 0xdb, 0x4b, 0x8a, 0xd}}
+
+ #
+ # South Cluster
+ #
+ gEfiQuarkSCSocIdTokenSpaceGuid = { 0xef251b71, 0xceed, 0x484e, { 0x82, 0xe3, 0x3a, 0x1f, 0x34, 0xf5, 0x12, 0xe2 }}
+
+################################################################################
+#
+# Global Ppi Definition section - list of Global Ppi C Name Data Structures
+# that are provided by this package.
+#
+################################################################################
+[Ppis]
+ #
+ # North Cluster
+ #
+ gQNCMemoryInitPpiGuid = { 0x21ff1fee, 0xd33a, 0x4fce, { 0xa6, 0x5e, 0x95, 0x5e, 0xa3, 0xc4, 0x1f, 0x40}}
+
+################################################################################
+#
+# Global Protocols Definition section - list of Global Protocols C Name Data
+# Structures that are provided by this package.
+#
+################################################################################
+[Protocols]
+ #
+ # North Cluster
+ #
+ gEfiPlatformPolicyProtocolGuid = { 0x2977064F, 0xAB96, 0x4FA9, { 0x85, 0x45, 0xF9, 0xC4, 0x02, 0x51, 0xE0, 0x7F }}
+ gEfiSmmIchnDispatch2ProtocolGuid = { 0xadf3a128, 0x416d, 0x4060, { 0x8d, 0xdf, 0x30, 0xa1, 0xd7, 0xaa, 0xb6, 0x99 }}
+ gEfiSpiProtocolGuid = { 0x1156efc6, 0xea32, 0x4396, { 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 }}
+ gEfiSmmSpiProtocolGuid = { 0xD9072C35, 0xEB8F, 0x43ad, { 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 }}
+ gEfiQncS3SupportProtocolGuid = { 0xe287d20b, 0xd897, 0x4e1e, { 0xa5, 0xd9, 0x97, 0x77, 0x63, 0x93, 0x6a, 0x4 }}
+
+ #
+ # South Cluster
+ #
+ gEfiSDHostIoProtocolGuid = {0xb63f8ec7, 0xa9c9, 0x4472, {0xa4, 0xc0, 0x4d, 0x8b, 0xf3, 0x65, 0xcc, 0x51}}
+
+################################################################################
+#
+# PCD Declarations section - list of all PCDs Declared by this Package
+# Only this package should be providing the
+# declaration, other packages should not.
+#
+################################################################################
+
+[PcdsFeatureFlag]
+ #
+ # North Cluster
+ #
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed|TRUE|BOOLEAN|0x10000001
+
+ #
+ # South Cluster
+ #
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdEhciRecoveryEnabled|FALSE|BOOLEAN|0x10000003
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdI2CFastModeEnabled|FALSE|BOOLEAN|0x10000005
+
+ #
+ # Feature Flag equivalent to linux SDHCI_QUIRK_NO_HISPD_BIT to stop
+ # setting of SD HCI hi_spd_en bit in HOST_CTL register.
+ #
+ # Alway TRUE ie high speed enable bit must never
+ # be set so we stay within SD interface Setup/Hold time.
+ #
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdSdHciQuirkNoHiSpd|TRUE|BOOLEAN|0x10000004
+
+[PcdsFixedAtBuild]
+ #
+ # North Cluster
+ #
+
+ # Values of Io Port Base Address, MMIO base address and space size.
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress|0x1000|UINT16|0x10000200
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoBaseAddress|0x1010|UINT16|0x10000201
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoLVL2|0x1014|UINT16|0x10000202
+
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress|0x1080|UINT16|0x10000205
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress|0x1100|UINT16|0x10000206
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress|0x1040|UINT16|0x10000207
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdWdtbaIoBaseAddress|0x1140|UINT16|0x10000209
+
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioBaseAddress|0xFED1C000|UINT64|0x1000020B
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicBaseAddress|0xFEC00000|UINT64|0x1000020C
+
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicSize|0x1000|UINT64|0x1000020D
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioSize|0x4000|UINT64|0x1000020E
+
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciExpressSize|0x02000000|UINT64|0x1000020F
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetBaseAddress|0xFED00000|UINT64|0x10000210
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetSize|0x400|UINT64|0x10000211
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdTSegSize|0x200000|UINT32|0x10000212
+
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeIoBase|0x2000|UINT16|0x10000214
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeIoSize|0xE000|UINT16|0x10000215
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory32Base|0x90000000|UINT32|0x1000021B
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory32Size|0x20000000|UINT32|0x1000021C
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory64Base|0xB0000000|UINT64|0x1000021D
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory64Size|0x30000000|UINT64|0x1000021E
+
+ # Values for programming Interrupt Route Configuration Registers:
+ # Indicates which interrupt routing is connected to the INTA/B/C/D pins reported in the
+ # "DxIP" register fields. This will be the internal routing, the device interrupt is connected
+ # to the interrupt controller.
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent0IR|0x0000|UINT16|0x10000223
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent1IR|0x7654|UINT16|0x10000224
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent2IR|0x0000|UINT16|0x10000225
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent3IR|0x3210|UINT16|0x10000226
+
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort|0xb2|UINT16|0x10000232
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort|0xb3|UINT16|0x10000233
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationData|0x55|UINT8|0x10000234
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrNum|0x0|UINT32|0x10000235
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrTable|0x0|UINT64|0x10000236
+
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdESramMemorySize|0x00080000|UINT32|0x10000240
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables|0x03|UINT32|0x10000237
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPcieRootPortConfiguration|{0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00}|VOID*|0x10000239
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkMicrocodeFile |{ 0x8B, 0xEA, 0x5E, 0xD7, 0xD2, 0x23, 0xD4, 0x4E, 0xBC, 0x4F, 0x57, 0x51, 0xD4, 0xA1, 0x8D, 0xCF }|VOID*|0x1000023A
+
+ #
+ # South Cluster
+ #
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohI2cMmioBase|0xA001F000|UINT64|0x20000005
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiP2PMemoryBaseAddress|0xA0000000|UINT32|0x20000006
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiQNCUsbControllerMemoryBaseAddress|0xA0010000|UINT32|0x20000007
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioMmioBase|0xA0020000|UINT64|0x20000008
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohMac0MmioBase|0xA0024000|UINT64|0x20000009
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohMac1MmioBase|0xA0028000|UINT64|0x2000000A
+
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartBusNumber|0x00|UINT8|0x20000013
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartDevNumber|0x14|UINT8|0x20000014
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartFunctionNumber|0x5|UINT8|0x20000001
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber|0x00|UINT8|0x20000029
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioDevNumber|0x15|UINT8|0x2000002A
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioFunctionNumber|0x2|UINT8|0x2000002B
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBarRegister|0x14|UINT8|0x2000002D
+
+[PcdsDynamic, PcdsDynamicEx]
+ #
+ # North Cluster
+ #
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxAddress|0|UINT64|0x30000026
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxSize|0|UINT64|0x30000027
+
+ ## Intel(R) Quark(TM) Soc X1000 processor MRC Parameters. Default is for Galileo Gen 2 platform.<BR><BR>
+ # @Prompt Intel(R) Quark(TM) Soc X1000 processor MRC Parameters.
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdMrcParameters|{0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x7c, 0x92, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x40, 0x9c, 0x00, 0x00, 0x06}|VOID*|0x40000001
+
+ #
+ # South Cluster
+ #
+ ## MAC0 address for the Ethernet Controller in Intel(R) Quark(TM) Soc X1000 processor. Default is 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff.<BR><BR>
+ # @Prompt Ethernet MAC 0 Address.
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohEthernetMac0|{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}|VOID*|0x50000001
+
+ ## MAC1 address for the Ethernet Controller in Intel(R) Quark(TM) Soc X1000 processor. Default is 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff.<BR><BR>
+ # @Prompt Ethernet MAC 1 Address.
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohEthernetMac1|{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}|VOID*|0x50000002
diff --git a/QuarkSocPkg/QuarkSocPkg.dsc b/QuarkSocPkg/QuarkSocPkg.dsc
new file mode 100644
index 0000000000..3c8dfca2b2
--- /dev/null
+++ b/QuarkSocPkg/QuarkSocPkg.dsc
@@ -0,0 +1,259 @@
+## @file
+# INTEL Quark SoC Module Package Reference Implementations
+#
+# This DSC file is used for Package Level build.
+#
+# This Module provides FRAMEWORK reference implementation for INTEL Quark SoC.
+# Copyright (c) 2013-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]
+ PLATFORM_NAME = QuarkSocPkg
+ PLATFORM_GUID = 5F9864F4-EAFB-4ded-A41A-CA501EE50502
+ PLATFORM_VERSION = 0.1
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/QuarkSocPkg
+ SUPPORTED_ARCHITECTURES = IA32|X64
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+
+################################################################################
+#
+# SKU Identification section - list of all SKU IDs supported by this
+# Platform.
+#
+################################################################################
+[SkuIds]
+ 0|DEFAULT # The entry: 0|DEFAULT is reserved and always required.
+
+################################################################################
+#
+# Library Class section - list of all Library Classes needed by this Platform.
+#
+################################################################################
+[LibraryClasses]
+ #
+ # Entry point
+ #
+ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ #
+ # Basic
+ #
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+ PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
+ PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf
+ CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+!if $(CFG_SOURCE_DEBUG) == 1
+ PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
+!else
+ PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
+!endif
+ #
+ # UEFI & PI
+ #
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
+ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
+ UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
+ #
+ # Framework
+ #
+ S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
+ S3IoLib|MdePkg/Library/BaseS3IoLib/BaseS3IoLib.inf
+ S3PciLib|MdePkg/Library/BaseS3PciLib/BaseS3PciLib.inf
+ #
+ # Generic Modules
+ #
+ OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
+
+ #
+ # CPU
+ #
+ MtrrLib|QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf
+ #
+ # Quark North Cluster
+ #
+ SmmLib|QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf
+ SmbusLib|QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf
+ TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
+ ResetSystemLib|QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf
+ IntelQNCLib|QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf
+ QNCAccessLib|QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf
+ #
+ # Quark South Cluster
+ #
+ IohLib|QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf
+ SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
+ PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
+ #
+ # Misc
+ #
+ DebugLib|IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+!if $(CFG_SOURCE_DEBUG) == TRUE
+ DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf
+!else
+ DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+!endif
+
+[LibraryClasses.IA32.PEIM,LibraryClasses.IA32.PEI_CORE]
+ #
+ # SEC and PEI phase common
+ #
+ PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+ ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
+ PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
+!if $(CFG_SOURCE_DEBUG) == TRUE
+ DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf
+!endif
+ TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
+
+[LibraryClasses.IA32.SEC]
+ #
+ # SEC specific phase
+ #
+ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
+
+[LibraryClasses.IA32]
+ #
+ # DXE phase common
+ #
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
+!if $(CFG_SOURCE_DEBUG) == 1
+ DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf
+!endif
+
+[LibraryClasses.IA32.DXE_SMM_DRIVER]
+ SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf
+ ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
+ MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
+!if $(CFG_SOURCE_DEBUG) == TRUE
+ DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf
+!endif
+
+[LibraryClasses.IA32.SMM_CORE]
+ ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
+
+[LibraryClasses.IA32.DXE_RUNTIME_DRIVER]
+ ReportStatusCodeLib|MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
+
+[LibraryClasses.IA32.UEFI_DRIVER,LibraryClasses.IA32.UEFI_APPLICATION]
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+
+[PcdsFixedAtBuild]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl|0x03
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl|0x07
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable|FALSE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|44236800
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0x14, 0x05, 0x84, 0x00, 0xFF}
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride|4
+
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber |0
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber |31
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber |0
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset|0x4b
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask |0x80
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset |0x48
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress |0x1000
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset |0x0008
+
+[PcdsFeatureFlag]
+
+################################################################################
+#
+# Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+
+[PcdsDynamicDefault.common.DEFAULT]
+
+###################################################################################################
+#
+# Components Section - list of the modules and components that will be processed by compilation
+# tools and the EDK II tools to generate PE32/PE32+/Coff image files.
+#
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
+# into firmware volume images. This section is just a list of modules to compile from
+# source into UEFI-compliant binaries.
+# It is the FDF file that contains information on combining binary files into firmware
+# volume images, whose concept is beyond UEFI and is described in PI specification.
+# Binary modules do not need to be listed in this section, as they should be
+# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
+# Logo (Logo.bmp), and etc.
+# There may also be modules listed in this section that are not required in the FDF file,
+# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
+# generated for it, but the binary will not be put into any firmware volume.
+#
+###################################################################################################
+
+[Components]
+ QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf
+ QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf
+ QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf
+ QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf
+ QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf
+ QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf {
+ <LibraryClasses>
+ PciExpressLib|MdePkg/Library/DxeRuntimePciExpressLib/DxeRuntimePciExpressLib.inf
+ }
+ QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf
+ QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf {
+ <LibraryClasses>
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ }
+ QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf
+ QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf
+
+ QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf
+ QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf
+ QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf
+ QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf
+ QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf
+ QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h b/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h
new file mode 100644
index 0000000000..741e7ddb09
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h
@@ -0,0 +1,120 @@
+/** @file
+
+Header file for chipset CE-AT spec.
+
+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 _CE_ATA_H
+#define _CE_ATA_H
+
+#pragma pack(1)
+
+
+#define DATA_UNIT_SIZE 512
+
+
+#define CMD60 60
+#define CMD61 61
+
+
+#define RW_MULTIPLE_REGISTER CMD60
+#define RW_MULTIPLE_BLOCK CMD61
+
+
+#define CE_ATA_SIG_CE 0xCE
+#define CE_ATA_SIG_AA 0xAA
+
+
+#define Reg_Features_Exp 01
+#define Reg_SectorCount_Exp 02
+#define Reg_LBALow_Exp 03
+#define Reg_LBAMid_Exp 04
+#define Reg_LBAHigh_Exp 05
+#define Reg_Control 06
+#define Reg_Features_Error 09
+#define Reg_SectorCount 10
+#define Reg_LBALow 11
+#define Reg_LBAMid 12
+#define Reg_LBAHigh 13
+#define Reg_Device_Head 14
+#define Reg_Command_Status 15
+
+#define Reg_scrTempC 0x80
+#define Reg_scrTempMaxP 0x84
+#define Reg_scrTempMinP 0x88
+#define Reg_scrStatus 0x8C
+#define Reg_scrReallocsA 0x90
+#define Reg_scrERetractsA 0x94
+#define Reg_scrCapabilities 0x98
+#define Reg_scrControl 0xC0
+
+
+
+typedef struct {
+ UINT8 Reserved0;
+ UINT8 Features_Exp;
+ UINT8 SectorCount_Exp;
+ UINT8 LBALow_Exp;
+ UINT8 LBAMid_Exp;
+ UINT8 LBAHigh_Exp;
+ UINT8 Control;
+ UINT8 Reserved1[2];
+ UINT8 Features_Error;
+ UINT8 SectorCount;
+ UINT8 LBALow;
+ UINT8 LBAMid;
+ UINT8 LBAHigh;
+ UINT8 Device_Head;
+ UINT8 Command_Status;
+}TASK_FILE;
+
+
+//
+//Reduced ATA command set
+//
+#define IDENTIFY_DEVICE 0xEC
+#define READ_DMA_EXT 0x25
+#define WRITE_DMA_EXT 0x35
+#define STANDBY_IMMEDIATE 0xE0
+#define FLUSH_CACHE_EXT 0xEA
+
+
+
+typedef struct {
+ UINT16 Reserved0[10];
+ UINT16 SerialNumber[10];
+ UINT16 Reserved1[3];
+ UINT16 FirmwareRevision[4];
+ UINT16 ModelNumber[20];
+ UINT16 Reserved2[33];
+ UINT16 MajorVersion;
+ UINT16 Reserved3[19];
+ UINT16 MaximumLBA[4];
+ UINT16 Reserved4[2];
+ UINT16 Sectorsize;
+ UINT16 Reserved5;
+ UINT16 DeviceGUID[4];
+ UINT16 Reserved6[94];
+ UINT16 Features;
+ UINT16 MaxWritesPerAddress;
+ UINT16 Reserved7[47];
+ UINT16 IntegrityWord;
+}IDENTIFY_DEVICE_DATA;
+
+
+
+
+
+#pragma pack()
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h b/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h
new file mode 100644
index 0000000000..eb0766fa69
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h
@@ -0,0 +1,101 @@
+/** @file
+Include file for I2C DXE Driver register definitions (PCIe config. space and memory space).
+
+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 _I2C_REGS_H_
+#define _I2C_REGS_H_
+
+
+//----------------------------------------------------------------------------
+/// I2C Device Address
+//----------------------------------------------------------------------------
+typedef struct {
+ ///
+ /// The I2C hardware address to which the I2C device is preassigned or allocated.
+ ///
+ UINTN I2CDeviceAddress : 10;
+} EFI_I2C_DEVICE_ADDRESS;
+
+//----------------------------------------------------------------------------
+/// I2C Addressing Mode (7-bit or 10 bit)
+//----------------------------------------------------------------------------
+typedef enum _EFI_I2C_ADDR_MODE {
+ EfiI2CSevenBitAddrMode,
+ EfiI2CTenBitAddrMode,
+} EFI_I2C_ADDR_MODE;
+
+
+//----------------------------------------------------------------------------
+// I2C Controller B:D:F
+//----------------------------------------------------------------------------
+#define I2C_Bus 0x00
+#define I2C_Device 0x15
+#define I2C_Func 0x02
+
+//----------------------------------------------------------------------------
+// Memory Mapped Registers
+//----------------------------------------------------------------------------
+#define I2C_REG_CON 0x00 // Control Register
+#define B_I2C_REG_CON_SPEED (BIT2+BIT1) // standard mode (01) or fast mode (10)
+#define B_I2C_REG_CON_10BITADD_MASTER (BIT4) // 7-bit addressing (0) or 10-bit addressing (1)
+#define I2C_REG_TAR 0x04 // Master Target Address Register
+#define B_I2C_REG_TAR (BIT9+BIT8+BIT7+BIT6+BIT5+BIT4+BIT3+BIT2+BIT1+BIT0) // Master Target Address bits
+#define I2C_REG_DATA_CMD 0x10 // Data Buffer and Command Register
+#define B_I2C_REG_DATA_CMD_RW (BIT8) // Data Buffer and Command Register Read/Write bit
+#define B_I2C_REG_DATA_CMD_STOP (BIT9) // Data Buffer and Command Register STOP bit
+#define B_I2C_REG_DATA_CMD_RESTART (BIT10) // Data Buffer and Command Register RESTART bit
+#define I2C_REG_SS_SCL_HCNT 0x14 // Standard Speed Clock SCL High Count Register
+#define I2C_REG_SS_SCL_LCNT 0x18 // Standard Speed Clock SCL Low Count Register
+#define I2C_REG_FS_SCL_HCNT 0x1C // Fast Speed Clock SCL High Count Register
+#define I2C_REG_FS_SCL_LCNT 0x20 // Fast Speed Clock SCL Low Count Register
+#define I2C_REG_INTR_STAT 0x2C // Interrupt Status Register
+#define B_I2C_REG_INTR_STAT_STOP_DET (BIT9) // Interrupt Status Register STOP_DET signal status
+#define I2C_REG_INTR_MASK 0x30 // Interrupt Status Mask Register
+#define I2C_REG_RAW_INTR_STAT 0x34 // Raw Interrupt Status Register
+#define I2C_REG_RAW_INTR_STAT_STOP_DET (BIT9) // Raw Interrupt Status Register STOP_DET signal status.
+#define I2C_REG_RAW_INTR_STAT_TX_ABRT (BIT6) // Raw Interrupt Status Register TX Abort status.
+#define I2C_REG_RAW_INTR_STAT_TX_OVER (BIT3) // Raw Interrupt Status Register TX Overflow signal status.
+#define I2C_REG_RAW_INTR_STAT_RX_OVER (BIT1) // Raw Interrupt Status Register RX Overflow signal status.
+#define I2C_REG_RAW_INTR_STAT_RX_UNDER (BIT0) // Raw Interrupt Status Register RX Underflow signal status.
+#define I2C_REG_RX_TL 0x38 // Receive FIFO Threshold Level Register
+#define I2C_REG_TX_TL 0x3C // Transmit FIFO Threshold Level Register
+#define I2C_REG_CLR_INT 0x40 // Clear Combined and Individual Interrupt Register
+#define I2C_REG_CLR_RX_UNDER 0x44 // Clear RX Under Interrupt Register
+#define I2C_REG_CLR_RX_OVER 0x48 // Clear RX Over Interrupt Register
+#define I2C_REG_CLR_TX_OVER 0x4C // Clear TX Over Interrupt Register
+#define I2C_REG_CLR_RD_REQ 0x50 // Clear RD REQ Interrupt Register
+#define I2C_REG_CLR_TX_ABRT 0x54 // Clear TX ABRT Interrupt Register
+#define I2C_REG_CLR_ACTIVITY 0x5C // Clear Activity Interrupt Register
+#define I2C_REG_CLR_STOP_DET 0x60 // Clear STOP DET Interrupt Register
+#define B_I2C_REG_CLR_STOP_DET (BIT0) // Clear STOP DET Interrupt Register
+#define I2C_REG_CLR_START_DET 0x64 // Clear START DET Interrupt Register
+#define B_I2C_REG_CLR_START_DET (BIT0) // Clear START DET Interrupt Register
+#define I2C_REG_ENABLE 0x6C // Enable Register
+#define B_I2C_REG_ENABLE (BIT0) // Enable (1) or disable (0) I2C Controller
+#define I2C_REG_STATUS 0x70 // Status Register
+#define I2C_REG_TXFLR 0x74 // Transmit FIFO Level Register
+#define B_I2C_REG_TXFLR (BIT3+BIT2+BIT1+BIT0) // Transmit FIFO Level Register bits
+#define I2C_REG_RXFLR 0x78 // Receive FIFO Level Register
+#define B_I2C_REG_RXFLR (BIT3+BIT2+BIT1+BIT0) // Receive FIFO Level Register bits
+#define I2C_REG_SDA_HOLD 0x7C // SDA HOLD Register
+#define I2C_REG_TX_ABRT_SOURCE 0x80 // Transmit Abort Source Register
+#define I2C_REG_ENABLE_STATUS 0x9C // Enable Status Register
+#define I2C_REG_FS_SPKLEN 0xA0 // SS and FS Spike Suppression Limit Register
+
+//
+// Features.
+//
+#define I2C_FIFO_SIZE 16
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h b/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h
new file mode 100644
index 0000000000..3ac2a45f39
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h
@@ -0,0 +1,254 @@
+/** @file
+Header file for QuarkSCSocId Ioh.
+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 _IOH_H_
+#define _IOH_H_
+
+#ifndef BIT0
+#define BIT0 0x01
+#define BIT1 0x02
+#define BIT2 0x04
+#define BIT3 0x08
+#define BIT4 0x10
+#define BIT5 0x20
+#define BIT6 0x40
+#define BIT7 0x80
+#define BIT8 0x100
+#define BIT9 0x200
+#define BIT00 0x00000001
+#define BIT01 0x00000002
+#define BIT02 0x00000004
+#define BIT03 0x00000008
+#define BIT04 0x00000010
+#define BIT05 0x00000020
+#define BIT06 0x00000040
+#define BIT07 0x00000080
+#define BIT08 0x00000100
+#define BIT09 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+#endif
+
+#define IOH_PCI_CFG_ADDRESS(bus,dev,func,reg) \
+ ((UINT32) ( (((UINTN)bus) << 24) + (((UINTN)dev) << 16) + \
+ (((UINTN)func) << 8) + ((UINTN)reg) ))& 0x00000000ffffffff
+
+//----------------------------------------------------------------------------
+
+#define INTEL_VENDOR_ID 0x8086 // Intel Vendor ID
+
+//----------------------------------------------------------------------------
+// Pci Configuration Map Register Offsets
+//----------------------------------------------------------------------------
+#define PCI_REG_VID 0x00 // Vendor ID Register
+#define PCI_REG_DID 0x02 // Device ID Register
+#define PCI_REG_PCICMD 0x04 // PCI Command Register
+#define PCI_REG_PCISTS 0x06 // PCI Status Register
+#define PCI_REG_RID 0x08 // PCI Revision ID Register
+#define PCI_REG_PI 0x09 // Programming Interface
+#define PCI_REG_SCC 0x0a // Sub Class Code Register
+#define PCI_REG_BCC 0x0b // Base Class Code Register
+#define PCI_REG_PMLT 0x0d // Primary Master Latnecy Timer
+#define PCI_REG_HDR 0x0e // Header Type Register
+#define PCI_REG_PBUS 0x18 // Primary Bus Number Register
+#define PCI_REG_SBUS 0x19 // Secondary Bus Number Register
+#define PCI_REG_SUBUS 0x1a // Subordinate Bus Number Register
+#define PCI_REG_SMLT 0x1b // Secondary Master Latnecy Timer
+#define PCI_REG_IOBASE 0x1c // I/O base Register
+#define PCI_REG_IOLIMIT 0x1d // I/O Limit Register
+#define PCI_REG_SECSTATUS 0x1e // Secondary Status Register
+#define PCI_REG_MEMBASE 0x20 // Memory Base Register
+#define PCI_REG_MEMLIMIT 0x22 // Memory Limit Register
+#define PCI_REG_PRE_MEMBASE 0x24 // Prefretchable memory Base register
+#define PCI_REG_PRE_MEMLIMIT 0x26 // Prefretchable memory Limit register
+#define PCI_REG_SVID0 0x2c // Subsystem Vendor ID low byte
+#define PCI_REG_SVID1 0x2d // Subsystem Vendor ID high byte
+#define PCI_REG_SID0 0x2e // Subsystem ID low byte
+#define PCI_REG_SID1 0x2f // Subsystem ID high byte
+#define PCI_REG_IOBASE_U 0x30 // I/O base Upper Register
+#define PCI_REG_IOLIMIT_U 0x32 // I/O Limit Upper Register
+#define PCI_REG_INTLINE 0x3c // Interrupt Line Register
+#define PCI_REG_BRIDGE_CNTL 0x3e // Bridge Control Register
+
+//---------------------------------------------------------------------------
+// QuarkSCSocId Packet Hub definitions
+//---------------------------------------------------------------------------
+
+#define PCIE_BRIDGE_VID_DID 0x88008086
+
+//---------------------------------------------------------------------------
+// Quark South Cluster definitions.
+//---------------------------------------------------------------------------
+
+#define IOH_BUS 0
+#define IOH_PCI_IOSF2AHB_0_DEV_NUM 0x14
+#define IOH_PCI_IOSF2AHB_0_MAX_FUNCS 7
+#define IOH_PCI_IOSF2AHB_1_DEV_NUM 0x15
+#define IOH_PCI_IOSF2AHB_1_MAX_FUNCS 3
+
+//---------------------------------------------------------------------------
+// Quark South Cluster USB definitions.
+//---------------------------------------------------------------------------
+
+#define IOH_USB_BUS_NUMBER IOH_BUS
+#define IOH_USB_CONTROLLER_MMIO_RANGE 0x1000
+#define IOH_MAX_OHCI_USB_CONTROLLERS 1
+#define IOH_MAX_EHCI_USB_CONTROLLERS 1
+#define IOH_MAX_USBDEVICE_USB_CONTROLLERS 1
+
+#define R_IOH_USB_VENDOR_ID 0x00
+#define V_IOH_USB_VENDOR_ID INTEL_VENDOR_ID
+#define R_IOH_USB_DEVICE_ID 0x02
+#define R_IOH_USB_COMMAND 0x04
+#define B_IOH_USB_COMMAND_BME BIT2
+#define B_IOH_USB_COMMAND_MSE BIT1
+#define B_IOH_USB_COMMAND_ISE BIT0
+#define R_IOH_USB_MEMBAR 0x10
+#define B_IOH_USB_MEMBAR_ADDRESS_MASK 0xFFFFF000 // [31:12].
+#define R_IOH_USB_OHCI_HCCABAR 0x18
+
+//---------------------------------------------------------------------------
+// Quark South Cluster OHCI definitions
+//---------------------------------------------------------------------------
+#define IOH_USB_OHCI_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_OHCI_FUNCTION_NUMBER 0x04
+
+//---------------------------------------------------------------------------
+// Quark South Cluster EHCI definitions
+//---------------------------------------------------------------------------
+#define IOH_USB_EHCI_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_EHCI_FUNCTION_NUMBER 0x03
+
+//
+// EHCI memory mapped registers offset from memory BAR0.
+//
+#define R_IOH_EHCI_CAPLENGTH 0x00
+#define R_IOH_EHCI_INSNREG01 0x94
+#define B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP (16)
+#define B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_MASK (0xff << B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP)
+#define B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP (0)
+#define B_IOH_EHCI_INSNREG01_IN_THRESHOLD_MASK (0xff << B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP)
+
+//
+// EHCI memory mapped registers offset from memory BAR0 + Cap length value.
+//
+#define R_IOH_EHCI_CONFIGFLAGS 0x40
+
+//---------------------------------------------------------------------------
+// Quark South Cluster USB Device definitions
+//---------------------------------------------------------------------------
+#define IOH_USBDEVICE_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_USBDEVICE_FUNCTION_NUMBER 0x02
+
+//
+// USB Device memory mapped registers offset from memory BAR0.
+//
+#define R_IOH_USBDEVICE_D_INTR_UDC_REG 0x40c
+#define R_IOH_USBDEVICE_D_INTR_MSK_UDC_REG 0x410
+#define B_IOH_USBDEVICE_D_INTR_MSK_UDC_REG_MASK1_MASK 0xff
+#define R_IOH_USBDEVICE_EP_INTR_UDC_REG 0x414
+#define R_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG 0x418
+#define B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_OUT_EP_MASK 0x000f0000
+#define B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_IN_EP_MASK 0x0000000f
+
+//---------------------------------------------------------------------------
+// Quark South Cluster 10/100 Mbps Ethernet Device definitions.
+//---------------------------------------------------------------------------
+#define IOH_MAC0_BUS_NUMBER IOH_BUS
+#define IOH_MAC0_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_MAC0_FUNCTION_NUMBER 0x06
+#define IOH_MAC1_BUS_NUMBER IOH_BUS
+#define IOH_MAC1_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM
+#define IOH_MAC1_FUNCTION_NUMBER 0x07
+
+//
+// MAC Device PCI config registers.
+//
+#define R_IOH_MAC_DEVICE_ID 0x02
+#define V_IOH_MAC_VENDOR_ID INTEL_VENDOR_ID
+#define R_IOH_MAC_DEVICE_ID 0x02
+#define V_IOH_MAC_DEVICE_ID 0x0937
+#define R_IOH_MAC_COMMAND 0x04
+#define B_IOH_MAC_COMMAND_BME BIT2
+#define B_IOH_MAC_COMMAND_MSE BIT1
+#define B_IOH_MAC_COMMAND_ISE BIT0
+#define R_IOH_MAC_MEMBAR 0x10
+#define B_IOH_MAC_MEMBAR_ADDRESS_MASK 0xFFFFF000
+
+//
+// LAN Device memory mapped registers offset from memory BAR0.
+//
+#define R_IOH_MAC_GMAC_REG_8 0x20
+#define B_IOH_MAC_USERVER_MASK 0x0000FF00
+#define B_IOH_MAC_SNPSVER_MASK 0x000000FF
+#define R_IOH_MAC_GMAC_REG_16 0x40
+#define B_IOH_MAC_ADDRHI_MASK 0x0000FFFF
+#define B_IOH_MAC_AE BIT31
+#define R_IOH_MAC_GMAC_REG_17 0x44
+#define B_IOH_MAC_ADDRLO_MASK 0xFFFFFFFF
+
+//---------------------------------------------------------------------------
+// Quark I2C / GPIO definitions
+//---------------------------------------------------------------------------
+
+#define V_IOH_I2C_GPIO_VENDOR_ID INTEL_VENDOR_ID
+#define V_IOH_I2C_GPIO_DEVICE_ID 0x0934
+
+#define R_IOH_I2C_MEMBAR 0x10
+#define B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK 0xFFFFF000 // [31:12].
+
+#define GPIO_SWPORTA_DR 0x00
+#define GPIO_SWPORTA_DDR 0x04
+#define GPIO_INTEN 0x30
+#define GPIO_INTMASK 0x34
+#define GPIO_INTTYPE_LEVEL 0x38
+#define GPIO_INT_POLARITY 0x3C
+#define GPIO_INTSTATUS 0x40
+#define GPIO_RAW_INTSTATUS 0x44
+#define GPIO_DEBOUNCE 0x48
+#define GPIO_PORTA_EOI 0x4C
+#define GPIO_EXT_PORTA 0x50
+#define GPIO_EXT_PORTB 0x54
+#define GPIO_LS_SYNC 0x60
+#define GPIO_CONFIG_REG2 0x70
+#define GPIO_CONFIG_REG1 0x74
+
+//---------------------------------------------------------------------------
+// Quark South Cluster UART definitions.
+//---------------------------------------------------------------------------
+
+#define R_IOH_UART_MEMBAR 0x10
+#define B_IOH_UART_MEMBAR_ADDRESS_MASK 0xFFFFF000 // [31:12].
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h b/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h
new file mode 100644
index 0000000000..7b462af199
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h
@@ -0,0 +1,24 @@
+/** @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 _IOH_ACCESS_H_
+#define _IOH_ACCESS_H_
+
+#include "Ioh.h"
+#include "IohCommonDefinitions.h"
+
+#endif
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h b/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h
new file mode 100644
index 0000000000..8a359b4f38
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h
@@ -0,0 +1,348 @@
+/** @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 _IOH_COMMON_DEFINITIONS_H_
+#define _IOH_COMMON_DEFINITIONS_H_
+
+//
+// PCI CONFIGURATION MAP REGISTER OFFSETS
+//
+#ifndef PCI_VID
+#define PCI_VID 0x0000 // Vendor ID Register
+#define PCI_DID 0x0002 // Device ID Register
+#define PCI_CMD 0x0004 // PCI Command Register
+#define PCI_STS 0x0006 // PCI Status Register
+#define PCI_RID 0x0008 // Revision ID Register
+#define PCI_IFT 0x0009 // Interface Type
+#define PCI_SCC 0x000A // Sub Class Code Register
+#define PCI_BCC 0x000B // Base Class Code Register
+#define PCI_CLS 0x000C // Cache Line Size
+#define PCI_PMLT 0x000D // Primary Master Latency Timer
+#define PCI_HDR 0x000E // Header Type Register
+#define PCI_BIST 0x000F // Built in Self Test Register
+#define PCI_BAR0 0x0010 // Base Address Register 0
+#define PCI_BAR1 0x0014 // Base Address Register 1
+#define PCI_BAR2 0x0018 // Base Address Register 2
+#define PCI_PBUS 0x0018 // Primary Bus Number Register
+#define PCI_SBUS 0x0019 // Secondary Bus Number Register
+#define PCI_SUBUS 0x001A // Subordinate Bus Number Register
+#define PCI_SMLT 0x001B // Secondary Master Latency Timer
+#define PCI_BAR3 0x001C // Base Address Register 3
+#define PCI_IOBASE 0x001C // I/O base Register
+#define PCI_IOLIMIT 0x001D // I/O Limit Register
+#define PCI_SECSTATUS 0x001E // Secondary Status Register
+#define PCI_BAR4 0x0020 // Base Address Register 4
+#define PCI_MEMBASE 0x0020 // Memory Base Register
+#define PCI_MEMLIMIT 0x0022 // Memory Limit Register
+#define PCI_BAR5 0x0024 // Base Address Register 5
+#define PCI_PRE_MEMBASE 0x0024 // Prefetchable memory Base register
+#define PCI_PRE_MEMLIMIT 0x0026 // Prefetchable memory Limit register
+#define PCI_PRE_MEMBASE_U 0x0028 // Prefetchable memory base upper 32 bits
+#define PCI_PRE_MEMLIMIT_U 0x002C // Prefetchable memory limit upper 32 bits
+#define PCI_SVID 0x002C // Subsystem Vendor ID
+#define PCI_SID 0x002E // Subsystem ID
+#define PCI_IOBASE_U 0x0030 // I/O base Upper Register
+#define PCI_IOLIMIT_U 0x0032 // I/O Limit Upper Register
+#define PCI_CAPP 0x0034 // Capabilities Pointer
+#define PCI_EROM 0x0038 // Expansion ROM Base Address
+#define PCI_INTLINE 0x003C // Interrupt Line Register
+#define PCI_INTPIN 0x003D // Interrupt Pin Register
+#define PCI_MAXGNT 0x003E // Max Grant Register
+#define PCI_BRIDGE_CNTL 0x003E // Bridge Control Register
+#define PCI_MAXLAT 0x003F // Max Latency Register
+#endif
+//
+// Bit Difinitions
+//
+#ifndef BIT0
+#define BIT0 0x0001
+#define BIT1 0x0002
+#define BIT2 0x0004
+#define BIT3 0x0008
+#define BIT4 0x0010
+#define BIT5 0x0020
+#define BIT6 0x0040
+#define BIT7 0x0080
+#define BIT8 0x0100
+#define BIT9 0x0200
+#define BIT10 0x0400
+#define BIT11 0x0800
+#define BIT12 0x1000
+#define BIT13 0x2000
+#define BIT14 0x4000
+#define BIT15 0x8000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+#endif
+
+
+//
+// Common Memory mapped Io access macros ------------------------------------------
+//
+#define IohMmioAddress( BaseAddr, Register ) \
+ ( (UINTN)BaseAddr + \
+ (UINTN)(Register) \
+ )
+
+//
+// UINT64
+//
+#define IohMmio64Ptr( BaseAddr, Register ) \
+ ( (volatile UINT64 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio64( BaseAddr, Register ) \
+ *IohMmio64Ptr( BaseAddr, Register )
+
+#define IohMmio64Or( BaseAddr, Register, OrData ) \
+ IohMmio64( BaseAddr, Register ) = \
+ (UINT64) ( \
+ IohMmio64( BaseAddr, Register ) | \
+ (UINT64)(OrData) \
+ )
+
+#define IohMmio64And( BaseAddr, Register, AndData ) \
+ IohMmio64( BaseAddr, Register ) = \
+ (UINT64) ( \
+ IohMmio64( BaseAddr, Register ) & \
+ (UINT64)(AndData) \
+ )
+
+#define IohMmio64AndThenOr( BaseAddr, Register, AndData, OrData ) \
+ IohMmio64( BaseAddr, Register ) = \
+ (UINT64) ( \
+ ( IohMmio64( BaseAddr, Register ) & \
+ (UINT64)(AndData) \
+ ) | \
+ (UINT64)(OrData) \
+ )
+
+//
+// UINT32
+//
+#define IohMmio32Ptr( BaseAddr, Register ) \
+ ( (volatile UINT32 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio32( BaseAddr, Register ) \
+ *IohMmio32Ptr( BaseAddr, Register )
+
+#define IohMmio32Or( BaseAddr, Register, OrData ) \
+ IohMmio32( BaseAddr, Register ) = \
+ (UINT32) ( \
+ IohMmio32( BaseAddr, Register ) | \
+ (UINT32)(OrData) \
+ )
+
+#define IohMmio32And( BaseAddr, Register, AndData ) \
+ IohMmio32( BaseAddr, Register ) = \
+ (UINT32) ( \
+ IohMmio32( BaseAddr, Register ) & \
+ (UINT32)(AndData) \
+ )
+
+#define IohMmio32AndThenOr( BaseAddr, Register, AndData, OrData ) \
+ IohMmio32( BaseAddr, Register ) = \
+ (UINT32) ( \
+ ( IohMmio32( BaseAddr, Register ) & \
+ (UINT32)(AndData) \
+ ) | \
+ (UINT32)(OrData) \
+ )
+//
+// UINT16
+//
+
+#define IohMmio16Ptr( BaseAddr, Register ) \
+ ( (volatile UINT16 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio16( BaseAddr, Register ) \
+ *IohMmio16Ptr( BaseAddr, Register )
+
+#define IohMmio16Or( BaseAddr, Register, OrData ) \
+ IohMmio16( BaseAddr, Register ) = \
+ (UINT16) ( \
+ IohMmio16( BaseAddr, Register ) | \
+ (UINT16)(OrData) \
+ )
+
+#define IohMmio16And( BaseAddr, Register, AndData ) \
+ IohMmio16( BaseAddr, Register ) = \
+ (UINT16) ( \
+ IohMmio16( BaseAddr, Register ) & \
+ (UINT16)(AndData) \
+ )
+
+#define IohMmio16AndThenOr( BaseAddr, Register, AndData, OrData ) \
+ IohMmio16( BaseAddr, Register ) = \
+ (UINT16) ( \
+ ( IohMmio16( BaseAddr, Register ) & \
+ (UINT16)(AndData) \
+ ) | \
+ (UINT16)(OrData) \
+ )
+//
+// UINT8
+//
+#define IohMmio8Ptr( BaseAddr, Register ) \
+ ( (volatile UINT8 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio8( BaseAddr, Register ) \
+ *IohMmio8Ptr( BaseAddr, Register )
+
+#define IohMmio8Or( BaseAddr, Register, OrData ) \
+ IohMmio8( BaseAddr, Register ) = \
+ (UINT8) ( \
+ IohMmio8( BaseAddr, Register ) | \
+ (UINT8)(OrData) \
+ )
+
+#define IohMmio8And( BaseAddr, Register, AndData ) \
+ IohMmio8( BaseAddr, Register ) = \
+ (UINT8) ( \
+ IohMmio8( BaseAddr, Register ) & \
+ (UINT8)(AndData) \
+ )
+
+#define IohMmio8AndThenOr( BaseAddr, Register, AndData, OrData ) \
+ IohMmio8( BaseAddr, Register ) = \
+ (UINT8) ( \
+ ( IohMmio8( BaseAddr, Register ) & \
+ (UINT8)(AndData) \
+ ) | \
+ (UINT8)(OrData) \
+ )
+
+//
+// Common Memory mapped Pci access macros ------------------------------------------
+//
+#define Ioh_PCI_EXPRESS_BASE_ADDRESS 0xE0000000
+
+
+#define IohMmPciAddress( Segment, Bus, Device, Function, Register ) \
+ ( (UINTN)Ioh_PCI_EXPRESS_BASE_ADDRESS + \
+ (UINTN)(Bus << 20) + \
+ (UINTN)(Device << 15) + \
+ (UINTN)(Function << 12) + \
+ (UINTN)(Register) \
+ )
+
+//
+// UINT32
+//
+#define IohMmPci32Ptr( Segment, Bus, Device, Function, Register ) \
+ ( (volatile UINT32 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define IohMmPci32( Segment, Bus, Device, Function, Register ) \
+ *IohMmPci32Ptr( Segment, Bus, Device, Function, Register )
+
+#define IohMmPci32Or( Segment, Bus, Device, Function, Register, OrData ) \
+ IohMmPci32( Segment, Bus, Device, Function, Register ) = \
+ (UINT32) ( \
+ IohMmPci32( Segment, Bus, Device, Function, Register ) | \
+ (UINT32)(OrData) \
+ )
+
+#define IohMmPci32And( Segment, Bus, Device, Function, Register, AndData ) \
+ IohMmPci32( Segment, Bus, Device, Function, Register ) = \
+ (UINT32) ( \
+ IohMmPci32( Segment, Bus, Device, Function, Register ) & \
+ (UINT32)(AndData) \
+ )
+
+#define IohMmPci32AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+ IohMmPci32( Segment, Bus, Device, Function, Register ) = \
+ (UINT32) ( \
+ ( IohMmPci32( Segment, Bus, Device, Function, Register ) & \
+ (UINT32)(AndData) \
+ ) | \
+ (UINT32)(OrData) \
+ )
+//
+// UINT16
+//
+#define IohMmPci16Ptr( Segment, Bus, Device, Function, Register ) \
+ ( (volatile UINT16 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define IohMmPci16( Segment, Bus, Device, Function, Register ) \
+ *IohMmPci16Ptr( Segment, Bus, Device, Function, Register )
+
+#define IohMmPci16Or( Segment, Bus, Device, Function, Register, OrData ) \
+ IohMmPci16( Segment, Bus, Device, Function, Register ) = \
+ (UINT16) ( \
+ IohMmPci16( Segment, Bus, Device, Function, Register ) | \
+ (UINT16)(OrData) \
+ )
+
+#define IohMmPci16And( Segment, Bus, Device, Function, Register, AndData ) \
+ IohMmPci16( Segment, Bus, Device, Function, Register ) = \
+ (UINT16) ( \
+ IohMmPci16( Segment, Bus, Device, Function, Register ) & \
+ (UINT16)(AndData) \
+ )
+
+#define IohMmPci16AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+ IohMmPci16( Segment, Bus, Device, Function, Register ) = \
+ (UINT16) ( \
+ ( IohMmPci16( Segment, Bus, Device, Function, Register ) & \
+ (UINT16)(AndData) \
+ ) | \
+ (UINT16)(OrData) \
+ )
+//
+// UINT8
+//
+#define IohMmPci8Ptr( Segment, Bus, Device, Function, Register ) \
+ ( (volatile UINT8 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define IohMmPci8( Segment, Bus, Device, Function, Register ) \
+ *IohMmPci8Ptr( Segment, Bus, Device, Function, Register )
+
+#define IohMmPci8Or( Segment, Bus, Device, Function, Register, OrData ) \
+ IohMmPci8( Segment, Bus, Device, Function, Register ) = \
+ (UINT8) ( \
+ IohMmPci8( Segment, Bus, Device, Function, Register ) | \
+ (UINT8)(OrData) \
+ )
+
+#define IohMmPci8And( Segment, Bus, Device, Function, Register, AndData ) \
+ IohMmPci8( Segment, Bus, Device, Function, Register ) = \
+ (UINT8) ( \
+ IohMmPci8( Segment, Bus, Device, Function, Register ) & \
+ (UINT8)(AndData) \
+ )
+
+#define IohMmPci8AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+ IohMmPci8( Segment, Bus, Device, Function, Register ) = \
+ (UINT8) ( \
+ ( IohMmPci8( Segment, Bus, Device, Function, Register ) & \
+ (UINT8)(AndData) \
+ ) | \
+ (UINT8)(OrData) \
+ )
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h b/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h
new file mode 100644
index 0000000000..b494a3b159
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h
@@ -0,0 +1,158 @@
+/** @file
+
+Intel I2C 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.
+
+**/
+
+#ifndef _I2C_LIB_H_
+#define _I2C_LIB_H_
+
+#include "I2cRegs.h"
+
+/**
+
+ The I2cWriteByte() function is a wrapper function for the WriteByte() function.
+ Provides a standard way to execute a standard single byte write to an IC2 device
+ (without accessing sub-addresses), as defined in the I2C Specification.
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param Buffer Contains the value of byte data to execute to the
+ I2C slave device.
+
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN OUT VOID *Buffer
+ );
+
+/**
+
+ The I2cReadByte() function is a wrapper function for the ReadByte() function.
+ Provides a standard way to execute a standard single byte read to an I2C device
+ (without accessing sub-addresses), as defined in the I2C Specification.
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param Buffer Contains the value of byte data read from the
+ I2C slave device.
+
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN OUT VOID *Buffer
+ );
+
+/**
+
+ The I2cWriteMultipleByte() function is a wrapper function for the WriteMultipleByte()
+ function. Provides a standard way to execute multiple byte writes to an I2C device (e.g. when
+ accessing sub-addresses or writing block of data), as defined in the I2C Specification.
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param Length No. of bytes to be written.
+
+ @param Buffer Contains the value of byte to be written to the
+ I2C slave device.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This, Length or Buffer pointers are invalid.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteMultipleByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN UINTN *Length,
+ IN OUT VOID *Buffer
+ );
+
+/**
+
+ The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte
+ function. Provides a standard way to execute multiple byte writes to an IC2 device
+ (e.g. when accessing sub-addresses or when reading block of data), as defined
+ in the I2C Specification (I2C combined write/read protocol).
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param WriteLength No. of bytes to be written. In this case data
+ written typically contains sub-address or sub-addresses
+ in Hi-Lo format, that need to be read (I2C combined
+ write/read protocol).
+
+ @param ReadLength No. of bytes to be read from I2C slave device.
+ need to be read.
+
+ @param Buffer Contains the value of byte data read from the
+ I2C slave device.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This, WriteLength, ReadLength or Buffer
+ pointers are invalid.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadMultipleByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN UINTN *WriteLength,
+ IN UINTN *ReadLength,
+ IN OUT VOID *Buffer
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h b/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h
new file mode 100644
index 0000000000..87aced6d18
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h
@@ -0,0 +1,42 @@
+/** @file
+Library that provides Soc specific library services for SouthCluster devices.
+
+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 __IOH_LIB_H__
+#define __IOH_LIB_H__
+
+#include "Ioh.h"
+
+EFI_STATUS
+EFIAPI
+InitializeIohSsvidSsid (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ );
+
+VOID
+EFIAPI
+EnableUsbMemIoBusMaster (
+ IN UINT8 UsbBusNumber
+ );
+
+UINT32
+EFIAPI
+ReadIohGpioValues (
+ VOID
+ );
+
+#endif
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h b/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h
new file mode 100644
index 0000000000..ac34930826
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h
@@ -0,0 +1,280 @@
+/** @file
+
+Header file for Industry MMC 4.2 spec.
+
+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 _MMC_H
+#define _MMC_H
+
+#pragma pack(1)
+//
+//Command definition
+//
+
+#define CMD0 0
+#define CMD1 1
+#define CMD2 2
+#define CMD3 3
+#define CMD4 4
+#define CMD6 6
+#define CMD7 7
+#define CMD8 8
+#define CMD9 9
+#define CMD10 10
+#define CMD11 11
+#define CMD12 12
+#define CMD13 13
+#define CMD14 14
+#define CMD15 15
+#define CMD16 16
+#define CMD17 17
+#define CMD18 18
+#define CMD19 19
+#define CMD20 20
+#define CMD23 23
+#define CMD24 24
+#define CMD25 25
+#define CMD26 26
+#define CMD27 27
+#define CMD28 28
+#define CMD29 29
+#define CMD30 30
+#define CMD35 35
+#define CMD36 36
+#define CMD38 38
+#define CMD39 39
+#define CMD40 40
+#define CMD42 42
+#define CMD55 55
+#define CMD56 56
+
+
+
+#define GO_IDLE_STATE CMD0
+#define SEND_OP_COND CMD1
+#define ALL_SEND_CID CMD2
+#define SET_RELATIVE_ADDR CMD3
+#define SET_DSR CMD4
+#define SWITCH CMD6
+#define SELECT_DESELECT_CARD CMD7
+#define SEND_EXT_CSD CMD8
+#define SEND_CSD CMD9
+#define SEND_CID CMD10
+#define READ_DAT_UNTIL_STOP CMD11
+#define STOP_TRANSMISSION CMD12
+#define SEND_STATUS CMD13
+#define BUSTEST_R CMD14
+#define GO_INACTIVE_STATE CMD15
+#define SET_BLOCKLEN CMD16
+#define READ_SINGLE_BLOCK CMD17
+#define READ_MULTIPLE_BLOCK CMD18
+#define BUSTEST_W CMD19
+#define WRITE_DAT_UNTIL_STOP CMD20
+#define SET_BLOCK_COUNT CMD23
+#define WRITE_BLOCK CMD24
+#define WRITE_MULTIPLE_BLOCK CMD25
+#define PROGRAM_CID CMD26
+#define PROGRAM_CSD CMD27
+#define SET_WRITE_PROT CMD28
+#define CLR_WRITE_PROT CMD29
+#define SEND_WRITE_PROT CMD30
+#define ERASE_GROUP_START CMD35
+#define ERASE_GROUP_END CMD36
+#define ERASE CMD38
+#define FAST_IO CMD39
+#define GO_IRQ_STATE CMD40
+#define LOCK_UNLOCK CMD42
+#define APP_CMD CMD55
+#define GEN_CMD CMD56
+
+
+#define CMD_INDEX_MASK 0x3F
+#define AUTO_CMD12_ENABLE BIT6
+#define AUTO_CMD23_ENABLE BIT7
+
+#define FREQUENCY_OD (400 * 1000)
+#define FREQUENCY_MMC_PP (26 * 1000 * 1000)
+#define FREQUENCY_MMC_PP_HIGH (52 * 1000 * 1000)
+
+#define DEFAULT_DSR_VALUE 0x404
+
+//
+//Registers definition
+//
+
+typedef struct {
+ UINT32 Reserved0: 7; // 0
+ UINT32 V170_V195: 1; // 1.70V - 1.95V
+ UINT32 V200_V260: 7; // 2.00V - 2.60V
+ UINT32 V270_V360: 9; // 2.70V - 3.60V
+ UINT32 Reserved1: 5; // 0
+ UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode)
+ UINT32 Busy: 1; // This bit is set to LOW if the card has not finished the power up routine
+}OCR;
+
+
+typedef struct {
+ UINT8 NotUsed: 1; // 1
+ UINT8 CRC: 7; // CRC7 checksum
+ UINT8 MDT; // Manufacturing date
+ UINT32 PSN; // Product serial number
+ UINT8 PRV; // Product revision
+ UINT8 PNM[6]; // Product name
+ UINT16 OID; // OEM/Application ID
+ UINT8 MID; // Manufacturer ID
+}CID;
+
+
+typedef struct {
+ UINT8 NotUsed: 1; // 1 [0:0]
+ UINT8 CRC: 7; // CRC [7:1]
+ UINT8 ECC: 2; // ECC code [9:8]
+ UINT8 FILE_FORMAT: 2; // File format [11:10]
+ UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12]
+ UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13]
+ UINT8 COPY: 1; // Copy flag (OTP) [14:14]
+ UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15]
+ UINT16 CONTENT_PROT_APP: 1; // Content protection application [16:16]
+ UINT16 Reserved0: 4; // 0 [20:17]
+ UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21]
+ UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22]
+ UINT16 R2W_FACTOR: 3; // Write speed factor [28:26]
+ UINT16 DEFAULT_ECC: 2; // Manufacturer default ECC [30:29]
+ UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31]
+ UINT32 WP_GRP_SIZE: 5; // Write protect group size [36:32]
+ UINT32 ERASE_GRP_MULT: 5; // Erase group size multiplier [41:37]
+ UINT32 ERASE_GRP_SIZE: 5; // Erase group size [46:42]
+ UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47]
+ UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50]
+ UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53]
+ UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56]
+ UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59]
+ UINT32 C_SIZELow2: 2;// Device size [73:62]
+ UINT32 C_SIZEHigh10: 10;// Device size [73:62]
+ UINT32 Reserved1: 2; // 0 [75:74]
+ UINT32 DSR_IMP: 1; // DSR implemented [76:76]
+ UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77]
+ UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78]
+ UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79]
+ UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80]
+ UINT32 CCC: 12;// Card command classes [95:84]
+ UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96]
+ UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+ UINT8 TAAC ; // Data read access-time 1 [119:112]
+ UINT8 Reserved2: 2; // 0 [121:120]
+ UINT8 SPEC_VERS: 4; // System specification version [125:122]
+ UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126]
+}CSD;
+
+typedef struct {
+ UINT8 Reserved0[181]; // 0 [0:180]
+ UINT8 ERASED_MEM_CONT; // Erased Memory Content [181]
+ UINT8 Reserved2; // Erased Memory Content [182]
+ UINT8 BUS_WIDTH; // Bus Width Mode [183]
+ UINT8 Reserved3; // 0 [184]
+ UINT8 HS_TIMING; // High Speed Interface Timing [185]
+ UINT8 Reserved4; // 0 [186]
+ UINT8 POWER_CLASS; // Power Class [187]
+ UINT8 Reserved5; // 0 [188]
+ UINT8 CMD_SET_REV; // Command Set Revision [189]
+ UINT8 Reserved6; // 0 [190]
+ UINT8 CMD_SET; // Command Set [191]
+ UINT8 EXT_CSD_REV; // Extended CSD Revision [192]
+ UINT8 Reserved7; // 0 [193]
+ UINT8 CSD_STRUCTURE; // CSD Structure Version [194]
+ UINT8 Reserved8; // 0 [195]
+ UINT8 CARD_TYPE; // Card Type [196]
+ UINT8 Reserved9[3]; // 0 [199:197]
+ UINT8 PWR_CL_52_195; // Power Class for 52MHz @ 1.95V [200]
+ UINT8 PWR_CL_26_195; // Power Class for 26MHz @ 1.95V [201]
+ UINT8 PWR_CL_52_360; // Power Class for 52MHz @ 3.6V [202]
+ UINT8 PWR_CL_26_360; // Power Class for 26MHz @ 3.6V [203]
+ UINT8 Reserved10; // 0 [204]
+ UINT8 MIN_PERF_R_4_26; // Minimum Read Performance for 4bit @26MHz [205]
+ UINT8 MIN_PERF_W_4_26; // Minimum Write Performance for 4bit @26MHz [206]
+ UINT8 MIN_PERF_R_8_26_4_52; // Minimum Read Performance for 8bit @26MHz/4bit @52MHz [207]
+ UINT8 MIN_PERF_W_8_26_4_52; // Minimum Write Performance for 8bit @26MHz/4bit @52MHz [208]
+ UINT8 MIN_PERF_R_8_52; // Minimum Read Performance for 8bit @52MHz [209]
+ UINT8 MIN_PERF_W_8_52; // Minimum Write Performance for 8bit @52MHz [210]
+ UINT8 Reserved11; // 0 [211]
+ UINT8 SEC_COUNT[4]; // Sector Count [215:212]
+ UINT8 Reserved12[288]; // 0 [503:216]
+ UINT8 S_CMD_SET; // Sector Count [504]
+ UINT8 Reserved13[7]; // Sector Count [511:505]
+}EXT_CSD;
+
+
+//
+//Card Status definition
+//
+typedef struct {
+ UINT32 Reserved0: 2; //Reserved for Manufacturer Test Mode
+ UINT32 Reserved1: 2; //Reserved for Application Specific commands
+ UINT32 Reserved2: 1; //
+ UINT32 SAPP_CMD: 1; //
+ UINT32 Reserved3: 1; //Reserved
+ UINT32 SWITCH_ERROR: 1; //
+ UINT32 READY_FOR_DATA: 1; //
+ UINT32 CURRENT_STATE: 4; //
+ UINT32 ERASE_RESET: 1; //
+ UINT32 Reserved4: 1; //Reserved
+ UINT32 WP_ERASE_SKIP: 1; //
+ UINT32 CID_CSD_OVERWRITE: 1; //
+ UINT32 OVERRUN: 1; //
+ UINT32 UNDERRUN: 1; //
+ UINT32 ERROR: 1; //
+ UINT32 CC_ERROR: 1; //
+ UINT32 CARD_ECC_FAILED: 1; //
+ UINT32 ILLEGAL_COMMAND: 1; //
+ UINT32 COM_CRC_ERROR: 1; //
+ UINT32 LOCK_UNLOCK_FAILED: 1; //
+ UINT32 CARD_IS_LOCKED: 1; //
+ UINT32 WP_VIOLATION: 1; //
+ UINT32 ERASE_PARAM: 1; //
+ UINT32 ERASE_SEQ_ERROR: 1; //
+ UINT32 BLOCK_LEN_ERROR: 1; //
+ UINT32 ADDRESS_MISALIGN: 1; //
+ UINT32 ADDRESS_OUT_OF_RANGE:1; //
+}CARD_STATUS;
+
+typedef struct {
+ UINT32 CmdSet: 3;
+ UINT32 Reserved0: 5;
+ UINT32 Value: 8;
+ UINT32 Index: 8;
+ UINT32 Access: 2;
+ UINT32 Reserved1: 6;
+}SWITCH_ARGUMENT;
+
+#define CommandSet_Mode 0
+#define SetBits_Mode 1
+#define ClearBits_Mode 2
+#define WriteByte_Mode 3
+
+
+#define Idle_STATE 0
+#define Ready_STATE 1
+#define Ident_STATE 2
+#define Stby_STATE 3
+#define Tran_STATE 4
+#define Data_STATE 5
+#define Rcv_STATE 6
+#define Prg_STATE 7
+#define Dis_STATE 8
+#define Btst_STATE 9
+
+
+
+#pragma pack()
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h b/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h
new file mode 100644
index 0000000000..8d9fdb52c6
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h
@@ -0,0 +1,152 @@
+/** @file
+
+Header file for Industry SD Card 2.0 spec.
+
+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 _SD_CARD_H
+#define _SD_CARD_H
+
+#include "MMC.h"
+
+#pragma pack(1)
+
+#define CHECK_PATTERN 0xAA ///< Physical Layer Simplified Specification Version 3.01 recommended 0xAA
+
+#define ACMD6 6
+#define ACMD13 13
+#define ACMD23 23
+#define ACMD41 41
+#define ACMD42 42
+#define ACMD51 51
+
+
+#define SWITCH_FUNC CMD6
+#define SEND_IF_COND CMD8
+
+
+#define SET_BUS_WIDTH ACMD6
+#define SD_STATUS ACMD13
+#define SET_WR_BLK_ERASE_COUNT ACMD23
+#define SD_SEND_OP_COND ACMD41
+#define SET_CLR_CARD_DETECT ACMD42
+#define SEND_SCR ACMD51
+
+
+
+#define SD_BUS_WIDTH_1 0
+#define SD_BUS_WIDTH_4 2
+
+
+
+#define FREQUENCY_SD_PP (25 * 1000 * 1000)
+#define FREQUENCY_SD_PP_HIGH (50 * 1000 * 1000)
+
+
+#define SD_SPEC_10 0
+#define SD_SPEC_11 1
+#define SD_SPEC_20 2
+
+
+#define VOLTAGE_27_36 0x1
+
+typedef struct {
+ UINT8 NotUsed: 1; // 1 [0:0]
+ UINT8 CRC: 7; // CRC [7:1]
+ UINT8 ECC: 2; // ECC code [9:8]
+ UINT8 FILE_FORMAT: 2; // File format [11:10]
+ UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12]
+ UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13]
+ UINT8 COPY: 1; // Copy flag (OTP) [14:14]
+ UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15]
+ UINT16 Reserved0: 5; // 0 [20:16]
+ UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21]
+ UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22]
+ UINT16 R2W_FACTOR: 3; // Write speed factor [28:26]
+ UINT16 DEFAULT_ECC: 2; // Manufacturer default ECC [30:29]
+ UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31]
+ UINT16 WP_GRP_SIZE: 7; // Write protect group size [38:32]
+ UINT16 SECTOR_SIZE: 7; // Erase sector size [45:39]
+ UINT16 ERASE_BLK_EN: 1; // Erase single block enable [46:46]
+ UINT16 Reserved1: 1; // 0 [47:47]
+
+ UINT32 C_SIZE: 22; // Device size [69:48]
+ UINT32 Reserved2: 6; // 0 [75:70]
+ UINT32 DSR_IMP: 1; // DSR implemented [76:76]
+ UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77]
+ UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78]
+ UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79]
+
+ UINT16 READ_BL_LEN: 4; // Max. read data block length [83:80]
+ UINT16 CCC: 12; // Card command classes [95:84]
+ UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96]
+ UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+ UINT8 TAAC ; // Data read access-time 1 [119:112]
+ UINT8 Reserved3: 6; // 0 [125:120]
+ UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126]
+}CSD_SDV2;
+
+typedef struct {
+ UINT32 Reserved0;
+ UINT32 Reserved1: 16;
+ UINT32 SD_BUS_WIDTH: 4;
+ UINT32 SD_SECURITY: 3;
+ UINT32 DATA_STAT_AFTER_ERASE: 1;
+ UINT32 SD_SPEC: 4;
+ UINT32 SCR_STRUCT: 4;
+}SCR;
+
+
+typedef struct {
+ UINT8 Reserved0[50];
+ UINT8 ERASE_OFFSET: 2;
+ UINT8 ERASE_TIMEOUT: 6;
+ UINT16 ERASE_SIZE;
+ UINT8 Reserved1: 4;
+ UINT8 AU_SIZE: 4;
+ UINT8 PERFORMANCE_MOVE;
+ UINT8 SPEED_CLASS;
+ UINT32 SIZE_OF_PROTECTED_AREA;
+ UINT32 SD_CARD_TYPE: 16;
+ UINT32 Reserved2: 13;
+ UINT32 SECURED_MODE: 1;
+ UINT32 DAT_BUS_WIDTH: 2;
+}SD_STATUS_REG;
+
+
+
+typedef struct {
+ UINT8 Reserved0[34];
+ UINT16 Group1BusyStatus;
+ UINT16 Group2BusyStatus;
+ UINT16 Group3BusyStatus;
+ UINT16 Group4BusyStatus;
+ UINT16 Group5BusyStatus;
+ UINT16 Group6BusyStatus;
+ UINT8 DataStructureVersion;
+ UINT8 Group21Status;
+ UINT8 Group43Status;
+ UINT8 Group65Status;
+ UINT16 Group1Function;
+ UINT16 Group2Function;
+ UINT16 Group3Function;
+ UINT16 Group4Function;
+ UINT16 Group5Function;
+ UINT16 Group6Function;
+ UINT16 MaxCurrent;
+}SWITCH_STATUS;
+
+
+#pragma pack()
+#endif
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h b/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h
new file mode 100644
index 0000000000..42ff8415ba
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h
@@ -0,0 +1,339 @@
+/** @file
+
+Interface definition for EFI_SD_HOST_IO_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 _SD_HOST_IO_H
+#define _SD_HOST_IO_H
+
+#include "SDCard.h"
+#include "CEATA.h"
+
+
+#define EFI_SD_HOST_IO_PROTOCOL_GUID \
+ { \
+ 0xb63f8ec7, 0xa9c9, 0x4472, {0xa4, 0xc0, 0x4d, 0x8b, 0xf3, 0x65, 0xcc, 0x51} \
+ }
+
+///
+/// Forward reference for pure ANSI compatability
+///
+typedef struct _EFI_SD_HOST_IO_PROTOCOL EFI_SD_HOST_IO_PROTOCOL;
+
+
+
+typedef enum {
+ ResponseNo = 0,
+ ResponseR1,
+ ResponseR1b,
+ ResponseR2,
+ ResponseR3,
+ ResponseR4,
+ ResponseR5,
+ ResponseR5b,
+ ResponseR6,
+ ResponseR7
+}RESPONSE_TYPE;
+
+typedef enum {
+ NoData = 0,
+ InData,
+ OutData
+}TRANSFER_TYPE;
+
+typedef enum {
+ Reset_Auto = 0,
+ Reset_DAT,
+ Reset_CMD,
+ Reset_DAT_CMD,
+ Reset_All
+}RESET_TYPE;
+
+#define PCI_SUBCLASS_SD_HOST_CONTROLLER 0x05
+#define PCI_IF_STANDARD_HOST_NO_DMA 0x00
+#define PCI_IF_STANDARD_HOST_SUPPORT_DMA 0x01
+
+#define SDHCI_SPEC_100 0
+#define SDHCI_SPEC_200 1
+#define SDHCI_SPEC_300 2
+
+//
+//MMIO Registers definition for MMC/SDIO controller
+//
+#define MMIO_DMAADR 0x00
+#define MMIO_BLKSZ 0x04
+#define MMIO_BLKCNT 0x06
+#define MMIO_CMDARG 0x08
+#define MMIO_XFRMODE 0x0C
+#define MMIO_SDCMD 0x0E
+#define MMIO_RESP 0x10
+#define MMIO_BUFDATA 0x20
+#define MMIO_PSTATE 0x24
+#define MMIO_HOSTCTL 0x28
+#define MMIO_PWRCTL 0x29
+#define MMIO_BLKGAPCTL 0x2A
+#define MMIO_WAKECTL 0x2B
+#define MMIO_CLKCTL 0x2C
+#define V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL 0x80
+#define V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL 0x3FF
+#define B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK 0xC0
+
+#define MMIO_TOCTL 0x2E
+#define MMIO_SWRST 0x2F
+#define MMIO_NINTSTS 0x30
+#define MMIO_ERINTSTS 0x32
+#define MMIO_NINTEN 0x34
+#define MMIO_ERINTEN 0x36
+#define MMIO_NINTSIGEN 0x38
+#define MMIO_ERINTSIGEN 0x3A
+#define MMIO_AC12ERRSTS 0x3C
+#define MMIO_HOSTCTL2 0x3E
+#define MMIO_CAP 0x40
+#define MMIO_MCCAP 0x48
+#define MMIO_SLTINTSTS 0xFC
+#define MMIO_CTRLRVER 0xFE
+#define MMIO_SRST 0x1FC
+
+//
+// Protocol definitions
+//
+
+/**
+ The main function used to send the command to the card inserted into the SD host slot.
+ It will assemble the arguments to set the command register and wait for the command
+ and transfer completed until timeout. Then it will read the response register to fill
+ the ResponseData.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param CommandIndex The command index to set the command index field of command register.
+ @param Argument Command argument to set the argument field of command register.
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.
+ @param Buffer Contains the data read from / write to the device.
+ @param BufferSize The size of the buffer.
+ @param ResponseType RESPONSE_TYPE.
+ @param TimeOut Time out value in 1 ms unit.
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_OUT_OF_RESOURCES
+ @retval EFI_TIMEOUT
+ @retval EFI_DEVICE_ERROR
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SEND_COMMAND) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData OPTIONAL
+ );
+
+/**
+ Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+ It depends on the max frequency the host can support, divider, and host speed mode.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param MaxFrequency Max frequency in HZ.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_CLOCK_FREQUENCY) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 MaxFrequency
+ );
+
+
+/**
+ Set bus width of the host controller
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param BusWidth Bus width in 1, 4, 8 bits.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_BUS_WIDTH) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 BusWidth
+ );
+
+/**
+ Set voltage which could supported by the host controller.
+ Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Voltage Units in 0.1 V.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_HOST_VOLTAGE) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 Voltage
+ );
+
+/**
+ Reset the host controller.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param ResetAll TRUE to reset all.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_RESET_SD_HOST) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN RESET_TYPE ResetType
+ );
+
+/**
+ Enable auto stop on the host controller.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Enable TRUE to enable, FALSE to disable.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_ENABLE_AUTO_STOP_CMD) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ );
+
+/**
+ Find whether these is a card inserted into the slot. If so init the host.
+ If not, return EFI_NOT_FOUND.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS
+ @retval EFI_NOT_FOUND
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_DETECT_CARD_AND_INIT_HOST) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This
+ );
+
+/**
+ Set the Block length on the host controller.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param BlockLength card supportes block length.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_BLOCK_LENGTH) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 BlockLength
+ );
+
+/**
+ Enable/Disable High Speed transfer mode
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Enable TRUE to Enable, FALSE to Disable
+
+ @return EFI_SUCCESS
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_HIGH_SPEED_MODE) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_DUAL_DATARATE_MODE) (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ );
+
+
+
+#define EFI_SD_HOST_IO_PROTOCOL_REVISION_01 0x02
+
+
+typedef struct {
+ UINT32 HighSpeedSupport: 1; //High speed supported
+ UINT32 V18Support: 1; //1.8V supported
+ UINT32 V30Support: 1; //3.0V supported
+ UINT32 V33Support: 1; //3.3V supported
+ UINT32 Reserved0: 4;
+ UINT32 HostVersion: 8;
+ UINT32 BusWidth4: 1; // 4 bit width
+ UINT32 BusWidth8: 1; // 8 bit width
+ UINT32 Reserved1: 14;
+ UINT32 BoundarySize;
+}HOST_CAPABILITY;
+
+
+//
+// Interface structure for the SD HOST I/O Protocol
+//
+struct _EFI_SD_HOST_IO_PROTOCOL {
+ UINT32 Revision;
+ HOST_CAPABILITY HostCapability;
+ EFI_SD_HOST_IO_PROTOCOL_SEND_COMMAND SendCommand;
+ EFI_SD_HOST_IO_PROTOCOL_SET_CLOCK_FREQUENCY SetClockFrequency;
+ EFI_SD_HOST_IO_PROTOCOL_SET_BUS_WIDTH SetBusWidth;
+ EFI_SD_HOST_IO_PROTOCOL_SET_HOST_VOLTAGE SetHostVoltage;
+ EFI_SD_HOST_IO_PROTOCOL_RESET_SD_HOST ResetSDHost;
+ EFI_SD_HOST_IO_PROTOCOL_ENABLE_AUTO_STOP_CMD EnableAutoStopCmd;
+ EFI_SD_HOST_IO_PROTOCOL_DETECT_CARD_AND_INIT_HOST DetectCardAndInitHost;
+ EFI_SD_HOST_IO_PROTOCOL_SET_BLOCK_LENGTH SetBlockLength;
+ EFI_SD_HOST_IO_PROTOCOL_HIGH_SPEED_MODE SetHighSpeedMode;
+ EFI_SD_HOST_IO_PROTOCOL_DUAL_DATARATE_MODE SetDDRMode;
+};
+
+extern EFI_GUID gEfiSDHostIoProtocolGuid;
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h
new file mode 100644
index 0000000000..0d56b7160b
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h
@@ -0,0 +1,61 @@
+/** @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 <Ioh.h>
+#include <IohCommonDefinitions.h>
+
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Protocol/PciRootBridgeIo.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/DevicePath.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/S3PciLib.h>
+#include <Library/S3IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/TimerLib.h>
+#include <Library/IoLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IohLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <IndustryStandard/Pci.h>
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h
new file mode 100644
index 0000000000..789f18b191
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h
@@ -0,0 +1,89 @@
+/** @file
+Head file for BDS Platform specific code
+
+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 _IOH_BDS_H
+#define _IOH_BDS_H
+
+#include <Ioh.h>
+#include <Protocol/DevicePath.h>
+#include <Library/DevicePathLib.h>
+
+extern EFI_DEVICE_PATH_PROTOCOL *gDeviceConnectOption [];
+
+#define PCI_DEVICE_PATH_NODE(Func, Dev) \
+ { \
+ { \
+ HARDWARE_DEVICE_PATH, \
+ HW_PCI_DP, \
+ { \
+ (UINT8) (sizeof (PCI_DEVICE_PATH)), \
+ (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
+ } \
+ }, \
+ (Func), \
+ (Dev) \
+ }
+
+#define PNPID_DEVICE_PATH_NODE(PnpId) \
+ { \
+ { \
+ ACPI_DEVICE_PATH, \
+ ACPI_DP, \
+ { \
+ (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
+ (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
+ } \
+ }, \
+ EISA_PNP_ID((PnpId)), \
+ 0 \
+ }
+
+
+
+#define gEndEntire \
+ { \
+ END_DEVICE_PATH_TYPE, \
+ END_ENTIRE_DEVICE_PATH_SUBTYPE, \
+ { \
+ END_DEVICE_PATH_LENGTH, \
+ 0 \
+ } \
+ }
+
+#define gPciRootBridge \
+ PNPID_DEVICE_PATH_NODE(0x0A03)
+
+
+//
+// Platform Root Bridge
+//
+typedef struct {
+ ACPI_HID_DEVICE_PATH PciRootBridge;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_ROOT_BRIDGE_DEVICE_PATH;
+
+
+typedef struct {
+ ACPI_HID_DEVICE_PATH PciRootBridge;
+ PCI_DEVICE_PATH IohDevice;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} IOH_PCI_USB_DEVICE_PATH;
+
+//
+// Ioh BDS Functions
+//
+
+
+#endif // _IOH_BDS_H
diff --git a/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c
new file mode 100644
index 0000000000..432a86f68b
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c
@@ -0,0 +1,48 @@
+/** @file
+Defined the Ioh device path which will be used by
+platform Bbd to perform the platform policy connect.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+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 "IohBds.h"
+
+//
+// Predefined platform root bridge
+//
+PLATFORM_ROOT_BRIDGE_DEVICE_PATH gPlatformRootBridge0 = {
+ gPciRootBridge,
+ gEndEntire
+};
+
+EFI_DEVICE_PATH_PROTOCOL* gPlatformRootBridges [] = {
+ (EFI_DEVICE_PATH_PROTOCOL*)&gPlatformRootBridge0,
+ NULL
+};
+
+//
+// Ioh USB EHCI controller device path
+//
+IOH_PCI_USB_DEVICE_PATH gIohUsbDevicePath0 = {
+ gPciRootBridge,
+ PCI_DEVICE_PATH_NODE(IOH_EHCI_FUNCTION_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER),
+ gEndEntire
+};
+
+//
+// Ioh predefined device connecting option
+//
+EFI_DEVICE_PATH_PROTOCOL* gDeviceConnectOption [] = {
+ // (EFI_DEVICE_PATH_PROTOCOL*)&gIohUsbDevicePath0,
+ NULL
+};
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c
new file mode 100644
index 0000000000..8ab48bc20e
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c
@@ -0,0 +1,43 @@
+/** @file
+QuarkSCSocId 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 "IohBds.h"
+
+/**
+ The entry function for IohInit driver.
+
+ This function just call initialization function.
+
+ @param ImageHandle The driver image handle for GmchInit driver
+ @param SystemTable The pointer to System Table
+
+ @retval EFI_SUCCESS Success to initialize every module.
+ @return EFI_STATUS The status of initialization work.
+
+**/
+EFI_STATUS
+EFIAPI
+IohInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ InitializeIohSsvidSsid(IOH_BUS, IOH_PCI_IOSF2AHB_0_DEV_NUM, 0);
+
+ InitializeIohSsvidSsid(IOH_BUS, IOH_PCI_IOSF2AHB_1_DEV_NUM, 0);
+
+ return EFI_SUCCESS;
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf
new file mode 100644
index 0000000000..4ac1609673
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf
@@ -0,0 +1,82 @@
+## @file
+# Component description file for Quark South Cluster Init driver.
+#
+# IohInit driver implement QuarkSCSocId related drivers, includes:
+# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver.
+#
+# This driver mainly do full initialization for the Soc chipet includes:
+# 1. Initialize the PCI Express device.
+# 2. Initialize the PciHostBridge, and allocate the I/O and memory space from GCD service.
+# 3. Initialize the SmmAccess module and install EFI_SMM_ACCESS_PROTOCOL
+# 4. Initialize the LegacyRegion module, install EFI_LEGACY_REGION_PROTOCOL and set below 1M
+# memory attribute from MTRR.
+#
+# Copyright (c) 2013-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 = IohInitDxe
+ FILE_GUID = 3FE2A8A3-C400-48F8-832F-7881A394C250
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = IohInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ IohInit.c
+ IohBds.h
+ IohData.c
+ CommonHeader.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ S3BootScriptLib
+ PcdLib
+ HobLib
+ PciLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ S3PciLib
+ UefiLib
+ DebugLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ DxeServicesTableLib
+ UefiDriverEntryPoint
+ BaseLib
+ S3IoLib
+ IoLib
+ DevicePathLib
+ IohLib
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiPciIoProtocolGuid
+
+[Pcd]
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartBusNumber
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartDevNumber
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartFunctionNumber
+
+[Depex]
+ TRUE
diff --git a/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h b/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h
new file mode 100644
index 0000000000..facc00f1f0
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h
@@ -0,0 +1,220 @@
+/** @file
+Provides definition of entry point to the common I2C module that produces
+common I2C Controller functions used by I2C library services.
+
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+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 _I2CCOMMON_H_
+#define _I2CCOMMON_H_
+
+#include <Uefi.h>
+#include <Base.h>
+
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/I2cLib.h>
+#include <IohAccess.h>
+#include <IohCommonDefinitions.h>
+#include "I2cRegs.h"
+
+//
+// Constants that define I2C Controller timeout and max. polling time.
+//
+#define MAX_T_POLL_COUNT 100
+#define TI2C_POLL 25 // microseconds
+#define MAX_STOP_DET_POLL_COUNT ((1000 * 1000) / TI2C_POLL) // Extreme for expected Stop detect.
+
+/**
+ The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.
+
+ Always reads PCI configuration space to get MMIO base address of I2C Controller.
+
+ @return The IO port base address of I2C controller.
+
+**/
+UINTN
+GetI2CIoPortBaseAddress (
+ VOID
+ );
+
+/**
+ The EnableI2CMmioSpace() function enables access to I2C MMIO space.
+
+**/
+VOID
+EnableI2CMmioSpace (
+ VOID
+ );
+
+/**
+ The DisableI2CController() functions disables I2C Controller.
+
+**/
+VOID
+DisableI2CController (
+ VOID
+ );
+
+/**
+ The EnableI2CController() function enables the I2C Controller.
+
+**/
+VOID
+EnableI2CController (
+ VOID
+ );
+
+/**
+ The WaitForStopDet() function waits until I2C STOP Condition occurs,
+ indicating transfer completion.
+
+ @retval EFI_SUCCESS Stop detected.
+ @retval EFI_TIMEOUT Timeout while waiting for stop condition.
+ @retval EFI_ABORTED Tx abort signaled in HW status register.
+ @retval EFI_DEVICE_ERROR Tx or Rx overflow detected.
+
+**/
+EFI_STATUS
+WaitForStopDet (
+ VOID
+ );
+
+/**
+
+ The InitializeInternal() function initialises internal I2C Controller
+ register values that are commonly required for I2C Write and Read transfers.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @retval EFI_SUCCESS I2C Operation completed successfully.
+
+**/
+EFI_STATUS
+InitializeInternal (
+ IN EFI_I2C_ADDR_MODE AddrMode
+ );
+
+/**
+
+ The WriteByte() function provides a standard way to execute a
+ standard single byte write to an IC2 device (without accessing
+ sub-addresses), as defined in the I2C Specification.
+
+ @param I2CAddress I2C Slave device address
+ @param Value The 8-bit value to write.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteByte (
+ IN UINTN I2CAddress,
+ IN UINT8 Value
+ );
+
+/**
+
+ The ReadByte() function provides a standard way to execute a
+ standard single byte read to an IC2 device (without accessing
+ sub-addresses), as defined in the I2C Specification.
+
+ @param I2CAddress I2C Slave device address
+ @param ReturnDataPtr Pointer to location to receive read byte.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadByte (
+ IN UINTN I2CAddress,
+ OUT UINT8 *ReturnDataPtr
+ );
+
+/**
+
+ The WriteMultipleByte() function provides a standard way to execute
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+ when writing block of data), as defined in the I2C Specification.
+
+ @param I2CAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param WriteBuffer Contains the value of byte to be written to the
+ I2C slave device.
+
+ @param Length No. of bytes to be written.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Tx abort signaled in HW status register.
+ @retval EFI_DEVICE_ERROR Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteMultipleByte (
+ IN UINTN I2CAddress,
+ IN UINT8 *WriteBuffer,
+ IN UINTN Length
+ );
+
+/**
+
+ The ReadMultipleByte() function provides a standard way to execute
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+ when reading block of data), as defined in the I2C Specification (I2C combined
+ write/read protocol).
+
+ @param I2CAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param Buffer Contains the value of byte data written or read from the
+ I2C slave device.
+
+ @param WriteLength No. of bytes to be written. In this case data
+ written typically contains sub-address or sub-addresses
+ in Hi-Lo format, that need to be read (I2C combined
+ write/read protocol).
+
+ @param ReadLength No. of bytes to be read from I2C slave device.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Tx abort signaled in HW status register.
+ @retval EFI_DEVICE_ERROR Rx underflow or Rx/Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadMultipleByte (
+ IN UINTN I2CAddress,
+ IN OUT UINT8 *Buffer,
+ IN UINTN WriteLength,
+ IN UINTN ReadLength
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c b/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c
new file mode 100644
index 0000000000..80f03eaf29
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c
@@ -0,0 +1,1004 @@
+/** @file
+I2C Library for Quark I2C Controller.
+Follows I2C Controller setup instructions as detailed in
+Quark DataSheet (doc id: 329676) Section 19.1/19.1.3.
+
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+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"
+
+/**
+ The Called to Common Service Entry.
+
+ @return None.
+
+**/
+
+VOID
+I2cCommonServiceEntry (
+ OUT UINT16 *SaveCmdPtr,
+ OUT UINT32 *SaveBar0Ptr
+ )
+{
+ *SaveBar0Ptr = IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
+ if (((*SaveBar0Ptr) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
+
+ IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) =
+ FixedPcdGet32 (PcdIohI2cMmioBase) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK;
+
+ //
+ // also Save Cmd Register, Setup by InitializeInternal later during xfers.
+ //
+ *SaveCmdPtr = IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD);
+ }
+}
+
+/**
+ The Called on Common Service Exit.
+
+ @return None.
+
+**/
+VOID
+I2cCommonServiceExit (
+ IN CONST UINT16 SaveCmd,
+ IN CONST UINT32 SaveBar0
+
+ )
+{
+ if ((SaveBar0 & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
+ IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD) = SaveCmd;
+ IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) = SaveBar0;
+ }
+}
+
+
+/**
+ The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.
+
+ Always reads PCI configuration space to get MMIO base address of I2C Controller.
+
+ @return The IO port base address of I2C controller.
+
+**/
+UINTN
+GetI2CIoPortBaseAddress (
+ VOID
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
+
+ //
+ // Make sure that the IO port base address has been properly set.
+ //
+ ASSERT (I2CIoPortBaseAddress != 0);
+ ASSERT (I2CIoPortBaseAddress != 0xFF);
+
+ return I2CIoPortBaseAddress;
+}
+
+
+/**
+ The EnableI2CMmioSpace() function enables access to I2C MMIO space.
+
+**/
+VOID
+EnableI2CMmioSpace (
+ VOID
+ )
+{
+ UINT8 PciCmd;
+
+ //
+ // Read PCICMD. Bus=0, Dev=0, Func=0, Reg=0x4
+ //
+ PciCmd = IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD);
+
+ //
+ // Enable Bus Master(Bit2), MMIO Space(Bit1) & I/O Space(Bit0)
+ //
+ PciCmd |= 0x7;
+ IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD) = PciCmd;
+
+}
+
+/**
+ The DisableI2CController() functions disables I2C Controller.
+
+**/
+VOID
+DisableI2CController (
+ VOID
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINT32 Addr;
+ UINT32 Data;
+ UINT8 PollCount;
+
+ PollCount = 0;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Disable the I2C Controller by setting IC_ENABLE.ENABLE to zero
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_ENABLE;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Read the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled
+ //
+ Data = 0xFF;
+ Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE_STATUS;
+ Data = *((volatile UINT32 *) (UINTN)(Addr)) & I2C_REG_ENABLE_STATUS;
+ while (Data != 0) {
+ //
+ // Poll the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled, until timeout (TI2C_POLL*MAX_T_POLL_COUNT).
+ //
+ PollCount++;
+ if (PollCount >= MAX_T_POLL_COUNT) {
+ break;
+ }
+ MicroSecondDelay(TI2C_POLL);
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= I2C_REG_ENABLE_STATUS;
+ }
+
+ //
+ // Asset if controller does not enter Disabled state.
+ //
+ ASSERT (PollCount < MAX_T_POLL_COUNT);
+
+ //
+ // Read IC_CLR_INTR register to automatically clear the combined interrupt,
+ // all individual interrupts and the IC_TX_ABRT_SOURCE register.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_INT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+}
+
+/**
+ The EnableI2CController() function enables the I2C Controller.
+
+**/
+VOID
+EnableI2CController (
+ VOID
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINT32 Addr;
+ UINT32 Data;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Enable the I2C Controller by setting IC_ENABLE.ENABLE to 1
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data |= B_I2C_REG_ENABLE;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Clear overflow and abort error status bits before transactions.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_OVER;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_OVER;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_ABRT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+}
+
+/**
+ The WaitForStopDet() function waits until I2C STOP Condition occurs,
+ indicating transfer completion.
+
+ @retval EFI_SUCCESS Stop detected.
+ @retval EFI_TIMEOUT Timeout while waiting for stop condition.
+ @retval EFI_ABORTED Tx abort signaled in HW status register.
+ @retval EFI_DEVICE_ERROR Tx or Rx overflow detected.
+
+**/
+EFI_STATUS
+WaitForStopDet (
+ VOID
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINT32 Addr;
+ UINT32 Data;
+ UINT32 PollCount;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ PollCount = 0;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Wait for STOP Detect.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+
+ do {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ if ((Data & I2C_REG_RAW_INTR_STAT_TX_ABRT) != 0) {
+ Status = EFI_ABORTED;
+ break;
+ }
+ if ((Data & I2C_REG_RAW_INTR_STAT_TX_OVER) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+ if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+ if ((Data & I2C_REG_RAW_INTR_STAT_STOP_DET) != 0) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ MicroSecondDelay(TI2C_POLL);
+ PollCount++;
+ if (PollCount >= MAX_STOP_DET_POLL_COUNT) {
+ Status = EFI_TIMEOUT;
+ break;
+ }
+
+ } while (TRUE);
+
+ return Status;
+}
+
+/**
+
+ The InitializeInternal() function initialises internal I2C Controller
+ register values that are commonly required for I2C Write and Read transfers.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @retval EFI_SUCCESS I2C Operation completed successfully.
+
+**/
+EFI_STATUS
+InitializeInternal (
+ IN EFI_I2C_ADDR_MODE AddrMode
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Addr;
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Enable access to I2C Controller MMIO space.
+ //
+ EnableI2CMmioSpace ();
+
+ //
+ // Disable I2C Controller initially
+ //
+ DisableI2CController ();
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Clear START_DET
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_START_DET;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_CLR_START_DET;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Clear STOP_DET
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_STOP_DET;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_CLR_STOP_DET;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Set addressing mode to user defined (7 or 10 bit) and
+ // speed mode to that defined by PCD (standard mode default).
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CON;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ // Set Addressing Mode
+ if (AddrMode == EfiI2CSevenBitAddrMode) {
+ Data &= ~B_I2C_REG_CON_10BITADD_MASTER;
+ } else {
+ Data |= B_I2C_REG_CON_10BITADD_MASTER;
+ }
+ // Set Speed Mode
+ Data &= ~B_I2C_REG_CON_SPEED;
+ if (FeaturePcdGet (PcdI2CFastModeEnabled)) {
+ Data |= BIT2;
+ } else {
+ Data |= BIT1;
+ }
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+ return Status;
+
+}
+
+/**
+
+ The WriteByte() function provides a standard way to execute a
+ standard single byte write to an IC2 device (without accessing
+ sub-addresses), as defined in the I2C Specification.
+
+ @param I2CAddress I2C Slave device address
+ @param Value The 8-bit value to write.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteByte (
+ IN UINTN I2CAddress,
+ IN UINT8 Value
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Addr;
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ //
+ // Get I2C Memory Mapped registers base address
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Write to the IC_TAR register the address of the slave device to be addressed
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_TAR;
+ Data |= I2CAddress;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Enable the I2C Controller
+ //
+ EnableI2CController ();
+
+ //
+ // Write the data and transfer direction to the IC_DATA_CMD register.
+ // Also specify that transfer should be terminated by STOP condition.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0xFFFFFF00;
+ Data |= (UINT8)Value;
+ Data &= ~B_I2C_REG_DATA_CMD_RW;
+ Data |= B_I2C_REG_DATA_CMD_STOP;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Wait for transfer completion.
+ //
+ Status = WaitForStopDet ();
+
+ //
+ // Ensure I2C Controller disabled.
+ //
+ DisableI2CController();
+
+ return Status;
+}
+
+/**
+
+ The ReadByte() function provides a standard way to execute a
+ standard single byte read to an IC2 device (without accessing
+ sub-addresses), as defined in the I2C Specification.
+
+ @param I2CAddress I2C Slave device address
+ @param ReturnDataPtr Pointer to location to receive read byte.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadByte (
+ IN UINTN I2CAddress,
+ OUT UINT8 *ReturnDataPtr
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Addr;
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ //
+ // Get I2C Memory Mapped registers base address.
+ //
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Write to the IC_TAR register the address of the slave device to be addressed
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_TAR;
+ Data |= I2CAddress;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Enable the I2C Controller
+ //
+ EnableI2CController ();
+
+ //
+ // Write transfer direction to the IC_DATA_CMD register and
+ // specify that transfer should be terminated by STOP condition.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0xFFFFFF00;
+ Data |= B_I2C_REG_DATA_CMD_RW;
+ Data |= B_I2C_REG_DATA_CMD_STOP;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Wait for transfer completion
+ //
+ Status = WaitForStopDet ();
+ if (!EFI_ERROR(Status)) {
+
+ //
+ // Clear RX underflow before reading IC_DATA_CMD.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+ //
+ // Obtain and return read data byte from RX buffer (IC_DATA_CMD[7:0]).
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0x000000FF;
+ *ReturnDataPtr = (UINT8) Data;
+
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
+ if (Data != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Ensure I2C Controller disabled.
+ //
+ DisableI2CController ();
+
+ return Status;
+}
+
+/**
+
+ The WriteMultipleByte() function provides a standard way to execute
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+ when writing block of data), as defined in the I2C Specification.
+
+ @param I2CAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param WriteBuffer Contains the value of byte to be written to the
+ I2C slave device.
+
+ @param Length No. of bytes to be written.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Tx abort signaled in HW status register.
+ @retval EFI_DEVICE_ERROR Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteMultipleByte (
+ IN UINTN I2CAddress,
+ IN UINT8 *WriteBuffer,
+ IN UINTN Length
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Index;
+ UINTN Addr;
+ UINT32 Data;
+ EFI_STATUS Status;
+
+ if (Length > I2C_FIFO_SIZE) {
+ return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.
+ }
+
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Write to the IC_TAR register the address of the slave device to be addressed
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_TAR;
+ Data |= I2CAddress;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Enable the I2C Controller
+ //
+ EnableI2CController ();
+
+ //
+ // Write the data and transfer direction to the IC_DATA_CMD register.
+ // Also specify that transfer should be terminated by STOP condition.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ for (Index = 0; Index < Length; Index++) {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0xFFFFFF00;
+ Data |= (UINT8)WriteBuffer[Index];
+ Data &= ~B_I2C_REG_DATA_CMD_RW;
+ if (Index == (Length-1)) {
+ Data |= B_I2C_REG_DATA_CMD_STOP;
+ }
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+ }
+
+ //
+ // Wait for transfer completion
+ //
+ Status = WaitForStopDet ();
+
+ //
+ // Ensure I2C Controller disabled.
+ //
+ DisableI2CController ();
+ return Status;
+}
+
+/**
+
+ The ReadMultipleByte() function provides a standard way to execute
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+ when reading block of data), as defined in the I2C Specification (I2C combined
+ write/read protocol).
+
+ @param I2CAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param Buffer Contains the value of byte data written or read from the
+ I2C slave device.
+
+ @param WriteLength No. of bytes to be written. In this case data
+ written typically contains sub-address or sub-addresses
+ in Hi-Lo format, that need to be read (I2C combined
+ write/read protocol).
+
+ @param ReadLength No. of bytes to be read from I2C slave device.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Tx abort signaled in HW status register.
+ @retval EFI_DEVICE_ERROR Rx underflow or Rx/Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadMultipleByte (
+ IN UINTN I2CAddress,
+ IN OUT UINT8 *Buffer,
+ IN UINTN WriteLength,
+ IN UINTN ReadLength
+ )
+{
+ UINTN I2CIoPortBaseAddress;
+ UINTN Index;
+ UINTN Addr;
+ UINT32 Data;
+ UINT8 PollCount;
+ EFI_STATUS Status;
+
+ if (WriteLength > I2C_FIFO_SIZE || ReadLength > I2C_FIFO_SIZE) {
+ return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.
+ }
+
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+ //
+ // Write to the IC_TAR register the address of the slave device to be addressed
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= ~B_I2C_REG_TAR;
+ Data |= I2CAddress;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+ //
+ // Enable the I2C Controller
+ //
+ EnableI2CController ();
+
+ //
+ // Write the data (sub-addresses) to the IC_DATA_CMD register.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ for (Index = 0; Index < WriteLength; Index++) {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0xFFFFFF00;
+ Data |= (UINT8)Buffer[Index];
+ Data &= ~B_I2C_REG_DATA_CMD_RW;
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+ }
+
+ //
+ // Issue Read Transfers for each byte (Restart issued when write/read bit changed).
+ //
+ for (Index = 0; Index < ReadLength; Index++) {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data |= B_I2C_REG_DATA_CMD_RW;
+ // Issue a STOP for last read transfer.
+ if (Index == (ReadLength-1)) {
+ Data |= B_I2C_REG_DATA_CMD_STOP;
+ }
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+ }
+
+ //
+ // Wait for STOP condition.
+ //
+ Status = WaitForStopDet ();
+ if (!EFI_ERROR(Status)) {
+
+ //
+ // Poll Receive FIFO Buffer Level register until valid (upto MAX_T_POLL_COUNT times).
+ //
+ Data = 0;
+ PollCount = 0;
+ Addr = I2CIoPortBaseAddress + I2C_REG_RXFLR;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ while ((Data != ReadLength) && (PollCount < MAX_T_POLL_COUNT)) {
+ MicroSecondDelay(TI2C_POLL);
+ PollCount++;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ }
+
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+ //
+ // If no timeout or device error then read rx data.
+ //
+ if (PollCount == MAX_T_POLL_COUNT) {
+ Status = EFI_TIMEOUT;
+ } else if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+
+ //
+ // Clear RX underflow before reading IC_DATA_CMD.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+ //
+ // Read data.
+ //
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+ for (Index = 0; Index < ReadLength; Index++) {
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= 0x000000FF;
+ *(Buffer+Index) = (UINT8)Data;
+ }
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+ Data = *((volatile UINT32 *) (UINTN)(Addr));
+ Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
+ if (Data != 0) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Ensure I2C Controller disabled.
+ //
+ DisableI2CController ();
+
+ return Status;
+}
+
+/**
+
+ The I2cWriteByte() function is a wrapper function for the WriteByte function.
+ Provides a standard way to execute a standard single byte write to an IC2 device
+ (without accessing sub-addresses), as defined in the I2C Specification.
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param Buffer Contains the value of byte data to execute to the
+ I2C slave device.
+
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN I2CAddress;
+ UINT16 SaveCmd;
+ UINT32 SaveBar0;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SaveCmd = 0;
+ SaveBar0 = 0;
+
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+ Status = EFI_SUCCESS;
+
+ I2CAddress = SlaveAddress.I2CDeviceAddress;
+ Status = InitializeInternal (AddrMode);
+ if (!EFI_ERROR(Status)) {
+ Status = WriteByte (I2CAddress, *(UINT8 *) Buffer);
+ }
+
+ I2cCommonServiceExit (SaveCmd, SaveBar0);
+ return Status;
+}
+
+/**
+
+ The I2cReadByte() function is a wrapper function for the ReadByte function.
+ Provides a standard way to execute a standard single byte read to an I2C device
+ (without accessing sub-addresses), as defined in the I2C Specification.
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param Buffer Contains the value of byte data read from the
+ I2C slave device.
+
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN I2CAddress;
+ UINT16 SaveCmd;
+ UINT32 SaveBar0;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SaveCmd = 0;
+ SaveBar0 =0;
+
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+ Status = EFI_SUCCESS;
+
+ I2CAddress = SlaveAddress.I2CDeviceAddress;
+
+ Status = InitializeInternal (AddrMode);
+ if (!EFI_ERROR(Status)) {
+ Status = ReadByte (I2CAddress, (UINT8 *) Buffer);
+ }
+ I2cCommonServiceExit (SaveCmd, SaveBar0);
+ return Status;
+}
+
+/**
+
+ The I2cWriteMultipleByte() function is a wrapper function for the
+ WriteMultipleByte() function. Provides a standard way to execute multiple
+ byte writes to an I2C device (e.g. when accessing sub-addresses or writing
+ block of data), as defined in the I2C Specification.
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param Length No. of bytes to be written.
+
+ @param Buffer Contains the value of byte to be written to the
+ I2C slave device.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This, Length or Buffer pointers are invalid.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteMultipleByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN UINTN *Length,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN I2CAddress;
+ UINT16 SaveCmd;
+ UINT32 SaveBar0;
+
+ if (Buffer == NULL || Length == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SaveCmd = 0;
+ SaveBar0 =0;
+
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+ Status = EFI_SUCCESS;
+
+ I2CAddress = SlaveAddress.I2CDeviceAddress;
+
+ Status = InitializeInternal (AddrMode);
+ if (!EFI_ERROR(Status)) {
+ Status = WriteMultipleByte (I2CAddress, Buffer, (*Length));
+ }
+
+ I2cCommonServiceExit (SaveCmd, SaveBar0);
+ return Status;
+}
+
+/**
+
+ The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte() function.
+ Provides a standard way to execute multiple byte writes to an I2C device
+ (e.g. when accessing sub-addresses or when reading block of data), as defined
+ in the I2C Specification (I2C combined write/read protocol).
+
+ @param SlaveAddress The I2C slave address of the device
+ with which to communicate.
+
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.
+
+ @param WriteLength No. of bytes to be written. In this case data
+ written typically contains sub-address or sub-addresses
+ in Hi-Lo format, that need to be read (I2C combined
+ write/read protocol).
+
+ @param ReadLength No. of bytes to be read from I2C slave device.
+
+ @param Buffer Contains the value of byte data read from the
+ I2C slave device.
+
+ @retval EFI_SUCCESS Transfer success.
+ @retval EFI_INVALID_PARAMETER This, WriteLength, ReadLength or Buffer
+ pointers are invalid.
+ @retval EFI_UNSUPPORTED Unsupported input param.
+ @retval EFI_TIMEOUT Timeout while waiting xfer.
+ @retval EFI_ABORTED Controller aborted xfer.
+ @retval EFI_DEVICE_ERROR Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadMultipleByte (
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,
+ IN EFI_I2C_ADDR_MODE AddrMode,
+ IN UINTN *WriteLength,
+ IN UINTN *ReadLength,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN I2CAddress;
+ UINT16 SaveCmd;
+ UINT32 SaveBar0;
+
+ if (Buffer == NULL || WriteLength == NULL || ReadLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SaveCmd = 0;
+ SaveBar0 =0;
+
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+ Status = EFI_SUCCESS;
+
+ I2CAddress = SlaveAddress.I2CDeviceAddress;
+ Status = InitializeInternal (AddrMode);
+ if (!EFI_ERROR(Status)) {
+ Status = ReadMultipleByte (I2CAddress, Buffer, (*WriteLength), (*ReadLength));
+ }
+ I2cCommonServiceExit (SaveCmd, SaveBar0);
+ return Status;
+}
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf b/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf
new file mode 100644
index 0000000000..8251756f73
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf
@@ -0,0 +1,68 @@
+## @file
+# Component description file for Quark South Cluster I2C library.
+#
+# I2C library implement QuarkSCSocId related drivers, includes:
+# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver.
+#
+# This driver contains I2C bus access routines:
+# 1. I2C Read (byte, multi-byte)
+# 2. I2C Write (byte, multi-byte)
+#
+# Copyright (c) 2013-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 = I2cLib
+ FILE_GUID = 462d127a-c143-469e-8449-b6e36beb04a8
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = I2cLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ CommonHeader.h
+ I2cLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ PcdLib
+ PciLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ DebugLib
+ BaseLib
+ TimerLib
+ IoLib
+ IohLib
+
+[FeaturePcd]
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdI2CFastModeEnabled
+
+[FixedPcd]
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohI2cMmioBase
+
+[Pcd]
+
+[Depex]
+ TRUE
diff --git a/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h b/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h
new file mode 100644
index 0000000000..9f4c6f2304
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h
@@ -0,0 +1,35 @@
+/** @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 <Ioh.h>
+#include <IohCommonDefinitions.h>
+
+#include <Library/IohLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CpuLib.h>
+#include <Library/PciCf8Lib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Pci22.h>
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c b/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c
new file mode 100644
index 0000000000..a48a2a4419
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c
@@ -0,0 +1,105 @@
+/** @file
+Lib function for Pei Quark South Cluster.
+
+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"
+
+/**
+ Program SVID/SID the same as VID/DID*
+**/
+EFI_STATUS
+EFIAPI
+InitializeIohSsvidSsid (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Func
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index <= IOH_PCI_IOSF2AHB_0_MAX_FUNCS; Index++) {
+ if (((Device == IOH_PCI_IOSF2AHB_1_DEV_NUM) && (Index >= IOH_PCI_IOSF2AHB_1_MAX_FUNCS))) {
+ continue;
+ }
+
+ IohMmPci32(0, Bus, Device, Index, PCI_REG_SVID0) = IohMmPci32(0, Bus, Device, Index, PCI_REG_VID);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* Enable memory, io, and bus master for USB controller */
+VOID
+EFIAPI
+EnableUsbMemIoBusMaster (
+ IN UINT8 UsbBusNumber
+ )
+{
+ UINT16 CmdReg;
+
+ CmdReg = PciRead16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, PCI_REG_PCICMD));
+ CmdReg = (UINT16) (CmdReg | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_BUS_MASTER);
+ PciWrite16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, PCI_REG_PCICMD), CmdReg);
+
+ CmdReg = PciRead16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, PCI_REG_PCICMD));
+ CmdReg = (UINT16) (CmdReg | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_BUS_MASTER);
+ PciWrite16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, PCI_REG_PCICMD), CmdReg);
+}
+
+/**
+ Read south cluster GPIO input from Port A.
+
+**/
+UINT32
+EFIAPI
+ReadIohGpioValues (
+ VOID
+ )
+{
+ UINT32 GipData;
+ UINT32 GipAddr;
+ UINT32 TempBarAddr;
+ UINT16 SaveCmdReg;
+ UINT32 SaveBarReg;
+
+ TempBarAddr = (UINT32) PcdGet64(PcdIohGpioMmioBase);
+
+ GipAddr = PCI_LIB_ADDRESS(
+ PcdGet8 (PcdIohGpioBusNumber),
+ PcdGet8 (PcdIohGpioDevNumber),
+ PcdGet8 (PcdIohGpioFunctionNumber), 0);
+
+ //
+ // Save current settings for PCI CMD/BAR registers.
+ //
+ SaveCmdReg = PciRead16 (GipAddr + PCI_COMMAND_OFFSET);
+ SaveBarReg = PciRead32 (GipAddr + PcdGet8 (PcdIohGpioBarRegister));
+
+ DEBUG ((EFI_D_INFO, "SC GPIO temporary enable at %08X\n", TempBarAddr));
+
+ // Use predefined tempory memory resource.
+ PciWrite32 ( GipAddr + PcdGet8 (PcdIohGpioBarRegister), TempBarAddr);
+ PciWrite8 ( GipAddr + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+
+ // Read GPIO configuration
+ GipData = MmioRead32(TempBarAddr + GPIO_EXT_PORTA);
+
+ //
+ // Restore settings for PCI CMD/BAR registers.
+ //
+ PciWrite32 ((GipAddr + PcdGet8 (PcdIohGpioBarRegister)), SaveBarReg);
+ PciWrite16 (GipAddr + PCI_COMMAND_OFFSET, SaveCmdReg);
+
+ // Only 8 bits valid.
+ return GipData & 0x000000FF;
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf b/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf
new file mode 100644
index 0000000000..eb7a4cb436
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf
@@ -0,0 +1,55 @@
+## @file
+# Intel Soc Library Instance
+#
+# Intel Soc 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 = IohLib
+ FILE_GUID = B4C12297-7B19-4523-B165-81374D96716B
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IohLib
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ IohLib.c
+ CommonHeader.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ PciLib
+ IoLib
+ PciCf8Lib
+ BaseLib
+ CpuLib
+
+[Pcd]
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioDevNumber
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioFunctionNumber
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBarRegister
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioMmioBase
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c
new file mode 100644
index 0000000000..6cc80d3028
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c
@@ -0,0 +1,233 @@
+/** @file
+
+UEFI Component Name(2) protocol implementation for SD controller 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 "SDController.h"
+
+
+//
+// EFI Component Name Protocol
+//
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSDControllerName = {
+ SDControllerGetDriverName,
+ SDControllerGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSDControllerName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SDControllerGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SDControllerGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSDControllerDriverNameTable[] = {
+ { "eng;en", L"EFI SD Host Controller Driver" },
+ { NULL, NULL }
+};
+
+
+//
+// EFI Component Name Functions
+//
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 3066 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSDControllerDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gSDControllerName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 3066 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ SDHOST_DATA *SDHostData;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSDControllerDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSDHostIoProtocolGuid,
+ (VOID **) &SDHostIo,
+ gSDControllerDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SDHostData = SDHOST_DATA_FROM_THIS(SDHostIo);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ SDHostData->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gSDControllerName)
+ );
+
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h
new file mode 100644
index 0000000000..afb690fe32
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h
@@ -0,0 +1,147 @@
+/** @file
+
+This file contains the delarations for componet name 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 _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 3066 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 3066 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c
new file mode 100644
index 0000000000..18e85c8299
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c
@@ -0,0 +1,1789 @@
+/** @file
+
+The SD host controller driver model and HC protocol 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.
+
+**/
+
+
+
+#include "SDController.h"
+
+
+EFI_DRIVER_BINDING_PROTOCOL gSDControllerDriverBinding = {
+ SDControllerSupported,
+ SDControllerStart,
+ SDControllerStop,
+ 0x20,
+ NULL,
+ NULL
+};
+
+
+EFI_SD_HOST_IO_PROTOCOL mSDHostIo = {
+ EFI_SD_HOST_IO_PROTOCOL_REVISION_01,
+ {
+ 0, // HighSpeedSupport
+ 0, // V18Support
+ 0, // V30Support
+ 0, // V33Support
+ 0, // Reserved0
+ 0, // BusWidth4
+ 0, // BusWidth8
+ 0, // Reserved1
+ 0, // Reserved1
+ (512 * 1024) //BoundarySize
+ },
+ SendCommand,
+ SetClockFrequency,
+ SetBusWidth,
+ SetHostVoltage,
+ ResetSDHost,
+ EnableAutoStopCmd,
+ DetectCardAndInitHost,
+ SetBlockLength,
+ SetHighSpeedMode,
+ SetDDRMode
+};
+
+/**
+ Find sdclk_freq_sel and upr_sdclk_freq_sel bits
+ for Clock Control Register (CLK_CTL)Offset 2Ch when using 8bit or 10bit
+ divided clock mode.
+
+ @param BaseClockFreg Base Clock Frequency in Hz For SD Clock in the
+ Capabilities register.
+ @param TargetFreq Target Frequency in Hz to reach.
+ @param Is8BitMode True if 8-bit Divided Clock Mode else 10bit mode.
+ @param Bits sdclk_freq_sel and upr_sdclk_freq_sel bits for
+ TargetFreq.
+
+ @return EFI_SUCCESS // Bits setup.
+ @return EFI_UNSUPPORTED // Cannot divide base clock to reach target clock.
+**/
+EFI_STATUS
+DividedClockModeBits (
+ IN CONST UINTN BaseClockFreg,
+ IN CONST UINTN TargetFreq,
+ IN CONST BOOLEAN Is8BitMode,
+ OUT UINT16 *Bits
+ )
+{
+ UINTN N;
+ UINTN CurrFreq;
+
+ *Bits = 0;
+ CurrFreq = BaseClockFreg;
+ N = 0;
+ //
+ // N == 0 same for 8bit & 10bit mode i.e. BaseClockFreg of controller.
+ //
+ if (TargetFreq < CurrFreq) {
+ if (Is8BitMode) {
+ N = 1;
+ do {
+ //
+ // N values for 8bit mode when N > 0.
+ // Bit[15:8] SDCLK Frequency Select at offset 2Ch
+ // 80h - base clock divided by 256
+ // 40h - base clock divided by 128
+ // 20h - base clock divided by 64
+ // 10h - base clock divided by 32
+ // 08h - base clock divided by 16
+ // 04h - base clock divided by 8
+ // 02h - base clock divided by 4
+ // 01h - base clock divided by 2
+ //
+ CurrFreq = BaseClockFreg / (2 * N);
+ if (TargetFreq >= CurrFreq) {
+ break;
+ }
+ N *= 2;
+ if (N > V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL) {
+ return EFI_UNSUPPORTED;
+ }
+ } while (TRUE);
+ } else {
+ N = 1;
+ CurrFreq = BaseClockFreg / (2 * N);
+ //
+ // (try N = 0 or 1 first since don't want divide by 0).
+ //
+ if (TargetFreq < CurrFreq) {
+ //
+ // If still no match then calculate it for 10bit.
+ // N values for 10bit mode.
+ // N 1/2N Divided Clock (Duty 50%).
+ // from Spec "The length of divider is extended to 10 bits and all
+ // divider values shall be supported.
+ //
+ N = (BaseClockFreg / TargetFreq) / 2;
+
+ //
+ // Can only be N or N+1;
+ //
+ CurrFreq = BaseClockFreg / (2 * N);
+ if (TargetFreq < CurrFreq) {
+ N++;
+ CurrFreq = BaseClockFreg / (2 * N);
+ }
+
+ if (N > V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set upper bits of SDCLK Frequency Select (bits 7:6 of reg 0x2c).
+ //
+ *Bits |= ((UINT16) ((N >> 2) & B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK));
+ }
+ }
+ }
+
+ //
+ // Set lower bits of SDCLK Frequency Select (bits 15:8 of reg 0x2c).
+ //
+ *Bits |= ((UINT16) ((UINT8) N) << 8);
+ DEBUG (
+ (EFI_D_INFO,
+ "SDIO:DividedClockModeBits: %dbit mode Want %dHz Got %dHz bits = %04x\r\n",
+ (Is8BitMode) ? 8 : 10,
+ TargetFreq,
+ CurrFreq,
+ (UINTN) *Bits
+ ));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Print type of error and command index
+
+ @param CommandIndex Command index to set the command index field of command register.
+ @param ErrorCode Error interrupt status read from host controller
+
+ @return EFI_DEVICE_ERROR
+ @return EFI_TIMEOUT
+ @return EFI_CRC_ERROR
+
+**/
+EFI_STATUS
+GetErrorReason (
+ IN UINT16 CommandIndex,
+ IN UINT16 ErrorCode
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_DEVICE_ERROR;
+
+ DEBUG((EFI_D_ERROR, "[%2d] -- ", CommandIndex));
+
+ if (ErrorCode & BIT0) {
+ Status = EFI_TIMEOUT;
+ DEBUG((EFI_D_ERROR, "Command Timeout Erro"));
+ }
+
+ if (ErrorCode & BIT1) {
+ Status = EFI_CRC_ERROR;
+ DEBUG((EFI_D_ERROR, "Command CRC Error"));
+ }
+
+ if (ErrorCode & BIT2) {
+ DEBUG((EFI_D_ERROR, "Command End Bit Error"));
+ }
+
+ if (ErrorCode & BIT3) {
+ DEBUG((EFI_D_ERROR, "Command Index Error"));
+ }
+ if (ErrorCode & BIT4) {
+ Status = EFI_TIMEOUT;
+ DEBUG((EFI_D_ERROR, "Data Timeout Error"));
+ }
+
+ if (ErrorCode & BIT5) {
+ Status = EFI_CRC_ERROR;
+ DEBUG((EFI_D_ERROR, "Data CRC Error"));
+ }
+
+ if (ErrorCode & BIT6) {
+ DEBUG((EFI_D_ERROR, "Data End Bit Error"));
+ }
+
+ if (ErrorCode & BIT7) {
+ DEBUG((EFI_D_ERROR, "Current Limit Error"));
+ }
+
+ if (ErrorCode & BIT8) {
+ DEBUG((EFI_D_ERROR, "Auto CMD12 Error"));
+ }
+
+ if (ErrorCode & BIT9) {
+ DEBUG((EFI_D_ERROR, "ADMA Error"));
+ }
+
+ DEBUG((EFI_D_ERROR, "\n"));
+
+ return Status;
+}
+/**
+ Enable/Disable High Speed transfer mode
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Enable TRUE to Enable, FALSE to Disable
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+SetHighSpeedMode (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ )
+{
+ UINT32 Data;
+ SDHOST_DATA *SDHostData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+ PciIo = SDHostData->PciIo;
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_HOSTCTL,
+ 1,
+ &Data
+ );
+
+ if (Enable) {
+ if (PcdGetBool(PcdSdHciQuirkNoHiSpd)) {
+ DEBUG ((EFI_D_INFO, "SDIO: Quirk never set High Speed Enable bit\r\n"));
+ return EFI_SUCCESS;
+ }
+ DEBUG ((EFI_D_INFO, "Enable High Speed transfer mode ... \r\n"));
+ Data |= BIT2;
+ } else {
+ Data &= ~BIT2;
+ }
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_HOSTCTL,
+ 1,
+ &Data
+ );
+ return EFI_SUCCESS;
+}
+EFI_STATUS
+EFIAPI
+SetDDRMode (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ )
+{
+ UINT16 Data;
+ SDHOST_DATA *SDHostData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+ PciIo = SDHostData->PciIo;
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_HOSTCTL2,
+ 1,
+ &Data
+ );
+ Data &= 0xFFF0;
+ if (Enable) {
+ Data |= 0x0004; // Enable DDR50 by default, later should enable other mode like HS200/400
+ Data |= BIT3; // Enable 1.8V Signaling
+ }
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_HOSTCTL2,
+ 1,
+ &Data
+ );
+ return EFI_SUCCESS;
+}
+/**
+ Power on/off the LED associated with the slot
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Enable TRUE to set LED on, FALSE to set LED off
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+HostLEDEnable (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ )
+{
+ SDHOST_DATA *SDHostData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 Data;
+
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+ PciIo = SDHostData->PciIo;
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_HOSTCTL,
+ 1,
+ &Data
+ );
+
+ if (Enable) {
+ //
+ //LED On
+ //
+ Data |= BIT0;
+ } else {
+ //
+ //LED Off
+ //
+ Data &= ~BIT0;
+ }
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_HOSTCTL,
+ 1,
+ &Data
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The main function used to send the command to the card inserted into the SD host slot.
+ It will assemble the arguments to set the command register and wait for the command
+ and transfer completed until timeout. Then it will read the response register to fill
+ the ResponseData.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param CommandIndex The command index to set the command index field of command register.
+ @param Argument Command argument to set the argument field of command register.
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.
+ @param Buffer Contains the data read from / write to the device.
+ @param BufferSize The size of the buffer.
+ @param ResponseType RESPONSE_TYPE.
+ @param TimeOut Time out value in 1 ms unit.
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_OUT_OF_RESOURCES
+ @retval EFI_TIMEOUT
+ @retval EFI_DEVICE_ERROR
+
+**/
+
+EFI_STATUS
+EFIAPI
+SendCommand (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData OPTIONAL
+ )
+/*++
+
+ Routine Description:
+ The main function used to send the command to the card inserted into the SD host
+ slot.
+ It will assemble the arguments to set the command register and wait for the command
+ and transfer completed until timeout. Then it will read the response register to fill
+ the ResponseData
+
+ Arguments:
+ This - Pointer to EFI_SD_HOST_IO_PROTOCOL
+ CommandIndex - The command index to set the command index field of command register
+ Argument - Command argument to set the argument field of command register
+ DataType - TRANSFER_TYPE, indicates no data, data in or data out
+ Buffer - Contains the data read from / write to the device
+ BufferSize - The size of the buffer
+ ResponseType - RESPONSE_TYPE
+ TimeOut - Time out value in 1 ms unit
+ ResponseData - Depending on the ResponseType, such as CSD or card status
+
+ Returns:
+ EFI_SUCCESS
+ EFI_INVALID_PARAMETER
+ EFI_OUT_OF_RESOURCES
+ EFI_TIMEOUT
+ EFI_DEVICE_ERROR
+
+--*/
+{
+ EFI_STATUS Status;
+ SDHOST_DATA *SDHostData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 ResponseDataCount;
+ UINT32 Data;
+ UINT64 Data64;
+ UINT8 Index;
+ INTN TimeOut2;
+ BOOLEAN AutoCMD12Enable = FALSE;
+
+
+ Status = EFI_SUCCESS;
+ ResponseDataCount = 1;
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+ PciIo = SDHostData->PciIo;
+ AutoCMD12Enable = (CommandIndex & AUTO_CMD12_ENABLE) ? TRUE : FALSE;
+ CommandIndex = CommandIndex & CMD_INDEX_MASK;
+
+ if (Buffer != NULL && DataType == NoData) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+ goto Exit;
+ }
+
+ if (((UINTN)Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN)NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+ goto Exit;
+ }
+
+ DEBUG ((EFI_D_INFO, "SendCommand: Command Index = %d \r\n", CommandIndex));
+ //
+ TimeOut2 = 1000; // 10 ms
+ do {
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ (UINT64)MMIO_PSTATE,
+ 1,
+ &Data
+ );
+ gBS->Stall (10);
+ }while ((TimeOut2-- > 0) && (Data & BIT0));
+ TimeOut2 = 1000; // 10 ms
+ do {
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ (UINT64)MMIO_PSTATE,
+ 1,
+ &Data
+ );
+ gBS->Stall (10);
+ }while ((TimeOut2-- > 0) && (Data & BIT1));
+ //Clear status bits
+ //
+ Data = 0xFFFF;
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_NINTSTS,
+ 1,
+ &Data
+ );
+
+ Data = 0xFFFF;
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_ERINTSTS,
+ 1,
+ &Data
+ );
+
+
+ if (Buffer != NULL) {
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ (UINT64)MMIO_DMAADR,
+ 1,
+ &Buffer
+ );
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_BLKSZ,
+ 1,
+ &Data
+ );
+ Data &= ~(0xFFF);
+ if (BufferSize <= SDHostData->BlockLength) {
+ Data |= (BufferSize | 0x7000);
+ } else {
+ Data |= (SDHostData->BlockLength | 0x7000);
+ }
+
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_BLKSZ,
+ 1,
+ &Data
+ );
+ if (BufferSize <= SDHostData->BlockLength) {
+ Data = 1;
+ } else {
+ Data = BufferSize / SDHostData->BlockLength;
+ }
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_BLKCNT,
+ 1,
+ &Data
+ );
+
+ } else {
+ Data = 0;
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_BLKSZ,
+ 1,
+ &Data
+ );
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_BLKCNT,
+ 1,
+ &Data
+ );
+ }
+
+ //
+ //Argument
+ //
+ Data = Argument;
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ (UINT64)MMIO_CMDARG,
+ 1,
+ &Data
+ );
+
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_XFRMODE,
+ 1,
+ &Data
+ );
+
+
+ DEBUG ((EFI_D_INFO, "Transfer mode read = 0x%x \r\n", (Data & 0xFFFF)));
+ //
+ //BIT0 - DMA Enable
+ //BIT2 - Auto Cmd12
+ //
+ if (DataType == InData) {
+ Data |= BIT4 | BIT0;
+ } else if (DataType == OutData){
+ Data &= ~BIT4;
+ Data |= BIT0;
+ } else {
+ Data &= ~(BIT4 | BIT0);
+ }
+
+ if (BufferSize <= SDHostData->BlockLength) {
+ Data &= ~ (BIT5 | BIT1 | BIT2);
+ Data |= BIT1; // Enable block count always
+ } else {
+ if (SDHostData->IsAutoStopCmd && AutoCMD12Enable) {
+ Data |= (BIT5 | BIT1 | BIT2);
+ } else {
+ Data |= (BIT5 | BIT1);
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Transfer mode write = 0x%x \r\n", (Data & 0xffff)));
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_XFRMODE,
+ 1,
+ &Data
+ );
+ //
+ //Command
+ //
+ //ResponseTypeSelect IndexCheck CRCCheck ResponseType
+ // 00 0 0 NoResponse
+ // 01 0 1 R2
+ // 10 0 0 R3, R4
+ // 10 1 1 R1, R5, R6, R7
+ // 11 1 1 R1b, R5b
+ //
+ switch (ResponseType) {
+ case ResponseNo:
+ Data = (CommandIndex << 8);
+ ResponseDataCount = 0;
+ break;
+
+ case ResponseR1:
+ case ResponseR5:
+ case ResponseR6:
+ case ResponseR7:
+ Data = (CommandIndex << 8) | BIT1 | BIT4| BIT3;
+ ResponseDataCount = 1;
+ break;
+
+ case ResponseR1b:
+ case ResponseR5b:
+ Data = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;
+ ResponseDataCount = 1;
+ break;
+
+ case ResponseR2:
+ Data = (CommandIndex << 8) | BIT0 | BIT3;
+ ResponseDataCount = 4;
+ break;
+
+ case ResponseR3:
+ case ResponseR4:
+ Data = (CommandIndex << 8) | BIT1;
+ ResponseDataCount = 1;
+ break;
+
+ default:
+ ASSERT (0);
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+ goto Exit;
+ }
+
+ if (DataType != NoData) {
+ Data |= BIT5;
+ }
+
+ HostLEDEnable (This, TRUE);
+
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_SDCMD,
+ 1,
+ &Data
+ );
+
+
+ Data = 0;
+ do {
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_ERINTSTS,
+ 1,
+ &Data
+ );
+
+ if ((Data & 0x07FF) != 0) {
+ Status = GetErrorReason (CommandIndex, (UINT16)Data);
+ DEBUG ((EFI_D_ERROR, "SendCommand: Error happens \r\n"));
+ goto Exit;
+ }
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_NINTSTS,
+ 1,
+ &Data
+ );
+
+ if ((Data & BIT0) == BIT0) {
+ //
+ //Command completed, can read response
+ //
+ if (DataType == NoData) {
+ break;
+ } else {
+ //
+ //Transfer completed
+ //
+ if ((Data & BIT1) == BIT1) {
+ break;
+ }
+ }
+ }
+
+ gBS->Stall (1 * 1000);
+
+ TimeOut --;
+
+ } while (TimeOut > 0);
+
+ if (TimeOut == 0) {
+ Status = EFI_TIMEOUT;
+ DEBUG ((EFI_D_ERROR, "SendCommand: Time out \r\n"));
+ goto Exit;
+ }
+
+ if (ResponseData != NULL) {
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ (UINT64)MMIO_RESP,
+ ResponseDataCount,
+ ResponseData
+ );
+ if (ResponseType == ResponseR2) {
+ //
+ // Adjustment for R2 response
+ //
+ Data = 1;
+ for (Index = 0; Index < ResponseDataCount; Index++) {
+ Data64 = LShiftU64(*ResponseData, 8);
+ *ResponseData = (UINT32)((Data64 & 0xFFFFFFFF) | Data);
+ Data = (UINT32)RShiftU64 (Data64, 32);
+ ResponseData++;
+ }
+ }
+ }
+
+Exit:
+ HostLEDEnable (This, FALSE);
+ return Status;
+}
+
+/**
+ Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+ It depends on the max frequency the host can support, divider, and host speed mode.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param MaxFrequency Max frequency in HZ.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 MaxFrequency
+ )
+{
+ UINT32 Data;
+ UINT16 FreqSelBits;
+ EFI_STATUS Status;
+ SDHOST_DATA *SDHostData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 TimeOutCount;
+ UINT32 Revision;
+
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+ PciIo = SDHostData->PciIo;
+ Data = 0;
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CLKCTL,
+ 1,
+ &Data
+ );
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_CTRLRVER,
+ 1,
+ &Revision
+ );
+ Revision &= 0x000000FF;
+
+ Status = DividedClockModeBits (
+ SDHostData->BaseClockInMHz * 1000 * 1000,
+ MaxFrequency,
+ (Revision < SDHCI_SPEC_300),
+ &FreqSelBits
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Cannot reach MaxFrequency with SDHostData->BaseClockInMHz.
+ //
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Data = 0;
+
+ //
+ //Enable internal clock and Stop Clock Enable
+ //
+ Data = BIT0;
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CLKCTL,
+ 1,
+ &Data
+ );
+
+ TimeOutCount = TIME_OUT_1S;
+ do {
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CLKCTL,
+ 1,
+ &Data
+ );
+ gBS->Stall (1 * 1000);
+ TimeOutCount --;
+ if (TimeOutCount == 0) {
+ DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));
+ return EFI_TIMEOUT;
+ }
+ } while ((Data & BIT1) != BIT1);
+
+ DEBUG ((EFI_D_INFO, "Base Clock In MHz: %d\r\n", SDHostData->BaseClockInMHz));
+
+ Data = (BIT0 | ((UINT32) FreqSelBits));
+ DEBUG ((EFI_D_INFO, "Data write to MMIO_CLKCTL: 0x%04x \r\n", Data));
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CLKCTL,
+ 1,
+ &Data
+ );
+
+ TimeOutCount = TIME_OUT_1S;
+ do {
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CLKCTL,
+ 1,
+ &Data
+ );
+ gBS->Stall (1 * 1000);
+ TimeOutCount --;
+ if (TimeOutCount == 0) {
+ DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));
+ return EFI_TIMEOUT;
+ }
+ } while ((Data & BIT1) != BIT1);
+ gBS->Stall (20 * 1000);
+ Data |= BIT2;
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CLKCTL,
+ 1,
+ &Data
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set bus width of the host controller
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param BusWidth Bus width in 1, 4, 8 bits.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 BusWidth
+ )
+{
+ SDHOST_DATA *SDHostData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Data;
+
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+
+
+ if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {
+ DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((SDHostData->SDHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {
+ DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PciIo = SDHostData->PciIo;
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_HOSTCTL,
+ 1,
+ &Data
+ );
+ //
+ // BIT5 8-bit MMC Support (MMC8):
+ // If set, IOH supports 8-bit MMC. When cleared, IOH does not support this feature
+ //
+ if (BusWidth == 8) {
+ DEBUG ((EFI_D_INFO, "Bus Width is 8-bit ... \r\n"));
+ Data |= BIT5;
+ } else if (BusWidth == 4) {
+ DEBUG ((EFI_D_INFO, "Bus Width is 4-bit ... \r\n"));
+ Data &= ~BIT5;
+ Data |= BIT1;
+ } else {
+ DEBUG ((EFI_D_INFO, "Bus Width is 1-bit ... \r\n"));
+ Data &= ~BIT5;
+ Data &= ~BIT1;
+ }
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_HOSTCTL,
+ 1,
+ &Data
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Set voltage which could supported by the host controller.
+ Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Voltage Units in 0.1 V.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 Voltage
+ )
+{
+ SDHOST_DATA *SDHostData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Data;
+ EFI_STATUS Status;
+
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+ PciIo = SDHostData->PciIo;
+ Status = EFI_SUCCESS;
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_PWRCTL,
+ 1,
+ &Data
+ );
+
+ if (Voltage == 0) {
+ //
+ //Power Off the host
+ //
+ Data &= ~BIT0;
+ } else if (Voltage <= 18 && This->HostCapability.V18Support) {
+ //
+ //1.8V
+ //
+ Data |= (BIT1 | BIT3 | BIT0);
+ } else if (Voltage > 18 && Voltage <= 30 && This->HostCapability.V30Support) {
+ //
+ //3.0V
+ //
+ Data |= (BIT2 | BIT3 | BIT0);
+ } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {
+ //
+ //3.3V
+ //
+ Data |= (BIT1 | BIT2 | BIT3 | BIT0);
+ } else {
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_PWRCTL,
+ 1,
+ &Data
+ );
+ gBS->Stall (10 * 1000);
+
+Exit:
+ return Status;
+}
+
+
+
+/**
+ Reset the host controller.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param ResetAll TRUE to reset all.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+ResetSDHost (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN RESET_TYPE ResetType
+ )
+{
+ SDHOST_DATA *SDHostData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 Data;
+ UINT16 ErrStatus;
+ UINT32 Mask;
+ UINT32 TimeOutCount;
+ UINT16 SaveClkCtl;
+ UINT16 ZeroClkCtl;
+
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+ PciIo = SDHostData->PciIo;
+ Mask = 0;
+ ErrStatus = 0;
+
+ if (ResetType == Reset_Auto) {
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_ERINTSTS,
+ 1,
+ &ErrStatus
+ );
+ if ((ErrStatus & 0xF) != 0) {
+ //
+ //Command Line
+ //
+ Mask |= BIT1;
+ }
+ if ((ErrStatus & 0x70) != 0) {
+ //
+ //Data Line
+ //
+ Mask |= BIT2;
+ }
+ }
+
+
+ if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {
+ Mask |= BIT2;
+ }
+ if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {
+ Mask |= BIT1;
+ }
+ if (ResetType == Reset_All) {
+ Mask = BIT0;
+ }
+
+ if (Mask == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // To improve SD stability, we zero the MMIO_CLKCTL register and
+ // stall for 50 microseconds before reseting the controller. We
+ // restore the register setting following the reset operation.
+ //
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CLKCTL,
+ 1,
+ &SaveClkCtl
+ );
+
+ ZeroClkCtl = (UINT16) 0;
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CLKCTL,
+ 1,
+ &ZeroClkCtl
+ );
+
+ gBS->Stall (50);
+
+ //
+ // Reset the SD host controller
+ //
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_SWRST,
+ 1,
+ &Mask
+ );
+
+ Data = 0;
+ TimeOutCount = TIME_OUT_1S;
+ do {
+
+ gBS->Stall (1 * 1000);
+
+ TimeOutCount --;
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_SWRST,
+ 1,
+ &Data
+ );
+ if ((Data & Mask) == 0) {
+ break;
+ }
+ } while (TimeOutCount > 0);
+
+ //
+ // We now restore the MMIO_CLKCTL register which we set to 0 above.
+ //
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CLKCTL,
+ 1,
+ &SaveClkCtl
+ );
+
+ if (TimeOutCount == 0) {
+ DEBUG ((EFI_D_ERROR, "ResetSDHost: Time out \r\n"));
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enable auto stop on the host controller.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Enable TRUE to enable, FALSE to disable.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ )
+{
+ SDHOST_DATA *SDHostData;
+
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+
+ SDHostData->IsAutoStopCmd = Enable;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the Block length on the host controller.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param BlockLength card supportes block length.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 BlockLength
+ )
+{
+ SDHOST_DATA *SDHostData;
+
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+
+ DEBUG ((EFI_D_INFO, "Block length on the host controller: %d \r\n", BlockLength));
+ SDHostData->BlockLength = BlockLength;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find whether these is a card inserted into the slot. If so init the host.
+ If not, return EFI_NOT_FOUND.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS
+ @retval EFI_NOT_FOUND
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+ IN EFI_SD_HOST_IO_PROTOCOL *This
+ )
+{
+ SDHOST_DATA *SDHostData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 Data;
+ EFI_STATUS Status;
+ UINT8 Voltages[] = { 33, 30, 18 };
+ UINTN Loop;
+
+ SDHostData = SDHOST_DATA_FROM_THIS (This);
+ PciIo = SDHostData->PciIo;
+ Status = EFI_NOT_FOUND;
+
+ Data = 0;
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ (UINT64)MMIO_PSTATE,
+ 1,
+ &Data
+ );
+
+ if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {
+ //
+ // Has no card inserted
+ //
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: No Cards \r\n"));
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: Find Cards \r\n"));
+
+ Status = EFI_NOT_FOUND;
+ for (Loop = 0; Loop < sizeof (Voltages); Loop++) {
+ DEBUG ((
+ EFI_D_INFO,
+ "DetectCardAndInitHost: SetHostVoltage %d.%dV \r\n",
+ Voltages[Loop] / 10,
+ Voltages[Loop] % 10
+ ));
+ Status = SetHostVoltage (This, Voltages[Loop]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [failed]\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [success]\n"));
+ break;
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set voltage \r\n"));
+ goto Exit;
+ }
+
+ Status = SetClockFrequency (This, FREQUENCY_OD);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set frequency \r\n"));
+ goto Exit;
+ }
+ SetBusWidth (This, 1);
+
+ //
+ //Enable normal status change
+ //
+
+ Data = (BIT0 | BIT1);
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_NINTEN,
+ 1,
+ &Data
+ );
+
+ //
+ //Enable error status change
+ //
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_ERINTEN,
+ 1,
+ &Data
+ );
+
+ Data |= (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_ERINTEN,
+ 1,
+ &Data
+ );
+
+ //
+ //Data transfer Timeout control
+ //
+ Data = 0x0E;
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ (UINT64)MMIO_TOCTL,
+ 1,
+ &Data
+ );
+ //
+ //Set Default Bus width as 1 bit
+ //
+
+Exit:
+ return Status;
+
+}
+
+/**
+ Entry point for EFI drivers.
+
+ @param ImageHandle EFI_HANDLE.
+ @param SystemTable EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Driver is successfully loaded.
+ @return Others Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSDController (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSDControllerDriverBinding,
+ ImageHandle,
+ &gSDControllerName,
+ &gSDControllerName2
+ );
+}
+
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has SDHostIoProtocol installed will be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS OpenStatus;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_CLASSC PciClass;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSDHostIoProtocolGuid,
+ (VOID **)&SdHostIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG (( DEBUG_INFO, "SdHost controller is already started\n"));
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Test whether there is PCI IO Protocol attached on the controller handle.
+ //
+ OpenStatus = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (OpenStatus)) {
+ return OpenStatus;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (PCI_CLASSC) / sizeof (UINT8),
+ &PciClass
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+ }
+
+ //
+ // Test whether the controller belongs to SD type
+ //
+ if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||
+ (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||
+ ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))
+ ) {
+
+ Status = EFI_UNSUPPORTED;
+ }
+
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+/**
+ Starting the SD Host Controller Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ SDHOST_DATA *SDHostData;
+ UINT32 Data;
+
+
+ SDHostData = NULL;
+ Data = 0;
+
+ //
+ // Open PCI I/O Protocol and save pointer to open protocol
+ // in private data area.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Enable the SD Host Controller MMIO space
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+
+ SDHostData = (SDHOST_DATA*)AllocateZeroPool(sizeof (SDHOST_DATA));
+ if (SDHostData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ SDHostData->Signature = SDHOST_DATA_SIGNATURE;
+ SDHostData->PciIo = PciIo;
+
+ CopyMem (&SDHostData->SDHostIo, &mSDHostIo, sizeof (EFI_SD_HOST_IO_PROTOCOL));
+
+ ResetSDHost (&SDHostData->SDHostIo, Reset_All);
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0,
+ (UINT64)MMIO_CTRLRVER,
+ 1,
+ &Data
+ );
+ SDHostData->SDHostIo.HostCapability.HostVersion = Data & 0xFF;
+ DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: HostVersion 0x%x \r\n", SDHostData->SDHostIo.HostCapability.HostVersion));
+
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ (UINT64)MMIO_CAP,
+ 1,
+ &Data
+ );
+ DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: MMIO_CAP 0x%x \r\n", Data));
+ if ((Data & BIT18) != 0) {
+ SDHostData->SDHostIo.HostCapability.BusWidth8 = TRUE;
+ }
+
+ if ((Data & BIT21) != 0) {
+ SDHostData->SDHostIo.HostCapability.HighSpeedSupport = TRUE;
+ }
+
+ if ((Data & BIT24) != 0) {
+ SDHostData->SDHostIo.HostCapability.V33Support = TRUE;
+ }
+
+ if ((Data & BIT25) != 0) {
+ SDHostData->SDHostIo.HostCapability.V30Support = TRUE;
+ }
+
+ if ((Data & BIT26) != 0) {
+ SDHostData->SDHostIo.HostCapability.V18Support = TRUE;
+ }
+
+ SDHostData->SDHostIo.HostCapability.BusWidth4 = TRUE;
+
+ if(SDHostData->SDHostIo.HostCapability.HostVersion < SDHCI_SPEC_300) {
+
+
+
+ SDHostData->BaseClockInMHz = (Data >> 8) & 0x3F;
+ }
+ else {
+ SDHostData->BaseClockInMHz = (Data >> 8) & 0xFF;
+
+ }
+
+ SDHostData->BlockLength = 512 << ((Data >> 16) & 0x03);
+ DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: BlockLength 0x%x \r\n", SDHostData->BlockLength));
+ SDHostData->IsAutoStopCmd = TRUE;
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiSDHostIoProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &SDHostData->SDHostIo
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Install the component name protocol
+ //
+ SDHostData->ControllerNameTable = NULL;
+
+ AddUnicodeString2 (
+ "eng",
+ gSDControllerName.SupportedLanguages,
+ &SDHostData->ControllerNameTable,
+ L"SD Host Controller",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gSDControllerName2.SupportedLanguages,
+ &SDHostData->ControllerNameTable,
+ L"SD Host Controller",
+ FALSE
+ );
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ if (SDHostData != NULL) {
+ FreePool (SDHostData);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ SDHOST_DATA *SDHostData;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSDHostIoProtocolGuid,
+ (VOID **) &SDHostIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ //
+ // Test whether the Controller handler passed in is a valid
+ // Usb controller handle that should be supported, if not,
+ // return the error status directly
+ //
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SetHostVoltage (SDHostIo, 0);
+
+ SDHostData = SDHOST_DATA_FROM_THIS(SDHostIo);
+
+ //
+ // Uninstall Block I/O protocol from the device handle
+ //
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSDHostIoProtocolGuid,
+ SDHostIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FreeUnicodeStringTable (SDHostData->ControllerNameTable);
+
+ FreePool (SDHostData);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h
new file mode 100644
index 0000000000..d5302bac10
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h
@@ -0,0 +1,322 @@
+/** @file
+
+The definition for SD host controller driver model and HC protocol 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 _SD_CONTROLLER_H_
+#define _SD_CONTROLLER_H_
+
+
+#include <Uefi.h>
+
+
+#include <Protocol/PciIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Pci22.h>
+
+
+#include "ComponentName.h"
+#include "SDHostIo.h"
+
+
+extern EFI_DRIVER_BINDING_PROTOCOL gSDControllerDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gSDControllerName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSDControllerName2;
+
+
+#define SDHOST_DATA_SIGNATURE SIGNATURE_32 ('s', 'd', 'h', 's')
+
+#define BLOCK_SIZE 0x200
+#define TIME_OUT_1S 1000
+
+#pragma pack(1)
+//
+// PCI Class Code structure
+//
+typedef struct {
+ UINT8 PI;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+} PCI_CLASSC;
+
+#pragma pack()
+
+
+typedef struct {
+ UINTN Signature;
+ EFI_SD_HOST_IO_PROTOCOL SDHostIo;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ BOOLEAN IsAutoStopCmd;
+ UINT32 BaseClockInMHz;
+ UINT32 CurrentClockInKHz;
+ UINT32 BlockLength;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+}SDHOST_DATA;
+
+#define SDHOST_DATA_FROM_THIS(a) \
+ CR(a, SDHOST_DATA, SDHostIo, SDHOST_DATA_SIGNATURE)
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has SDHostIoProtocol installed will be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starting the SD Host Controller Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+EFIAPI
+SDControllerStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ The main function used to send the command to the card inserted into the SD host slot.
+ It will assemble the arguments to set the command register and wait for the command
+ and transfer completed until timeout. Then it will read the response register to fill
+ the ResponseData.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param CommandIndex The command index to set the command index field of command register.
+ @param Argument Command argument to set the argument field of command register.
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.
+ @param Buffer Contains the data read from / write to the device.
+ @param BufferSize The size of the buffer.
+ @param ResponseType RESPONSE_TYPE.
+ @param TimeOut Time out value in 1 ms unit.
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_OUT_OF_RESOURCES
+ @retval EFI_TIMEOUT
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData OPTIONAL
+ );
+
+/**
+ Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+ It depends on the max frequency the host can support, divider, and host speed mode.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param MaxFrequency Max frequency in HZ.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 MaxFrequencyInKHz
+ );
+
+/**
+ Set bus width of the host controller
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param BusWidth Bus width in 1, 4, 8 bits.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 BusWidth
+ );
+
+
+/**
+ Set voltage which could supported by the host controller.
+ Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Voltage Units in 0.1 V.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 Voltage
+ );
+
+
+/**
+ Reset the host controller.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param ResetAll TRUE to reset all.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+ResetSDHost (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN RESET_TYPE ResetType
+ );
+
+
+/**
+ Enable auto stop on the host controller.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Enable TRUE to enable, FALSE to disable.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ );
+
+/**
+ Find whether these is a card inserted into the slot. If so init the host.
+ If not, return EFI_NOT_FOUND.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS
+ @retval EFI_NOT_FOUND
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+ IN EFI_SD_HOST_IO_PROTOCOL *This
+ );
+
+/**
+ Set the Block length on the host controller.
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param BlockLength card supportes block length.
+
+ @retval EFI_SUCCESS
+ @retval EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT32 BlockLength
+ );
+
+/**
+ Enable/Disable High Speed transfer mode
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param Enable TRUE to Enable, FALSE to Disable
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+SetHighSpeedMode (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ );
+
+EFI_STATUS
+EFIAPI
+SetDDRMode (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN BOOLEAN Enable
+ );
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf
new file mode 100644
index 0000000000..3cbe2330a3
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf
@@ -0,0 +1,62 @@
+## @file
+#
+# Component Description File For SDControllerDxe 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 = SDController
+ FILE_GUID = 90A330BD-6F89-4900-933A-C25EB4356348
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeSDController
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gSDControllerDriverBinding
+# COMPONENT_NAME = gSDControllerName
+# COMPONENT_NAME2 = gSDControllerName2
+#
+
+[Sources]
+ SDController.c
+ SDController.h
+ ComponentName.c
+ ComponentName.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiSDHostIoProtocolGuid ## BY_START
+
+[FeaturePcd]
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdSdHciQuirkNoHiSpd
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c
new file mode 100644
index 0000000000..0261295cbf
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c
@@ -0,0 +1,656 @@
+/** @file
+
+CEATA specific functions implementation
+
+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 "SDMediaDevice.h"
+
+/**
+ Send RW_MULTIPLE_REGISTER command
+
+ @param CardData Pointer to CARD_DATA.
+ @param Address Register address.
+ @param ByteCount Buffer size.
+ @param Write TRUE means write, FALSE means read.
+ @param Buffer Buffer pointer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+ReadWriteMultipleRegister (
+ IN CARD_DATA *CardData,
+ IN UINT16 Address,
+ IN UINT8 ByteCount,
+ IN BOOLEAN Write,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Argument;
+
+ Status = EFI_SUCCESS;
+
+ if ((Address % 4 != 0) || (ByteCount % 4 != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Argument = (Address << 16) | ByteCount;
+ if (Write) {
+ Argument |= BIT31;
+ }
+
+
+ if (Write) {
+ CopyMem (CardData->AlignedBuffer, Buffer, ByteCount);
+
+ Status = SendCommand (
+ CardData,
+ RW_MULTIPLE_REGISTER,
+ Argument,
+ OutData,
+ CardData->AlignedBuffer,
+ ByteCount,
+ ResponseR1b,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ } else {
+ Status = SendCommand (
+ CardData,
+ RW_MULTIPLE_REGISTER,
+ Argument,
+ InData,
+ CardData->AlignedBuffer,
+ ByteCount,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ CopyMem (Buffer, CardData->AlignedBuffer, ByteCount);
+ }
+
+ }
+Exit:
+ return Status;
+}
+
+/**
+ Send ReadWriteMultipleBlock command with RW_MULTIPLE_REGISTER command
+
+ @param CardData Pointer to CARD_DATA.
+ @param DataUnitCount Buffer size in 512 bytes unit.
+ @param Write TRUE means write, FALSE means read.
+ @param Buffer Buffer pointer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+ReadWriteMultipleBlock (
+ IN CARD_DATA *CardData,
+ IN UINT16 DataUnitCount,
+ IN BOOLEAN Write,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ UINT32 TransferLength;
+
+ Status = EFI_SUCCESS;
+ SDHostIo = CardData->SDHostIo;
+
+ TransferLength = DataUnitCount * DATA_UNIT_SIZE;
+ if (TransferLength > SDHostIo->HostCapability.BoundarySize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Write) {
+ CopyMem (CardData->AlignedBuffer, Buffer, TransferLength);
+
+ Status = SendCommand (
+ CardData,
+ RW_MULTIPLE_BLOCK,
+ (DataUnitCount | BIT31),
+ OutData,
+ CardData->AlignedBuffer,
+ TransferLength,
+ ResponseR1b,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ } else {
+ Status = SendCommand (
+ CardData,
+ RW_MULTIPLE_BLOCK,
+ DataUnitCount,
+ InData,
+ CardData->AlignedBuffer,
+ TransferLength,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ CopyMem (Buffer, CardData->AlignedBuffer, TransferLength);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send software reset
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+SoftwareReset (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+ UINT32 TimeOut;
+
+ Data = BIT2;
+
+ Status = FastIO (CardData, Reg_Control, &Data, TRUE);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ TimeOut = 5 * 1000;
+
+ do {
+ gBS->Stall (1 * 1000);
+ Status = FastIO (CardData, Reg_Control, &Data, FALSE);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ if ((Data & BIT2) == BIT2) {
+ break;
+ }
+
+ TimeOut--;
+ } while (TimeOut > 0);
+
+ if (TimeOut == 0) {
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+
+ Data &= ~BIT2;
+ Status = FastIO (CardData, Reg_Control, &Data, TRUE);
+
+ TimeOut = 5 * 1000;
+
+ do {
+ gBS->Stall (1 * 1000);
+ Status = FastIO (CardData, Reg_Control, &Data, FALSE);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ if ((Data & BIT2) != BIT2) {
+ break;
+ }
+
+ TimeOut--;
+ } while (TimeOut > 0);
+
+
+ if (TimeOut == 0) {
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+
+
+Exit:
+ return Status;
+}
+
+
+/**
+ SendATACommand specificed in Taskfile
+
+ @param CardData Pointer to CARD_DATA.
+ @param TaskFile Pointer to TASK_FILE.
+ @param Write TRUE means write, FALSE means read.
+ @param Buffer If NULL, means no data transfer, neither read nor write.
+ @param SectorCount Buffer size in 512 bytes unit.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+SendATACommand (
+ IN CARD_DATA *CardData,
+ IN TASK_FILE *TaskFile,
+ IN BOOLEAN Write,
+ IN UINT8 *Buffer,
+ IN UINT16 SectorCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ UINT8 Data;
+ UINT32 TimeOut;
+
+ SDHostIo = CardData->SDHostIo;
+
+ //
+ //Write register
+ //
+ Status = ReadWriteMultipleRegister (
+ CardData,
+ 0,
+ sizeof (TASK_FILE),
+ TRUE,
+ (UINT8*)TaskFile
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister 0x%x\n", Status));
+ goto Exit;
+ }
+
+ TimeOut = 5000;
+ do {
+ gBS->Stall (1 * 1000);
+ Data = 0;
+ Status = FastIO (
+ CardData,
+ Reg_Command_Status,
+ &Data,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (((Data & BIT7) == 0) && ((Data & BIT6) == BIT6)) {
+ break;
+ }
+
+ TimeOut --;
+ } while (TimeOut > 0);
+
+ if (TimeOut == 0) {
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister FastIO EFI_TIMEOUT 0x%x\n", Data));
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+
+
+ if (Buffer != NULL) {
+ Status = ReadWriteMultipleBlock (
+ CardData,
+ SectorCount,
+ Write,
+ (UINT8*)Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock EFI_TIMEOUT 0x%x\n", Status));
+ goto Exit;
+ }
+
+ TimeOut = 5 * 1000;
+ do {
+ gBS->Stall (1 * 1000);
+
+ Data = 0;
+ Status = FastIO (
+ CardData,
+ Reg_Command_Status,
+ &Data,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (((Data & BIT7) == 0) && ((Data & BIT3) == 0)) {
+ break;
+ }
+
+ TimeOut --;
+ } while (TimeOut > 0);
+ if (TimeOut == 0) {
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock FastIO EFI_TIMEOUT 0x%x\n", Data));
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+
+
+ if (((Data & BIT6) == BIT6) && (Data & BIT0) == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ SoftwareReset (CardData);
+ }
+
+ return Status;
+}
+
+/**
+ IDENTIFY_DEVICE command
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+IndentifyDevice (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+ //
+ //The host only supports nIEN = 0
+ //
+ CardData->TaskFile.Command_Status = IDENTIFY_DEVICE;
+
+
+ Status = SendATACommand (
+ CardData,
+ &CardData->TaskFile,
+ FALSE,
+ (UINT8*)&(CardData->IndentifyDeviceData),
+ 1
+ );
+
+
+ return Status;
+}
+
+/**
+ FLUSH_CACHE_EXT command
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+FlushCache (
+ IN CARD_DATA *CardData
+ )
+{
+
+ //
+ //Hitachi CE-ATA will always make the busy high after
+ //receving this command
+ //
+/*
+ EFI_STATUS Status;
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+ //
+ //The host only supports nIEN = 0
+ //
+ CardData->TaskFile.Command_Status = FLUSH_CACHE_EXT;
+
+ Status = SendATACommand (
+ CardData,
+ &CardData->TaskFile,
+ FALSE,
+ NULL,
+ 0
+ );
+*/
+ return EFI_SUCCESS;
+}
+
+/**
+ STANDBY_IMMEDIATE command
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+StandByImmediate (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+ //
+ //The host only supports nIEN = 0
+ //
+ CardData->TaskFile.Command_Status = STANDBY_IMMEDIATE;
+
+
+ Status = SendATACommand (
+ CardData,
+ &CardData->TaskFile,
+ FALSE,
+ NULL,
+ 0
+ );
+ return Status;
+}
+
+/**
+ READ_DMA_EXT command
+
+ @param CardData Pointer to CARD_DATA.
+ @param LBA The starting logical block address to read from on the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the buffer.
+ @param SectorCount Size in 512 bytes unit.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+ReadDMAExt (
+ IN CARD_DATA *CardData,
+ IN EFI_LBA LBA,
+ IN UINT8 *Buffer,
+ IN UINT16 SectorCount
+ )
+{
+
+ EFI_STATUS Status;
+
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+ //
+ //The host only supports nIEN = 0
+ //
+ CardData->TaskFile.Command_Status = READ_DMA_EXT;
+
+ CardData->TaskFile.SectorCount = (UINT8)SectorCount;
+ CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);
+
+ CardData->TaskFile.LBALow = (UINT8)LBA;
+ CardData->TaskFile.LBAMid = (UINT8)RShiftU64(LBA, 8);
+ CardData->TaskFile.LBAHigh = (UINT8)RShiftU64(LBA, 16);
+
+ CardData->TaskFile.LBALow_Exp = (UINT8)RShiftU64(LBA, 24);
+ CardData->TaskFile.LBAMid_Exp = (UINT8)RShiftU64(LBA, 32);
+ CardData->TaskFile.LBAHigh_Exp = (UINT8)RShiftU64(LBA, 40);
+
+ Status = SendATACommand (
+ CardData,
+ &CardData->TaskFile,
+ FALSE,
+ Buffer,
+ SectorCount
+ );
+ return Status;
+
+}
+
+/**
+ WRITE_DMA_EXT command
+
+ @param CardData Pointer to CARD_DATA.
+ @param LBA The starting logical block address to read from on the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the buffer.
+ @param SectorCount Size in 512 bytes unit.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+WriteDMAExt (
+ IN CARD_DATA *CardData,
+ IN EFI_LBA LBA,
+ IN UINT8 *Buffer,
+ IN UINT16 SectorCount
+ )
+{
+
+ EFI_STATUS Status;
+
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+ //
+ //The host only supports nIEN = 0
+ //
+ CardData->TaskFile.Command_Status = WRITE_DMA_EXT;
+
+ CardData->TaskFile.SectorCount = (UINT8)SectorCount;
+ CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);
+
+ CardData->TaskFile.LBALow = (UINT8)LBA;
+ CardData->TaskFile.LBAMid = (UINT8)RShiftU64(LBA, 8);
+ CardData->TaskFile.LBAHigh = (UINT8)RShiftU64(LBA, 16);
+
+ CardData->TaskFile.LBALow_Exp = (UINT8)RShiftU64(LBA, 24);
+ CardData->TaskFile.LBAMid_Exp = (UINT8)RShiftU64(LBA, 32);
+ CardData->TaskFile.LBAHigh_Exp = (UINT8)RShiftU64(LBA, 40);
+
+ Status = SendATACommand (
+ CardData,
+ &CardData->TaskFile,
+ TRUE,
+ Buffer,
+ SectorCount
+ );
+ return Status;
+
+}
+
+
+/**
+ Judge whether it is CE-ATA device or not.
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval TRUE
+ @retval FALSE
+
+**/
+BOOLEAN
+IsCEATADevice (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+
+ Status = ReadWriteMultipleRegister (
+ CardData,
+ 0,
+ sizeof (TASK_FILE),
+ FALSE,
+ (UINT8*)&CardData->TaskFile
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ //To bring back the normal MMC card to work
+ //
+ CardData->SDHostIo->ResetSDHost (CardData->SDHostIo, Reset_DAT_CMD);
+ return FALSE;
+ }
+
+ if (CardData->TaskFile.LBAMid == CE_ATA_SIG_CE &&
+ CardData->TaskFile.LBAHigh == CE_ATA_SIG_AA
+ ) {
+ //
+ //Disable Auto CMD for CE-ATA
+ //
+ CardData->SDHostIo->EnableAutoStopCmd (CardData->SDHostIo, FALSE);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c
new file mode 100644
index 0000000000..a9addecf39
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c
@@ -0,0 +1,396 @@
+/** @file
+
+Block I/O protocol for CE-ATA device
+
+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 "SDMediaDevice.h"
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive.
+ verification operation of the device during reset.
+ (This parameter is ingored in this driver.)
+
+ @retval EFI_SUCCESS Success
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ CARD_DATA *CardData;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+
+ CardData = CARD_DATA_FROM_THIS(This);
+ SDHostIo = CardData->SDHostIo;
+
+ if (!ExtendedVerification) {
+ Status = SoftwareReset (CardData);
+ } else {
+ Status = SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" ));
+ return Status;
+ }
+ Status = MMCSDCardInit (CardData);
+ }
+
+
+ return Status;
+
+ }
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.
+ @param MediaId The media id that the write request is for.
+ @param LBA The starting logical block address to read from on the device.
+ The caller is responsible for writing to only legitimate locations.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the
+ intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ CARD_DATA *CardData;
+ UINT32 TransferSize;
+ UINT8 *pBuf;
+ UINT32 Index;
+ UINT64 Address;
+ UINT32 Remainder;
+ UINT64 CEATALBA;
+ UINT32 BoundarySize;
+
+ Status = EFI_SUCCESS;
+ CardData = CARD_DATA_FROM_THIS(This);
+ pBuf = Buffer;
+ Index = 0;
+ Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
+ BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
+
+ if (!Buffer) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
+ goto Exit;
+ }
+
+ if (MediaId != CardData->BlockIoMedia.MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" ));
+ goto Exit;
+ }
+
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" ));
+ goto Exit;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+
+ if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
+ goto Exit;
+ }
+
+
+ do {
+ if (BufferSize < BoundarySize) {
+ TransferSize = (UINT32)BufferSize;
+ } else {
+ TransferSize = BoundarySize;
+ }
+
+ Address += Index * TransferSize;
+ CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
+ ASSERT(Remainder == 0);
+
+ Status = ReadDMAExt (
+ CardData,
+ CEATALBA,
+ pBuf,
+ (UINT16)(TransferSize / DATA_UNIT_SIZE)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
+ This->Reset (This, TRUE);
+ goto Exit;
+ }
+ BufferSize -= TransferSize;
+ pBuf += TransferSize;
+ Index ++;
+ } while (BufferSize != 0);
+
+
+Exit:
+ return Status;
+}
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.
+ @param MediaId The media id that the write request is for.
+ @param LBA The starting logical block address to read from on the device.
+ The caller is responsible for writing to only legitimate locations.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the
+ intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ CARD_DATA *CardData;
+ UINT32 TransferSize;
+ UINT8 *pBuf;
+ UINT32 Index;
+ UINT64 Address;
+ UINT32 Remainder;
+ UINT64 CEATALBA;
+ UINT32 BoundarySize;
+
+
+ Status = EFI_SUCCESS;
+ CardData = CARD_DATA_FROM_THIS(This);
+ pBuf = Buffer;
+ Index = 0;
+ Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);
+ BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;
+
+
+ if (!Buffer) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (MediaId != CardData->BlockIoMedia.MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Exit;
+ }
+
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Exit;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+
+ if (CardData->BlockIoMedia.ReadOnly) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Exit;
+ }
+
+ if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ CardData->NeedFlush = TRUE;
+
+ do {
+ if (BufferSize < BoundarySize) {
+ TransferSize = (UINT32)BufferSize;
+ } else {
+ TransferSize = BoundarySize;
+ }
+
+ Address += Index * TransferSize;
+ CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
+ ASSERT(Remainder == 0);
+
+ Status = WriteDMAExt (
+ CardData,
+ CEATALBA,
+ pBuf,
+ (UINT16)(TransferSize / DATA_UNIT_SIZE)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
+ This->Reset (This, TRUE);
+ goto Exit;
+ }
+ BufferSize -= TransferSize;
+ pBuf += TransferSize;
+ Index ++;
+ } while (BufferSize != 0);
+
+
+Exit:
+ return Status;
+}
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+ (In this driver, this function just returns EFI_SUCCESS.)
+
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS
+ @retval Others
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+
+ EFI_STATUS Status;
+ CARD_DATA *CardData;
+
+ CardData = CARD_DATA_FROM_THIS(This);
+
+ if (CardData->NeedFlush) {
+ CardData->NeedFlush = FALSE;
+ Status = FlushCache (CardData);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ CEATA card BlockIo init function.
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS
+ @retval Others
+**/
+EFI_STATUS
+CEATABlockIoInit (
+ IN CARD_DATA *CardData
+ )
+/*++
+
+ Routine Description:
+ CEATA card BlockIo init function
+
+ Arguments:
+ CardData - Pointer to CARD_DATA
+
+ Returns:
+ EFI_SUCCESS - Success
+--*/
+{
+ EFI_STATUS Status;
+ UINT64 MaxSize;
+ UINT32 Remainder;
+ //
+ //BlockIO protocol
+ //
+ CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
+ CardData->BlockIo.Media = &(CardData->BlockIoMedia);
+ CardData->BlockIo.Reset = CEATABlockReset;
+ CardData->BlockIo.ReadBlocks = CEATABlockReadBlocks ;
+ CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks;
+ CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks;
+
+ CardData->BlockIoMedia.MediaId = 0;
+ CardData->BlockIoMedia.RemovableMedia = FALSE;
+ CardData->BlockIoMedia.MediaPresent = TRUE;
+ CardData->BlockIoMedia.LogicalPartition = FALSE;
+
+ if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) {
+ CardData->BlockIoMedia.ReadOnly = TRUE;
+ } else {
+ CardData->BlockIoMedia.ReadOnly = FALSE;
+ }
+
+
+ CardData->BlockIoMedia.WriteCaching = FALSE;
+ CardData->BlockIoMedia.IoAlign = 1;
+
+ Status = IndentifyDevice (CardData);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ //Some device does not support this feature
+ //
+
+ if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) {
+ CardData->BlockIoMedia.ReadOnly = TRUE;
+ }
+
+ CardData->BlockIoMedia.BlockSize = (1 << CardData->IndentifyDeviceData.Sectorsize);
+ ASSERT(CardData->BlockIoMedia.BlockSize >= 12);
+
+
+ MaxSize = *(UINT64*)(CardData->IndentifyDeviceData.MaximumLBA);
+ MaxSize = MultU64x32 (MaxSize, 512);
+
+ Remainder = 0;
+ CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder);
+ ASSERT(Remainder == 0);
+
+ CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1);
+
+
+Exit:
+ return Status;
+
+}
+
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c
new file mode 100644
index 0000000000..a047e85c3c
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c
@@ -0,0 +1,221 @@
+/** @file
+
+UEFI Component Name(2) protocol implementation for SD media device 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 "SDMediaDevice.h"
+
+
+//
+// EFI Component Name Protocol
+//
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSDMediaDeviceName = {
+ SDMediaDeviceGetDriverName,
+ SDMediaDeviceGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSDMediaDeviceName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SDMediaDeviceGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SDMediaDeviceGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSDMediaDeviceDriverNameTable[] = {
+ { "eng;en", L"UEFI MMC/SD Media Device Driver" },
+ { NULL, NULL }
+};
+
+
+//
+// EFI Component Name Functions
+//
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 3066 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSDMediaDeviceDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gSDMediaDeviceName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 3066 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ CARD_DATA *CardData;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gSDMediaDeviceDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CardData = CARD_DATA_FROM_THIS (BlockIo);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ CardData->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gSDMediaDeviceName)
+ );
+
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h
new file mode 100644
index 0000000000..51820388cc
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h
@@ -0,0 +1,145 @@
+/** @file
+
+This file contains the delarations for componet name 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 _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 3066 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 3066 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c
new file mode 100644
index 0000000000..584c541f71
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c
@@ -0,0 +1,544 @@
+/** @file
+
+Block I/O protocol for MMC/SD device
+
+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 "SDMediaDevice.h"
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive.
+ verification operation of the device during reset.
+ (This parameter is ingored in this driver.)
+
+ @retval EFI_SUCCESS Success
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ CARD_DATA *CardData;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+
+ CardData = CARD_DATA_FROM_THIS(This);
+ SDHostIo = CardData->SDHostIo;
+
+ return SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
+ }
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.
+ @param MediaId The media id that the write request is for.
+ @param LBA The starting logical block address to read from on the device.
+ The caller is responsible for writing to only legitimate locations.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the
+ intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Address;
+ CARD_DATA *CardData;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ UINT32 RemainingLength;
+ UINT32 TransferLength;
+ UINT8 *BufferPointer;
+ BOOLEAN SectorAddressing;
+ UINTN TotalBlock;
+
+ DEBUG((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
+ Status = EFI_SUCCESS;
+ CardData = CARD_DATA_FROM_THIS(This);
+ SDHostIo = CardData->SDHostIo;
+ if (MediaId != CardData->BlockIoMedia.MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (ModU64x32 (BufferSize,CardData->BlockIoMedia.BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
+ SectorAddressing = TRUE;
+ } else {
+ SectorAddressing = FALSE;
+ }
+ if (SectorAddressing) {
+ //
+ //Block Address
+ //
+ Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
+ } else {
+ //
+ //Byte Address
+ //
+ Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+ }
+ TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);
+ if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ if (!Buffer) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));
+ goto Done;
+ }
+
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));
+ goto Done;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+
+
+
+ BufferPointer = Buffer;
+ RemainingLength = (UINT32)BufferSize;
+
+ while (RemainingLength > 0) {
+ if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {
+ if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
+ TransferLength = SDHostIo->HostCapability.BoundarySize;
+ } else {
+ TransferLength = RemainingLength;
+ }
+
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+ if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
+ Status = SendCommand (
+ CardData,
+ SET_BLOCKLEN,
+ CardData->BlockIoMedia.BlockSize,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ Status = SendCommand (
+ CardData,
+ SET_BLOCK_COUNT,
+ TransferLength / CardData->BlockIoMedia.BlockSize,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ Status = SendCommand (
+ CardData,
+ READ_MULTIPLE_BLOCK,
+ Address,
+ InData,
+ CardData->AlignedBuffer,
+ TransferLength,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
+ break;
+ }
+ } else {
+ if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
+ TransferLength = CardData->BlockIoMedia.BlockSize;
+ } else {
+ TransferLength = RemainingLength;
+ }
+
+ Status = SendCommand (
+ CardData,
+ READ_SINGLE_BLOCK,
+ Address,
+ InData,
+ CardData->AlignedBuffer,
+ (UINT32)TransferLength,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
+ break;
+ }
+ }
+ CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
+
+ if (SectorAddressing) {
+ //
+ //Block Address
+ //
+ Address += TransferLength / 512;
+ } else {
+ //
+ //Byte Address
+ //
+ Address += TransferLength;
+ }
+ BufferPointer += TransferLength;
+ RemainingLength -= TransferLength;
+ }
+
+
+ if (EFI_ERROR (Status)) {
+ if ((CardData->CardType == SDMemoryCard) ||
+ (CardData->CardType == SDMemoryCard2)||
+ (CardData->CardType == SDMemoryCard2High)) {
+ SendCommand (
+ CardData,
+ STOP_TRANSMISSION,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ } else {
+ SendCommand (
+ CardData,
+ STOP_TRANSMISSION,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ }
+
+ }
+
+
+Done:
+ DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));
+ return Status;
+}
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.
+ @param MediaId The media id that the write request is for.
+ @param LBA The starting logical block address to read from on the device.
+ The caller is responsible for writing to only legitimate locations.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the
+ intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Address;
+ CARD_DATA *CardData;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ UINT32 RemainingLength;
+ UINT32 TransferLength;
+ UINT8 *BufferPointer;
+ BOOLEAN SectorAddressing;
+
+ DEBUG((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
+ Status = EFI_SUCCESS;
+ CardData = CARD_DATA_FROM_THIS(This);
+ SDHostIo = CardData->SDHostIo;
+ if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
+ SectorAddressing = TRUE;
+ } else {
+ SectorAddressing = FALSE;
+ }
+ if (SectorAddressing) {
+ //
+ //Block Address
+ //
+ Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
+ } else {
+ //
+ //Byte Address
+ //
+ Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+ }
+
+ if (!Buffer) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n"));
+ goto Done;
+ }
+
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n"));
+ goto Done;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (This->Media->ReadOnly == TRUE) {
+ Status = EFI_WRITE_PROTECTED;
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n"));
+ goto Done;
+ }
+
+
+
+ BufferPointer = Buffer;
+ RemainingLength = (UINT32)BufferSize;
+
+ while (RemainingLength > 0) {
+ if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) {
+ if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
+ TransferLength = SDHostIo->HostCapability.BoundarySize;
+ } else {
+ TransferLength = RemainingLength;
+ }
+
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+
+ if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
+ Status = SendCommand (
+ CardData,
+ SET_BLOCKLEN,
+ CardData->BlockIoMedia.BlockSize,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ Status = SendCommand (
+ CardData,
+ SET_BLOCK_COUNT,
+ TransferLength / CardData->BlockIoMedia.BlockSize,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+ Status = SendCommand (
+ CardData,
+ WRITE_MULTIPLE_BLOCK,
+ Address,
+ OutData,
+ CardData->AlignedBuffer,
+ (UINT32)TransferLength,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
+ break;
+ }
+ } else {
+ if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
+ TransferLength = CardData->BlockIoMedia.BlockSize;
+ } else {
+ TransferLength = RemainingLength;
+ }
+
+ CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+ Status = SendCommand (
+ CardData,
+ WRITE_BLOCK,
+ Address,
+ OutData,
+ CardData->AlignedBuffer,
+ (UINT32)TransferLength,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ }
+ if (SectorAddressing) {
+ //
+ //Block Address
+ //
+ Address += TransferLength / 512;
+ } else {
+ //
+ //Byte Address
+ //
+ Address += TransferLength;
+ }
+ BufferPointer += TransferLength;
+ RemainingLength -= TransferLength;
+
+ }
+
+ if (EFI_ERROR (Status)) {
+ SendCommand (
+ CardData,
+ STOP_TRANSMISSION,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+
+ }
+
+
+Done:
+ return EFI_SUCCESS;
+}
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+ (In this driver, this function just returns EFI_SUCCESS.)
+
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS
+ @retval Others
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ MMC/SD card BlockIo init function.
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS
+ @retval Others
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+ IN CARD_DATA *CardData
+ )
+{
+ //
+ //BlockIO protocol
+ //
+ CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
+ CardData->BlockIo.Media = &(CardData->BlockIoMedia);
+ CardData->BlockIo.Reset = MMCSDBlockReset;
+ CardData->BlockIo.ReadBlocks = MMCSDBlockReadBlocks ;
+ CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
+ CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
+
+ CardData->BlockIoMedia.MediaId = 0;
+ CardData->BlockIoMedia.RemovableMedia = FALSE;
+ CardData->BlockIoMedia.MediaPresent = TRUE;
+ CardData->BlockIoMedia.LogicalPartition = FALSE;
+
+ if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
+ CardData->BlockIoMedia.ReadOnly = TRUE;
+ } else {
+ CardData->BlockIoMedia.ReadOnly = FALSE;
+ }
+
+
+ CardData->BlockIoMedia.WriteCaching = FALSE;
+ CardData->BlockIoMedia.BlockSize = CardData->BlockLen;
+ CardData->BlockIoMedia.IoAlign = 1;
+ CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1);
+
+
+ return EFI_SUCCESS;
+
+}
+
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c
new file mode 100644
index 0000000000..5d34332b51
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c
@@ -0,0 +1,1716 @@
+/** @file
+
+MMC/SD transfer specific functions
+
+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 "SDMediaDevice.h"
+
+/**
+ Check card status, print the debug info and check the error
+
+ @param Status Status got from card status register.
+
+ @retval EFI_SUCCESS
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+CheckCardStatus (
+ IN UINT32 Status
+ )
+{
+ CARD_STATUS *CardStatus;
+ CardStatus = (CARD_STATUS*)(&Status);
+
+ if (CardStatus->ADDRESS_OUT_OF_RANGE) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n"));
+ }
+
+ if (CardStatus->ADDRESS_MISALIGN) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n"));
+ }
+
+ if (CardStatus->BLOCK_LEN_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n"));
+ }
+
+ if (CardStatus->ERASE_SEQ_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n"));
+ }
+
+ if (CardStatus->ERASE_PARAM) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n"));
+ }
+
+ if (CardStatus->WP_VIOLATION) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n"));
+ }
+
+ if (CardStatus->CARD_IS_LOCKED) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n"));
+ }
+
+ if (CardStatus->LOCK_UNLOCK_FAILED) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n"));
+ }
+
+ if (CardStatus->COM_CRC_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n"));
+ }
+
+ if (CardStatus->ILLEGAL_COMMAND) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n"));
+ }
+
+ if (CardStatus->CARD_ECC_FAILED) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n"));
+ }
+
+ if (CardStatus->CC_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n"));
+ }
+
+ if (CardStatus->ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n"));
+ }
+
+ if (CardStatus->UNDERRUN) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n"));
+ }
+
+ if (CardStatus->OVERRUN) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n"));
+ }
+
+ if (CardStatus->CID_CSD_OVERWRITE) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n"));
+ }
+
+ if (CardStatus->WP_ERASE_SKIP) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n"));
+ }
+
+ if (CardStatus->ERASE_RESET) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n"));
+ }
+
+ if (CardStatus->SWITCH_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n"));
+ }
+
+ if ((Status & 0xFCFFA080) != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send command by using Host IO protocol
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param CommandIndex The command index to set the command index field of command register.
+ @param Argument Command argument to set the argument field of command register.
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.
+ @param Buffer Contains the data read from / write to the device.
+ @param BufferSize The size of the buffer.
+ @param ResponseType RESPONSE_TYPE.
+ @param TimeOut Time out value in 1 ms unit.
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendCommand (
+ IN CARD_DATA *CardData,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ )
+{
+
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ SDHostIo = CardData->SDHostIo;
+ if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {
+ CommandIndex |= AUTO_CMD12_ENABLE;
+ }
+
+ Status = SDHostIo->SendCommand (
+ SDHostIo,
+ CommandIndex,
+ Argument,
+ DataType,
+ Buffer,
+ BufferSize,
+ ResponseType,
+ TimeOut,
+ ResponseData
+ );
+ if (!EFI_ERROR (Status)) {
+ if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+ ASSERT(ResponseData != NULL);
+ Status = CheckCardStatus (*ResponseData);
+ }
+ } else {
+ SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
+ }
+
+ return Status;
+}
+
+/**
+ Send the card APP_CMD command with the following command indicated by CommandIndex
+
+ @param CardData Pointer to CARD_DATA.
+ @param CommandIndex The command index to set the command index field of command register.
+ @param Argument Command argument to set the argument field of command register.
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.
+ @param Buffer Contains the data read from / write to the device.
+ @param BufferSize The size of the buffer.
+ @param ResponseType RESPONSE_TYPE.
+ @param TimeOut Time out value in 1 ms unit.
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendAppCommand (
+ IN CARD_DATA *CardData,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ )
+{
+
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ UINT8 Index;
+
+ SDHostIo = CardData->SDHostIo;
+ Status = EFI_SUCCESS;
+
+ for (Index = 0; Index < 2; Index++) {
+ Status = SDHostIo->SendCommand (
+ SDHostIo,
+ APP_CMD,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = CheckCardStatus (*(UINT32*)&(CardData->CardStatus));
+ if (CardData->CardStatus.SAPP_CMD != 1) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ } else {
+ SDHostIo->ResetSDHost (SDHostIo, Reset_Auto);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {
+ CommandIndex |= AUTO_CMD12_ENABLE;
+ }
+
+ Status = SDHostIo->SendCommand (
+ SDHostIo,
+ CommandIndex,
+ Argument,
+ DataType,
+ Buffer,
+ BufferSize,
+ ResponseType,
+ TimeOut,
+ ResponseData
+ );
+ if (!EFI_ERROR (Status)) {
+ if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+ ASSERT(ResponseData != NULL);
+ Status = CheckCardStatus (*ResponseData);
+ }
+ } else {
+ SDHostIo->ResetSDHost (SDHostIo, Reset_Auto);
+ }
+
+ return Status;
+}
+
+
+/**
+ Send the card FAST_IO command
+
+ @param CardData Pointer to CARD_DATA.
+ @param RegisterAddress Register Address.
+ @param RegisterData Pointer to register Data.
+ @param Write TRUE for write, FALSE for read.
+
+ @retval EFI_SUCCESS
+ @retval EFI_UNSUPPORTED
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+FastIO (
+ IN CARD_DATA *CardData,
+ IN UINT8 RegisterAddress,
+ IN OUT UINT8 *RegisterData,
+ IN BOOLEAN Write
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Argument;
+ UINT32 Data;
+
+ Status = EFI_SUCCESS;
+
+ if (RegisterData == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Argument = (CardData->Address << 16) | (RegisterAddress << 8);
+ if (Write) {
+ Argument |= BIT15 | (*RegisterData);
+ }
+
+ Status = SendCommand (
+ CardData,
+ FAST_IO,
+ Argument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR4,
+ TIMEOUT_COMMAND,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if ((Data & BIT15) == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ if (!Write) {
+ *RegisterData = (UINT8)Data;
+ }
+
+Exit:
+ return Status;
+}
+
+/**
+ Send the card GO_INACTIVE_STATE command.
+
+ @param CardData Pointer to CARD_DATA.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+PutCardInactive (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+
+
+ Status = SendCommand (
+ CardData,
+ GO_INACTIVE_STATE,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseNo,
+ TIMEOUT_COMMAND,
+ NULL
+ );
+
+ return Status;
+
+}
+
+/**
+ Get card interested information for CSD rergister
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS
+ @retval EFI_UNSUPPORTED
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+CaculateCardParameter (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Frequency;
+ UINT32 Multiple;
+ UINT32 CSize;
+ CSD_SDV2 *CsdSDV2;
+
+ Status = EFI_SUCCESS;
+
+ switch (CardData->CSDRegister.TRAN_SPEED & 0x7) {
+ case 0:
+ Frequency = 100 * 1000;
+ break;
+
+ case 1:
+ Frequency = 1 * 1000 * 1000;
+ break;
+
+ case 2:
+ Frequency = 10 * 1000 * 1000;
+ break;
+
+ case 3:
+ Frequency = 100 * 1000 * 1000;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) {
+ case 1:
+ Multiple = 10;
+ break;
+
+ case 2:
+ Multiple = 12;
+ break;
+
+ case 3:
+ Multiple = 13;
+ break;
+
+ case 4:
+ Multiple = 15;
+ break;
+
+ case 5:
+ Multiple = 20;
+ break;
+
+ case 6:
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+ Multiple = 26;
+ } else {
+ Multiple = 25;
+ }
+ break;
+
+ case 7:
+ Multiple = 30;
+ break;
+
+ case 8:
+ Multiple = 35;
+ break;
+
+ case 9:
+ Multiple = 40;
+ break;
+
+ case 10:
+ Multiple = 45;
+ break;
+
+ case 11:
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+ Multiple = 52;
+ } else {
+ Multiple = 50;
+ }
+ break;
+
+ case 12:
+ Multiple = 55;
+ break;
+
+ case 13:
+ Multiple = 60;
+ break;
+
+ case 14:
+ Multiple = 70;
+ break;
+
+ case 15:
+ Multiple = 80;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Frequency = Frequency * Multiple / 10;
+ CardData->MaxFrequency = Frequency;
+
+ CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN;
+
+ if (CardData->CardType == SDMemoryCard2High) {
+ ASSERT(CardData->CSDRegister.CSD_STRUCTURE == 1);
+ CsdSDV2 = (CSD_SDV2*)&CardData->CSDRegister;
+ //
+ // The SD Spec 2.0 says (CSize + 1) * 512K is the total size, so block numbber is (CSize + 1) * 1K
+ // the K here means 1024 not 1000
+ //
+ CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen);
+ } else {
+ //
+ // For MMC card > 2G, the block number will be recaculate later
+ //
+ CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2);
+ CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1);
+ }
+
+ //
+ //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes
+ //
+ if (CardData->BlockLen > 512) {
+ CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512);
+ CardData->BlockLen = 512;
+ }
+
+ DEBUG((
+ EFI_D_INFO,
+ "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen)
+ ));
+
+Exit:
+ return Status;
+}
+
+/**
+ Test the bus width setting for MMC card.It is used only for verification purpose.
+
+ @param CardData Pointer to CARD_DATA.
+ @param Width 1, 4, 8 bits.
+
+ @retval EFI_SUCCESS
+ @retval EFI_UNSUPPORTED
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+MMCCardBusWidthTest (
+ IN CARD_DATA *CardData,
+ IN UINT32 Width
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 Value;
+
+ ASSERT(CardData != NULL);
+
+
+ Value = 0;
+
+ switch (Width) {
+ case 1:
+ Data = 0x80;
+ break;
+
+ case 4:
+ Data = 0x5A;
+ break;
+
+ case 8:
+ Data = 0xAA55;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ CopyMem (CardData->AlignedBuffer, &Data, Width);
+ Status = SendCommand (
+ CardData,
+ BUSTEST_W,
+ 0,
+ OutData,
+ CardData->AlignedBuffer,
+ Width,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_W 0x%x\n", *(UINT32*)&(CardData->CardStatus)));
+ goto Exit;
+ }
+
+ gBS->Stall (10 * 1000);
+
+ Data = 0;
+
+ Status = SendCommand (
+ CardData,
+ BUSTEST_R,
+ 0,
+ InData,
+ CardData->AlignedBuffer,
+ Width,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_R 0x%x\n", *(UINT32*)&(CardData->CardStatus)));
+ goto Exit;
+ }
+ CopyMem (&Data, CardData->AlignedBuffer, Width);
+
+ switch (Width) {
+ case 1:
+ Value = (~(Data ^ 0x80)) & 0xC0;
+ break;
+ case 4:
+ Value = (~(Data ^ 0x5A)) & 0xFF;
+ break;
+ case 8:
+ Value = (~(Data ^ 0xAA55)) & 0xFFFF;
+ break;
+ }
+
+ if (Value == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+
+Exit:
+ return Status;
+}
+
+/**
+ This function can detect these card types:
+ 1. MMC card
+ 2. SD 1.1 card
+ 3. SD 2.0 standard card
+ 3. SD 2.0 high capacity card
+
+ @param CardData Pointer to CARD_DATA.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+GetCardType (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ UINT32 Argument;
+ UINT32 ResponseData;
+ UINT32 Count;
+ BOOLEAN SDCommand8Support;
+
+
+ SDHostIo = CardData->SDHostIo;
+
+ //
+ // Reset the card
+ //
+ Status = SendCommand (
+ CardData,
+ GO_IDLE_STATE,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseNo,
+ TIMEOUT_COMMAND,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ //
+ //No spec requirment, can be adjusted
+ //
+ gBS->Stall (10 * 1000);
+
+
+ //
+ // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass
+ // MMC and SD1.1 card will fail this command
+ //
+ Argument = (VOLTAGE_27_36 << 8) | CHECK_PATTERN;
+ ResponseData = 0;
+ SDCommand8Support = FALSE;
+
+ Status = SendCommand (
+ CardData,
+ SEND_IF_COND,
+ Argument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR7,
+ TIMEOUT_COMMAND,
+ &ResponseData
+ );
+
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_TIMEOUT) {
+ DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, none time out error\n"));
+ goto Exit;
+ }
+ } else {
+ if (ResponseData != Argument) {
+ DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ SDCommand8Support = TRUE;
+ }
+
+
+ Argument = 0;
+ if (SDHostIo->HostCapability.V30Support == TRUE) {
+ Argument |= BIT17 | BIT18;
+ } else if (SDHostIo->HostCapability.V33Support == TRUE) {
+ Argument |= BIT20 | BIT21;
+ }
+
+ if (SDCommand8Support) {
+ //
+ //If command SD_SEND_OP_COND sucessed, it should be set.
+ // SD 1.1 card will ignore it
+ // SD 2.0 standard card will repsond with CCS 0, SD high capacity card will respond with CCS 1
+ // CCS is BIT30 of OCR
+ Argument |= BIT30;
+ }
+
+
+ Count = 20;
+ //
+ //Only SD card will respond to this command, and spec says the card only checks condition at first ACMD41 command
+ //
+ do {
+ Status = SendAppCommand (
+ CardData,
+ SD_SEND_OP_COND,
+ Argument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR3,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->OCRRegister)
+ );
+ if (EFI_ERROR (Status)) {
+ if ((Status == EFI_TIMEOUT) && (!SDCommand8Support)) {
+ CardData->CardType = MMCCard;
+ Status = EFI_SUCCESS;
+ DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, MMC card was identified\n"));
+ } else {
+ //
+ // Not as expected, MMC card should has no response, which means timeout.
+ // SD card should pass this command
+ //
+ DEBUG((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n"));
+ }
+ goto Exit;
+ }
+ //
+ //Avoid waiting if sucess. Busy bit 0 means not ready
+ //
+ if (CardData->OCRRegister.Busy == 1) {
+ break;
+ }
+
+ gBS->Stall (50 * 1000);
+ Count--;
+ if (Count == 0) {
+ DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ } while (1);
+
+ //
+ //Check supported voltage
+ //
+ Argument = 0;
+ if (SDHostIo->HostCapability.V30Support == TRUE) {
+ if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) {
+ Argument |= BIT17;
+ } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) {
+ Argument |= BIT18;
+ }
+ } else if (SDHostIo->HostCapability.V33Support == TRUE) {
+ if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) {
+ Argument |= BIT20;
+ } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) {
+ Argument |= BIT21;
+ }
+ }
+
+ if (Argument == 0) {
+ //
+ //No matched support voltage
+ //
+ PutCardInactive (CardData);
+ DEBUG((EFI_D_ERROR, "No matched voltage for this card\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ CardData->CardType = SDMemoryCard;
+ if (SDCommand8Support == TRUE) {
+ CardData->CardType = SDMemoryCard2;
+ DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above standard card was identified\n"));
+ }
+
+ if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) {
+ CardData->CardType = SDMemoryCard2High;
+ DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above high capacity card was identified\n"));
+ }
+
+
+
+Exit:
+ return Status;
+}
+
+/**
+ MMC card high/low voltage selection function
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCCardVoltageSelection (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ UINT8 Retry;
+ UINT32 TimeOut;
+
+ Status = EFI_SUCCESS;
+ SDHostIo = CardData->SDHostIo;
+ //
+ //First try the high voltage, then if supported choose the low voltage
+ //
+
+ for (Retry = 0; Retry < 3; Retry++) {
+ //
+ // To bring back the normal MMC card to work
+ // after sending the SD command. Otherwise some
+ // card could not work
+
+ Status = SendCommand (
+ CardData,
+ GO_IDLE_STATE,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseNo,
+ TIMEOUT_COMMAND,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+ continue;
+ }
+ //
+ //CE-ATA device needs long delay
+ //
+ gBS->Stall ((Retry + 1) * 50 * 1000);
+
+ //
+ //Get OCR register to check voltage support, first time the OCR is 0
+ //
+ Status = SendCommand (
+ CardData,
+ SEND_OP_COND,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR3,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->OCRRegister)
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (Retry == 3) {
+ DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ //TimeOut Value, 5000 * 100 * 1000 = 5 s
+ //
+ TimeOut = 5000;
+
+ do {
+ Status = SendCommand (
+ CardData,
+ SEND_OP_COND,
+ 0x40300000,
+ NoData,
+ NULL,
+ 0,
+ ResponseR3,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->OCRRegister)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ gBS->Stall (1 * 1000);
+ TimeOut--;
+ if (TimeOut == 0) {
+ Status = EFI_TIMEOUT;
+ DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));
+ goto Exit;
+ }
+ } while (CardData->OCRRegister.Busy != 1);
+
+ if (CardData->OCRRegister.AccessMode == 2) // eMMC Card uses Sector Addressing - High Capacity
+ {
+ DEBUG((EFI_D_INFO, "eMMC Card is High Capacity\n"));
+ CardData->CardType = MMCCardHighCap;
+ }
+
+Exit:
+ return Status;
+
+}
+
+/**
+ This function set the bus and device width for MMC card
+
+ @param CardData Pointer to CARD_DATA.
+ @param Width 1, 4, 8 bits.
+
+ @retval EFI_SUCCESS
+ @retval EFI_UNSUPPORTED
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+MMCCardSetBusWidth (
+ IN CARD_DATA *CardData,
+ IN UINT8 BusWidth,
+ IN BOOLEAN EnableDDRMode
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ SWITCH_ARGUMENT SwitchArgument;
+ UINT8 Value;
+
+ SDHostIo = CardData->SDHostIo;
+ Value = 0;
+ switch (BusWidth) {
+ case 8:
+ if (EnableDDRMode)
+ Value = 6;
+ else
+ Value = 2;
+ break;
+
+ case 4:
+ if (EnableDDRMode)
+ Value = 5;
+ else
+ Value = 1;
+ break;
+
+ case 1:
+ if (EnableDDRMode) // Bus width 1 is not supported in ddr mode
+ return EFI_UNSUPPORTED;
+ Value = 0;
+ break;
+
+ default:
+ ASSERT(0);
+ }
+
+
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = Value;
+ SwitchArgument.Index = (UINT32)((UINTN)
+ (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN)(&(CardData->ExtCSDRegister)));
+ SwitchArgument.Access = WriteByte_Mode;
+ Status = SendCommand (
+ CardData,
+ SWITCH,
+ *(UINT32*)&SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = SendCommand (
+ CardData,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));
+ goto Exit;
+ } else {
+ DEBUG((EFI_D_ERROR, "MMCCardSetBusWidth:SWITCH Card Status:0x%x\n", *(UINT32*)&(CardData->CardStatus)));
+ Status = SDHostIo->SetBusWidth (SDHostIo, BusWidth);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SWITCH set %d bits Fail\n", BusWidth));
+ goto Exit;
+ }
+ gBS->Stall (5 * 1000);
+ }
+ }
+
+ if (!EnableDDRMode) { // CMD19 and CMD14 are illegal commands in ddr mode
+ //if (EFI_ERROR (Status)) {
+ // DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest: Fail to enable high speed mode\n"));
+ // goto Exit;
+ //}
+
+ Status = MMCCardBusWidthTest (CardData, BusWidth);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));
+ goto Exit;
+ }
+ }
+
+ CardData->CurrentBusWidth = BusWidth;
+
+Exit:
+ return Status;
+}
+
+
+/**
+ MMC/SD card init function
+
+ @param CardData Pointer to CARD_DATA.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ SWITCH_ARGUMENT SwitchArgument;
+ UINT32 Data;
+ UINT32 Argument;
+ UINT32 nIndex;
+ UINT8 PowerValue;
+ BOOLEAN EnableDDRMode;
+
+ ASSERT(CardData != NULL);
+ SDHostIo = CardData->SDHostIo;
+ EnableDDRMode = FALSE;
+
+ CardData->CardType = UnknownCard;
+ Status = GetCardType (CardData);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ DEBUG((DEBUG_INFO, "CardData->CardType 0x%x\n", CardData->CardType));
+
+ ASSERT (CardData->CardType != UnknownCard);
+ //
+ //MMC, SD card need host auto stop command support
+ //
+ SDHostIo->EnableAutoStopCmd (SDHostIo, TRUE);
+
+ if (CardData->CardType == MMCCard) {
+ Status = MMCCardVoltageSelection (CardData);
+ if (EFI_ERROR(Status)) {
+ goto Exit;
+ }
+ }
+
+ //
+ // Get CID Register
+ //
+ Status = SendCommand (
+ CardData,
+ ALL_SEND_CID,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR2,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CIDRegister)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "ALL_SEND_CID Fail Status = 0x%x\n", Status));
+ goto Exit;
+ } else {
+ // Dump out the Card ID data
+ DEBUG((EFI_D_INFO, "Product Name: "));
+ for ( nIndex=0; nIndex<6; nIndex++ ) {
+ DEBUG((EFI_D_INFO, "%c", CardData->CIDRegister.PNM[nIndex]));
+ }
+ DEBUG((EFI_D_INFO, "\nApplication ID : %d\n", CardData->CIDRegister.OID));
+ DEBUG((EFI_D_INFO, "Manufacturer ID: %d\n", CardData->CIDRegister.MID));
+ DEBUG((EFI_D_INFO, "Revision ID : %d\n", CardData->CIDRegister.PRV));
+ DEBUG((EFI_D_INFO, "Serial Number : %d\n", CardData->CIDRegister.PSN));
+ }
+
+ //
+ //SET_RELATIVE_ADDR
+ //
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+ //
+ //Hard code the RCA address
+ //
+ CardData->Address = 1;
+
+ //
+ // Set RCA Register
+ //
+ Status = SendCommand (
+ CardData,
+ SET_RELATIVE_ADDR,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+ } else {
+ Data = 0;
+ Status = SendCommand (
+ CardData,
+ SET_RELATIVE_ADDR,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR6,
+ TIMEOUT_COMMAND,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ CardData->Address = (UINT16)(Data >> 16);
+ *(UINT32*)&CardData->CardStatus = Data & 0x1FFF;
+ CardData->CardStatus.ERROR = (Data >> 13) & 0x1;
+ CardData->CardStatus.ILLEGAL_COMMAND = (Data >> 14) & 0x1;
+ CardData->CardStatus.COM_CRC_ERROR = (Data >> 15) & 0x1;
+ Status = CheckCardStatus (*(UINT32*)&CardData->CardStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+ }
+
+ //
+ // Get CSD Register
+ //
+ Status = SendCommand (
+ CardData,
+ SEND_CSD,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR2,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CSDRegister)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SEND_CSD Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ DEBUG((EFI_D_INFO, "CardData->CSDRegister.SPEC_VERS = 0x%x\n", CardData->CSDRegister.SPEC_VERS));
+ DEBUG((EFI_D_INFO, "CardData->CSDRegister.CSD_STRUCTURE = 0x%x\n", CardData->CSDRegister.CSD_STRUCTURE));
+
+ Status = CaculateCardParameter (CardData);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+
+ //
+ // It is platform and hardware specific, need hadrware engineer input
+ //
+ if (CardData->CSDRegister.DSR_IMP == 1) {
+ //
+ // Default is 0x404
+ //
+ Status = SendCommand (
+ CardData,
+ SET_DSR,
+ (DEFAULT_DSR_VALUE << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseNo,
+ TIMEOUT_COMMAND,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_DSR Fail Status = 0x%x\n", Status));
+ //
+ // Assume can operate even fail
+ //
+ }
+ }
+ //
+ //Change clock frequency from 400KHz to max supported when not in high speed mode
+ //
+ Status = SDHostIo->SetClockFrequency (SDHostIo, CardData->MaxFrequency);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
+ goto Exit;
+ }
+
+ //
+ //Put the card into tran state
+ //
+ Status = SendCommand (
+ CardData,
+ SELECT_DESELECT_CARD,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ //
+ // No spec requirment, can be adjusted
+ //
+ gBS->Stall (5 * 1000);
+ //
+ // No need to do so
+ //
+ //
+ Status = SendCommand (
+ CardData,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+ //
+ //if the SPEC_VERS indicates a version 4.0 or higher
+ //The card is a high speed card and support Switch
+ //and Send_ext_csd command
+ //otherwise it is an old card
+ //
+
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+ //
+ //Only V4.0 and above supports more than 1 bits and high speed
+ //
+ if (CardData->CSDRegister.SPEC_VERS >= 4) {
+ //
+ //Get ExtCSDRegister
+ //
+ Status = SendCommand (
+ CardData,
+ SEND_EXT_CSD,
+ 0x0,
+ InData,
+ CardData->AlignedBuffer,
+ sizeof (EXT_CSD),
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SEND_EXT_CSD Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));
+
+ //
+ // Recaculate the block number for >2G MMC card
+ //
+ Data = (CardData->ExtCSDRegister.SEC_COUNT[0]) |
+ (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) |
+ (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |
+ (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);
+
+ if (Data != 0) {
+ CardData->BlockNumber = Data;
+ }
+ DEBUG((DEBUG_INFO, "CardData->BlockNumber %d\n", Data));
+ DEBUG((EFI_D_ERROR, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN)CardData->ExtCSDRegister.CARD_TYPE));
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2)||
+ (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+ //DEBUG((DEBUG_INFO, "To enable DDR mode\n"));
+ //EnableDDRMode = TRUE;
+ }
+ //
+ // Check current chipset capability and the plugged-in card
+ // whether supports HighSpeed
+ //
+ if (SDHostIo->HostCapability.HighSpeedSupport) {
+
+ //
+ //Change card timing to high speed interface timing
+ //
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = 1;
+ SwitchArgument.Index = (UINT32)((UINTN)
+ (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN)(&(CardData->ExtCSDRegister)));
+ SwitchArgument.Access = WriteByte_Mode;
+ Status = SendCommand (
+ CardData,
+ SWITCH,
+ *(UINT32*)&SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "MMCSDCardInit:SWITCH frequency Fail Status = 0x%x\n", Status));
+ }
+
+ gBS->Stall (5 * 1000);
+
+
+ if (!EFI_ERROR (Status)) {
+ Status = SendCommand (
+ CardData,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ if (EnableDDRMode) {
+ DEBUG((EFI_D_ERROR, "Enable ddr mode on host controller\n"));
+ SDHostIo->SetDDRMode (SDHostIo, TRUE);
+ } else {
+ DEBUG((EFI_D_ERROR, "Enable high speed mode on host controller\n"));
+ SDHostIo->SetHighSpeedMode (SDHostIo, TRUE);
+ }
+ //
+ // Change host clock to support high speed and enable chispet to
+ // support speed
+ //
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+ Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP_HIGH);
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+ Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP);
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
+ goto Exit;
+ }
+ //
+ // It seems no need to stall after changing bus freqeuncy.
+ // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.
+ // But SetClock alreay has delay.
+ //
+ }
+ }
+
+ }
+
+
+
+ //
+ // Prefer wide bus width for performance
+ //
+ //
+ // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits
+ //
+ if (SDHostIo->HostCapability.BusWidth8 == TRUE) {
+ Status = MMCCardSetBusWidth (CardData, 8, EnableDDRMode);
+ if (EFI_ERROR (Status)) {
+ //
+ // CE-ATA may support 8 bits and 4 bits, but has no software method for detection
+ //
+ Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+ } else if (SDHostIo->HostCapability.BusWidth4 == TRUE) {
+ Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+
+ PowerValue = 0;
+
+ if (CardData->CurrentBusWidth == 8) {
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+ PowerValue = PowerValue >> 4;
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+ PowerValue = PowerValue >> 4;
+ }
+ } else if (CardData->CurrentBusWidth == 4) {
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+ PowerValue = PowerValue & 0xF;
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+ PowerValue = PowerValue & 0xF;
+ }
+ }
+
+ if (PowerValue != 0) {
+ //
+ //Update Power Class
+ //
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = PowerValue;
+ SwitchArgument.Index = (UINT32)((UINTN)
+ (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN)(&(CardData->ExtCSDRegister)));
+ SwitchArgument.Access = WriteByte_Mode;
+ Status = SendCommand (
+ CardData,
+ SWITCH,
+ *(UINT32*)&SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = SendCommand (
+ CardData,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SWITCH Power Class Fail Status = 0x%x\n", Status));
+ }
+ //gBS->Stall (10 * 1000);
+ }
+ }
+
+
+
+ } else {
+
+
+ DEBUG((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n",CardData->CSDRegister.SPEC_VERS));
+ }
+ } else {
+ //
+ // Pin 1, at power up this line has a 50KOhm pull up enabled in the card.
+ // This pull-up should be disconnected by the user, during regular data transfer,
+ // with SET_CLR_CARD_DETECT (ACMD42) command
+ //
+ Status = SendAppCommand (
+ CardData,
+ SET_CLR_CARD_DETECT,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ /*
+ //
+ // Don't rely on SCR and SD status, some cards have unexpected SCR.
+ // It only sets private section, the other bits are 0
+ // such as Sandisk Ultra II 4.0G, KinSton mini SD 128M, Toshiba 2.0GB
+ // Some card even fail this command, KinSton SD 4GB
+ //
+ Status = SendAppCommand (
+ CardData,
+ SEND_SCR,
+ 0,
+ InData,
+ (UINT8*)&(CardData->SCRRegister),
+ sizeof(SCR),
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // SD memory card at least supports 1 and 4 bits.
+ //
+ // ASSERT ((CardData->SCRRegister.SD_BUS_WIDTH & (BIT0 | BIT2)) == (BIT0 | BIT2));
+ */
+
+ //
+ // Set Bus Width to 4
+ //
+ Status = SendAppCommand (
+ CardData,
+ SET_BUS_WIDTH,
+ SD_BUS_WIDTH_4,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ Status = SDHostIo->SetBusWidth (SDHostIo, 4);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ CardData->CurrentBusWidth = 4;
+
+
+ if ((SDHostIo->HostCapability.HighSpeedSupport == FALSE) ||
+ ((CardData->CSDRegister.CCC & BIT10) != BIT10)) {
+ //
+ // Host must support high speed
+ // Card must support Switch function
+ //
+ goto Exit;
+ }
+
+ //
+ //Mode = 0, group 1, function 1, check operation
+ //
+ Argument = 0xFFFF01;
+ ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+ Status = SendCommand (
+ CardData,
+ SWITCH_FUNC,
+ Argument,
+ InData,
+ CardData->AlignedBuffer,
+ sizeof (SWITCH_STATUS),
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+ if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+ ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+ //
+ // 1. SD 1.1 card does not suppport busy bit
+ // 2. Ready state
+ //
+ //
+
+ //
+ //Mode = 1, group 1, function 1, BIT31 set means set mode
+ //
+ Argument = 0xFFFF01 | BIT31;
+ ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+ Status = SendCommand (
+ CardData,
+ SWITCH_FUNC,
+ Argument,
+ InData,
+ CardData->AlignedBuffer,
+ sizeof (SWITCH_STATUS),
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+ if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+ ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+ //
+ // 1. SD 1.1 card does not suppport busy bit
+ // 2. Ready state
+ //
+
+ //
+ // 8 clocks, (1/ 25M) * 8 ==> 320 us, so 1ms > 0.32 ms
+ //
+ gBS->Stall (1000);
+
+ //
+ //Change host clock
+ //
+ Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_SD_PP_HIGH);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ }
+ }
+ }
+ if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+ (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) {
+
+ //
+ // Set Block Length, to improve compatibility in case of some cards
+ //
+ Status = SendCommand (
+ CardData,
+ SET_BLOCKLEN,
+ 512,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_BLOCKLEN Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+ }
+ SDHostIo->SetBlockLength (SDHostIo, 512);
+
+
+Exit:
+ return Status;
+}
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c
new file mode 100644
index 0000000000..1a0682cca5
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c
@@ -0,0 +1,323 @@
+/** @file
+
+The definition for SD media device driver model and blkio protocol 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.
+
+**/
+
+
+#include "SDMediaDevice.h"
+
+
+EFI_DRIVER_BINDING_PROTOCOL gSDMediaDeviceDriverBinding = {
+ SDMediaDeviceSupported,
+ SDMediaDeviceStart,
+ SDMediaDeviceStop,
+ 0x20,
+ NULL,
+ NULL
+};
+
+/**
+ Entry point for EFI drivers.
+
+ @param ImageHandle EFI_HANDLE.
+ @param SystemTable EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Driver is successfully loaded.
+ @return Others Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSDMediaDevice (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSDMediaDeviceDriverBinding,
+ ImageHandle,
+ &gSDMediaDeviceName,
+ &gSDMediaDeviceName2
+ );
+}
+
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has BlockIoProtocol installed will be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+
+ //
+ // Test whether there is PCI IO Protocol attached on the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSDHostIoProtocolGuid,
+ (VOID **)&SDHostIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSDHostIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+Exit:
+ return Status;
+}
+
+/**
+ Starting the SD Media Device Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ CARD_DATA *CardData;
+
+ CardData = NULL;
+
+ //
+ // Open PCI I/O Protocol and save pointer to open protocol
+ // in private data area.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSDHostIoProtocolGuid,
+ (VOID **) &SDHostIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to open gEfiSDHostIoProtocolGuid \r\n"));
+ goto Exit;
+ }
+
+ Status = SDHostIo->DetectCardAndInitHost (SDHostIo);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: Fail to DetectCardAndInitHost \r\n"));
+ goto Exit;
+ }
+
+ CardData = (CARD_DATA*)AllocateZeroPool(sizeof (CARD_DATA));
+ if (CardData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to AllocateZeroPool(CARD_DATA) \r\n"));
+ goto Exit;
+ }
+
+ ASSERT (SDHostIo->HostCapability.BoundarySize >= 4 * 1024);
+ CardData->RawBufferPointer = (UINT8*)((UINTN)DMA_MEMORY_TOP);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (2 * SDHostIo->HostCapability.BoundarySize),
+ (EFI_PHYSICAL_ADDRESS *)(&CardData->RawBufferPointer)
+ );
+
+ if (CardData->RawBufferPointer == NULL) {
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to AllocateZeroPool(2*x) \r\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CardData->AlignedBuffer = CardData->RawBufferPointer - ((UINTN)(CardData->RawBufferPointer) & (SDHostIo->HostCapability.BoundarySize - 1)) + SDHostIo->HostCapability.BoundarySize;
+
+ CardData->Signature = CARD_DATA_SIGNATURE;
+ CardData->SDHostIo = SDHostIo;
+
+ Status = MMCSDCardInit (CardData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to MMCSDCardInit \r\n"));
+ goto Exit;
+ }
+ DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: MMCSDCardInit SuccessFul\n"));
+
+ if (CardData->CardType == CEATACard) {
+ Status = CEATABlockIoInit (CardData);
+ } else {
+ Status = MMCSDBlockIoInit (CardData);
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to BlockIoInit \r\n"));
+ goto Exit;
+ }
+ DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: BlockIo is successfully installed\n"));
+
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiBlockIoProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &CardData->BlockIo
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to install gEfiBlockIoProtocolGuid \r\n"));
+ goto Exit;
+ }
+
+ //
+ // Install the component name protocol
+ //
+ CardData->ControllerNameTable = NULL;
+
+ AddUnicodeString2 (
+ "eng",
+ gSDMediaDeviceName.SupportedLanguages,
+ &CardData->ControllerNameTable,
+ L"MMC/SD Media Device",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gSDMediaDeviceName2.SupportedLanguages,
+ &CardData->ControllerNameTable,
+ L"MMC/SD Media Device",
+ FALSE
+ );
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: End with failure\r\n"));
+ if (CardData != NULL) {
+ if (CardData->RawBufferPointer != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * SDHostIo->HostCapability.BoundarySize));
+ }
+ FreePool (CardData);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ CARD_DATA *CardData;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // First find BlockIo Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CardData = CARD_DATA_FROM_THIS(BlockIo);
+
+ //
+ // Uninstall Block I/O protocol from the device handle
+ //
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ BlockIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CardData != NULL) {
+ if (CardData->RawBufferPointer != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * CardData->SDHostIo->HostCapability.BoundarySize));
+ }
+ FreeUnicodeStringTable (CardData->ControllerNameTable);
+ FreePool (CardData);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSDHostIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h
new file mode 100644
index 0000000000..1550429f48
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h
@@ -0,0 +1,468 @@
+/** @file
+
+The definition for SD media device driver model and blkio protocol 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 _SD_MEDIA_DEVICE_H_
+#define _SD_MEDIA_DEVICE_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/BlockIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Pci22.h>
+
+#include "ComponentName.h"
+#include "SDHostIo.h"
+
+
+extern EFI_DRIVER_BINDING_PROTOCOL gSDMediaDeviceDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gSDMediaDeviceName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSDMediaDeviceName2;
+
+//
+// Define the region of memory used for DMA memory
+//
+#define DMA_MEMORY_TOP 0x0000000001FFFFFFULL
+
+#define CARD_DATA_SIGNATURE SIGNATURE_32 ('c', 'a', 'r', 'd')
+
+//
+// Command timeout will be max 100 ms
+//
+#define TIMEOUT_COMMAND 100
+#define TIMEOUT_DATA 5000
+
+typedef enum{
+ UnknownCard = 0,
+ MMCCard, // MMC card
+ MMCCardHighCap, // MMC Card High Capacity
+ CEATACard, // CE-ATA device
+ SDMemoryCard, // SD 1.1 card
+ SDMemoryCard2, // SD 2.0 or above standard card
+ SDMemoryCard2High // SD 2.0 or above high capacity card
+}CARD_TYPE;
+
+
+typedef struct {
+ //
+ //BlockIO
+ //
+ UINTN Signature;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+
+ EFI_BLOCK_IO_MEDIA BlockIoMedia;
+
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ CARD_TYPE CardType;
+
+ UINT8 CurrentBusWidth;
+ BOOLEAN DualVoltage;
+ BOOLEAN NeedFlush;
+ UINT8 Reserved[3];
+
+ UINT16 Address;
+ UINT32 BlockLen;
+ UINT32 MaxFrequency;
+ UINT64 BlockNumber;
+ //
+ //Common used
+ //
+ CARD_STATUS CardStatus;
+ OCR OCRRegister;
+ CID CIDRegister;
+ CSD CSDRegister;
+ EXT_CSD ExtCSDRegister;
+ UINT8 *RawBufferPointer;
+ UINT8 *AlignedBuffer;
+ //
+ //CE-ATA specific
+ //
+ TASK_FILE TaskFile;
+ IDENTIFY_DEVICE_DATA IndentifyDeviceData;
+ //
+ //SD specific
+ //
+ SCR SCRRegister;
+ SD_STATUS_REG SDSattus;
+ SWITCH_STATUS SwitchStatus;
+}CARD_DATA;
+
+#define CARD_DATA_FROM_THIS(a) \
+ CR(a, CARD_DATA, BlockIo, CARD_DATA_SIGNATURE)
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has BlockIoProtocol installed will be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starting the SD Media Device Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+EFIAPI
+SDMediaDeviceStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ MMC/SD card init function
+
+ @param CardData Pointer to CARD_DATA.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+ IN CARD_DATA *CardData
+ );
+
+/**
+ Send command by using Host IO protocol
+
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+ @param CommandIndex The command index to set the command index field of command register.
+ @param Argument Command argument to set the argument field of command register.
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.
+ @param Buffer Contains the data read from / write to the device.
+ @param BufferSize The size of the buffer.
+ @param ResponseType RESPONSE_TYPE.
+ @param TimeOut Time out value in 1 ms unit.
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendCommand (
+ IN CARD_DATA *CardData,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ );
+
+/**
+ Send the card APP_CMD command with the following command indicated by CommandIndex
+
+ @param CardData Pointer to CARD_DATA.
+ @param CommandIndex The command index to set the command index field of command register.
+ @param Argument Command argument to set the argument field of command register.
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.
+ @param Buffer Contains the data read from / write to the device.
+ @param BufferSize The size of the buffer.
+ @param ResponseType RESPONSE_TYPE.
+ @param TimeOut Time out value in 1 ms unit.
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendAppCommand (
+ IN CARD_DATA *CardData,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ );
+
+/**
+ Send the card FAST_IO command
+
+ @param CardData Pointer to CARD_DATA.
+ @param RegisterAddress Register Address.
+ @param RegisterData Pointer to register Data.
+ @param Write TRUE for write, FALSE for read.
+
+ @retval EFI_SUCCESS
+ @retval EFI_UNSUPPORTED
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+FastIO (
+ IN CARD_DATA *CardData,
+ IN UINT8 RegisterAddress,
+ IN OUT UINT8 *RegisterData,
+ IN BOOLEAN Write
+ );
+
+/**
+ Judge whether it is CE-ATA device or not.
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval TRUE
+ @retval FALSE
+
+**/
+BOOLEAN
+IsCEATADevice (
+ IN CARD_DATA *CardData
+ );
+
+/**
+ Send software reset
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+SoftwareReset (
+ IN CARD_DATA *CardData
+ );
+
+/**
+ SendATACommand specificed in Taskfile
+
+ @param CardData Pointer to CARD_DATA.
+ @param TaskFile Pointer to TASK_FILE.
+ @param Write TRUE means write, FALSE means read.
+ @param Buffer If NULL, means no data transfer, neither read nor write.
+ @param SectorCount Buffer size in 512 bytes unit.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+SendATACommand (
+ IN CARD_DATA *CardData,
+ IN TASK_FILE *TaskFile,
+ IN BOOLEAN Write,
+ IN UINT8 *Buffer,
+ IN UINT16 SectorCount
+ );
+
+/**
+ IDENTIFY_DEVICE command
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+IndentifyDevice (
+ IN CARD_DATA *CardData
+ );
+
+/**
+ FLUSH_CACHE_EXT command
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+FlushCache (
+ IN CARD_DATA *CardData
+ );
+
+/**
+ STANDBY_IMMEDIATE command
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+StandByImmediate (
+ IN CARD_DATA *CardData
+ );
+
+/**
+ READ_DMA_EXT command
+
+ @param CardData Pointer to CARD_DATA.
+ @param LBA The starting logical block address to read from on the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the buffer.
+ @param SectorCount Size in 512 bytes unit.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+ReadDMAExt (
+ IN CARD_DATA *CardData,
+ IN EFI_LBA LBA,
+ IN UINT8 *Buffer,
+ IN UINT16 SectorCount
+ );
+
+/**
+ WRITE_DMA_EXT command
+
+ @param CardData Pointer to CARD_DATA.
+ @param LBA The starting logical block address to read from on the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the buffer.
+ @param SectorCount Size in 512 bytes unit.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+WriteDMAExt (
+ IN CARD_DATA *CardData,
+ IN EFI_LBA LBA,
+ IN UINT8 *Buffer,
+ IN UINT16 SectorCount
+ );
+
+/**
+ CEATA card BlockIo init function.
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS
+ @retval Others
+**/
+EFI_STATUS
+CEATABlockIoInit (
+ IN CARD_DATA *CardData
+ );
+
+/**
+ MMC/SD card BlockIo init function.
+
+ @param CardData Pointer to CARD_DATA.
+
+ @retval EFI_SUCCESS
+ @retval Others
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+ IN CARD_DATA *CardData
+ );
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf
new file mode 100644
index 0000000000..812436e47a
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf
@@ -0,0 +1,66 @@
+## @file
+#
+# Component Description File For SDMediaDeviceDxe 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 = SDMediaDevice
+ FILE_GUID = 80897901-91F6-4efe-9579-3353A0C02DAB
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeSDMediaDevice
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gSDMediaDeviceDriverBinding
+# COMPONENT_NAME = gSDMediaDeviceName
+# COMPONENT_NAME2 = gSDMediaDeviceName2
+#
+
+[Sources]
+ SDMediaDevice.c
+ SDMediaDevice.h
+ MMCSDTransfer.c
+ CEATA.c
+ CEATABlockIo.c
+ MMCSDBlockIo.c
+ ComponentName.c
+ ComponentName.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiSDHostIoProtocolGuid ## TO_START
+ gEfiBlockIoProtocolGuid ## BY_START
+
+[Pcd.common]
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c
new file mode 100644
index 0000000000..41fb544a95
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c
@@ -0,0 +1,326 @@
+/** @file
+Implementation of Usb Controller PPI.
+
+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/UsbController.h>
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/IoLib.h>
+
+#include "UsbPei.h"
+
+//
+// Globals
+//
+//
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gPeiUsbControllerPpiGuid,
+ NULL
+};
+
+UINTN mIohOhciPciReg[IOH_MAX_OHCI_USB_CONTROLLERS] = {
+ PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, 0)
+};
+
+UINTN mIohEhciPciReg[IOH_MAX_EHCI_USB_CONTROLLERS] = {
+ PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, 0),
+};
+
+/**
+ When EHCI get started in DXE, OHCI couldn't get the ownership
+ of roothub after warm reset because CF@EHCI hasn't been cleared.
+ We should clear that reg before UpdateBootMode. But Reg@EHCI is
+ memory-mapped, so need assume a range of space without conflict
+ in PCI memory space.
+
+ @param[in] PeiServices The pointer of EFI_PEI_SERVICES
+
+**/
+
+VOID
+SwitchConfigFlag (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ UINT32 SavBaseAddr;
+ UINT32 UsbBaseAddr;
+ UINT16 SaveCmdData;
+ UINT8 EhciCapLen;
+ UINT8 Index;
+ UsbBaseAddr = 0;
+
+ for (Index = 0; Index < IOH_MAX_EHCI_USB_CONTROLLERS; Index++) {
+ UsbBaseAddr = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress);
+ //
+ // Manage EHCI on IOH, set UsbBaseAddr
+ //
+ SavBaseAddr = PciRead32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR);
+ PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, UsbBaseAddr);
+ //
+ // Save Cmd register
+ //
+ SaveCmdData = PciRead16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND);
+ //
+ // Enable EHCI on IOH
+ //
+ PciOr16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, B_IOH_USB_COMMAND_BME | B_IOH_USB_COMMAND_MSE );
+ //
+ // Clear CF register on EHCI
+ //
+ EhciCapLen = MmioRead8 (UsbBaseAddr + R_IOH_EHCI_CAPLENGTH);
+ MmioWrite32 (UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS, 0);
+
+ DEBUG ((EFI_D_INFO, "CF@EHCI = %x \n", UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS));
+ //
+ // Restore EHCI UsbBaseAddr in PCI space
+ //
+ PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, SavBaseAddr);
+ //
+ // Restore EHCI Command register in PCI space
+ //
+ PciWrite16(mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, SaveCmdData);
+ }
+}
+/**
+ Retrieved specified the USB controller information.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This This PEI_USB_CONTROLLER_PPI instance.
+ @param UsbControllerId Indicate which usb controller information will be retrieved.
+ @param ControllerType Indicate the controller is Ehci, Ohci, OHCI
+ @param BaseAddress Indicate the memory bar of the controller
+
+ @retval EFI_SUCCESS The reset operation succeeded.
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.
+
+**/
+
+EFI_STATUS
+GetOhciController (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_CONTROLLER_PPI *This,
+ IN UINT8 UsbControllerId,
+ IN UINTN *ControllerType,
+ IN UINTN *BaseAddress
+ )
+{
+ IOH_OHCI_DEVICE *PeiIohOhciDev;
+
+ PeiIohOhciDev = IOH_OHCI_DEVICE_FROM_THIS (This);
+
+ if (UsbControllerId >= IOH_MAX_OHCI_USB_CONTROLLERS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *ControllerType = PEI_OHCI_CONTROLLER;
+ *BaseAddress = PeiIohOhciDev->MmioBase[UsbControllerId];
+
+ return EFI_SUCCESS;
+}
+/**
+ Retrieved specified the USB controller information.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This This PEI_USB_CONTROLLER_PPI instance.
+ @param UsbControllerId Indicate which usb controller information will be retrieved.
+ @param ControllerType Indicate the controller is Ehci, Ohci, OHCI
+ @param BaseAddress Indicate the memory bar of the controller
+
+ @retval EFI_SUCCESS The reset operation succeeded.
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.
+
+**/
+
+EFI_STATUS
+GetEhciController (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_CONTROLLER_PPI *This,
+ IN UINT8 UsbControllerId,
+ IN UINTN *ControllerType,
+ IN UINTN *BaseAddress
+ )
+{
+ IOH_EHCI_DEVICE *PeiIohEhciDev;
+
+ PeiIohEhciDev = IOH_EHCI_DEVICE_FROM_THIS (This);
+
+ if (UsbControllerId >= IOH_MAX_EHCI_USB_CONTROLLERS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *ControllerType = PEI_EHCI_CONTROLLER;
+ *BaseAddress = PeiIohEhciDev->MmioBase[UsbControllerId];
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieved specified the USB controller information.
+
+ @param IohOhciPciReg Ohci device address list.
+ @param OhciCount The count of the OHCI
+ @param IohEhciPciReg Ehci device address list.
+ @param EhciCount The count of the EHCI
+
+**/
+
+VOID
+EnableBusMaster (
+ IN UINTN IohOhciPciReg[],
+ IN UINT8 OhciCount,
+ IN UINTN IohEhciPciReg[],
+ IN UINT8 EhciCount
+ )
+{
+ UINT8 Index;
+ UINT16 CmdReg;
+ for (Index = 0; Index < OhciCount; Index ++) {
+ CmdReg = PciRead16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND);
+ CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );
+ PciWrite16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);
+ }
+ for (Index = 0; Index < EhciCount; Index ++) {
+ CmdReg = PciRead16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND);
+ CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );
+ PciWrite16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);
+ }
+}
+
+PEI_USB_CONTROLLER_PPI mUsbControllerPpi[2] = { {GetOhciController}, {GetEhciController}};
+
+/**
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS PPI successfully installed
+
+**/
+EFI_STATUS
+PeimInitializeIchUsb (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN i;
+ EFI_PHYSICAL_ADDRESS AllocateAddress;
+ IOH_OHCI_DEVICE *PeiIohOhciDev;
+ IOH_EHCI_DEVICE *PeiIohEhciDev;
+ UINT16 CmdReg;
+
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ 1,
+ &AllocateAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ EnableBusMaster (
+ mIohOhciPciReg,
+ IOH_MAX_OHCI_USB_CONTROLLERS,
+ mIohEhciPciReg,
+ IOH_MAX_EHCI_USB_CONTROLLERS
+ );
+
+ if (FeaturePcdGet (PcdEhciRecoveryEnabled)) {
+ DEBUG ((EFI_D_INFO, "UsbPei:EHCI is used for recovery\n"));
+ //
+ // EHCI recovery is enabled
+ //
+ PeiIohEhciDev = (IOH_EHCI_DEVICE *)((UINTN)AllocateAddress);
+ ZeroMem (PeiIohEhciDev, sizeof(IOH_EHCI_DEVICE));
+
+ PeiIohEhciDev->Signature = PEI_IOH_EHCI_SIGNATURE;
+ CopyMem(&(PeiIohEhciDev->UsbControllerPpi), &mUsbControllerPpi[1], sizeof(PEI_USB_CONTROLLER_PPI));
+ CopyMem(&(PeiIohEhciDev->PpiList), &mPpiList, sizeof(mPpiList));
+ PeiIohEhciDev->PpiList.Ppi = &PeiIohEhciDev->UsbControllerPpi;
+
+ //
+ // Assign resources and enable Ehci controllers
+ //
+ for (i = 0; i < IOH_MAX_EHCI_USB_CONTROLLERS; i++) {
+ DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth EHCI controller for recovery\n", i));
+ PeiIohEhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;
+ //
+ // Assign base address register, Enable Bus Master and Memory Io
+ //
+ PciWrite32 (mIohEhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohEhciDev->MmioBase[i]);
+ CmdReg = PciRead16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND);
+ CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );
+ PciWrite16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);
+ }
+ //
+ // Install USB Controller PPI
+ //
+ Status = (**PeiServices).InstallPpi (
+ PeiServices,
+ &PeiIohEhciDev->PpiList
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ DEBUG ((EFI_D_INFO, "UsbPei:OHCI is used for recovery\n"));
+ //
+ // OHCI recovery is enabled
+ //
+ SwitchConfigFlag ((EFI_PEI_SERVICES**)PeiServices);
+ PeiIohOhciDev = (IOH_OHCI_DEVICE *)((UINTN)AllocateAddress);
+ ZeroMem (PeiIohOhciDev, sizeof(IOH_OHCI_DEVICE));
+
+ PeiIohOhciDev->Signature = PEI_IOH_OHCI_SIGNATURE;
+ CopyMem(&(PeiIohOhciDev->UsbControllerPpi), &mUsbControllerPpi[0], sizeof(PEI_USB_CONTROLLER_PPI));
+ CopyMem(&(PeiIohOhciDev->PpiList), &mPpiList, sizeof(mPpiList));
+ PeiIohOhciDev->PpiList.Ppi = &PeiIohOhciDev->UsbControllerPpi;
+ //
+ // Assign resources and enable OHCI controllers
+ //
+ for (i = 0; i < IOH_MAX_OHCI_USB_CONTROLLERS; i++) {
+ DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth OHCI controller for recovery\n", i));
+ PeiIohOhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;
+ //
+ // Assign base address register, Enable Bus Master and Memory Io
+ //
+ PciWrite32 (mIohOhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohOhciDev->MmioBase[i]);
+
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ 1,
+ &AllocateAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+ MmioWrite32(PeiIohOhciDev->MmioBase[i] + R_IOH_USB_OHCI_HCCABAR, (UINT32)AllocateAddress);
+
+ CmdReg = PciRead16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND);
+ CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );
+ PciWrite16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);
+ }
+ //
+ // Install USB Controller PPI
+ //
+ Status = (**PeiServices).InstallPpi (
+ PeiServices,
+ &PeiIohOhciDev->PpiList
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Status;
+}
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h
new file mode 100644
index 0000000000..5910a0bcfb
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h
@@ -0,0 +1,44 @@
+/** @file
+Define private data structure for UHCI and EHCI.
+
+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 _USB_PEI_H
+#define _USB_PEI_H
+
+#include "Ioh.h"
+
+#define PEI_IOH_OHCI_SIGNATURE SIGNATURE_32 ('O', 'H', 'C', 'I')
+#define PEI_IOH_EHCI_SIGNATURE SIGNATURE_32 ('E', 'H', 'C', 'I')
+
+typedef struct {
+ UINTN Signature;
+ PEI_USB_CONTROLLER_PPI UsbControllerPpi;
+ EFI_PEI_PPI_DESCRIPTOR PpiList;
+ UINTN MmioBase[IOH_MAX_OHCI_USB_CONTROLLERS];
+} IOH_OHCI_DEVICE;
+
+typedef struct {
+ UINTN Signature;
+ PEI_USB_CONTROLLER_PPI UsbControllerPpi;
+ EFI_PEI_PPI_DESCRIPTOR PpiList;
+ UINTN MmioBase[IOH_MAX_EHCI_USB_CONTROLLERS];
+} IOH_EHCI_DEVICE;
+
+#define IOH_OHCI_DEVICE_FROM_THIS(a) \
+ CR(a, IOH_OHCI_DEVICE, UsbControllerPpi, PEI_IOH_OHCI_SIGNATURE)
+
+#define IOH_EHCI_DEVICE_FROM_THIS(a) \
+ CR (a, IOH_EHCI_DEVICE, UsbControllerPpi, PEI_IOH_EHCI_SIGNATURE)
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf b/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf
new file mode 100644
index 0000000000..f06e21cdd0
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf
@@ -0,0 +1,59 @@
+## @file
+# Component description file for UsbPei 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 = UsbPei
+ FILE_GUID = 73E6F6B4-D029-4e87-8405-6067C8BD02A6
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = PeimInitializeIchUsb
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ UsbPei.c
+ UsbPei.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ IoLib
+ PciLib
+ PcdLib
+ BaseMemoryLib
+ PeimEntryPoint
+ DebugLib
+
+[Ppis]
+ gPeiUsbControllerPpiGuid # PPI ALWAYS_PRODUCED
+
+[FeaturePcd]
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdEhciRecoveryEnabled
+
+[Pcd]
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiQNCUsbControllerMemoryBaseAddress
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiP2PMemoryBaseAddress
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c
new file mode 100644
index 0000000000..31f8d59737
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c
@@ -0,0 +1,225 @@
+/** @file
+UEFI Component Name and Name2 protocol for OHCI 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 "Ohci.h"
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName = {
+ OhciComponentNameGetDriverName,
+ OhciComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) OhciComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) OhciComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOhciDriverNameTable[] = {
+ { "eng;en", L"Usb Ohci Driver" },
+ { NULL, NULL }
+};
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mOhciDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gOhciComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ USB_OHCI_HC_DEV *OhciDev;
+ EFI_USB_HC_PROTOCOL *UsbHc;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gOhciDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbHcProtocolGuid,
+ (VOID **) &UsbHc,
+ gOhciDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OhciDev = USB_OHCI_HC_DEV_FROM_THIS (UsbHc);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ OhciDev->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gOhciComponentName)
+ );
+
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h
new file mode 100644
index 0000000000..4d6b499b12
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h
@@ -0,0 +1,147 @@
+/** @file
+This file contains the delarations for componet name 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 _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+#endif
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h
new file mode 100644
index 0000000000..ca8baf5c36
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h
@@ -0,0 +1,138 @@
+/** @file
+This file contains the descriptor definination of OHCI spec
+
+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 _DESCRIPTOR_H
+#define _DESCRIPTOR_H
+
+#define ED_FUNC_ADD 0x0001
+#define ED_ENDPT_NUM 0x0002
+#define ED_DIR 0x0004
+#define ED_SPEED 0x0008
+#define ED_SKIP 0x0010
+#define ED_FORMAT 0x0020
+#define ED_MAX_PACKET 0x0040
+#define ED_TDTAIL_PTR 0x0080
+#define ED_HALTED 0x0100
+#define ED_DTTOGGLE 0x0200
+#define ED_TDHEAD_PTR 0x0400
+#define ED_NEXT_EDPTR 0x0800
+#define ED_PDATA 0x1000
+#define ED_ZERO 0x2000
+
+#define TD_BUFFER_ROUND 0x0001
+#define TD_DIR_PID 0x0002
+#define TD_DELAY_INT 0x0004
+#define TD_DT_TOGGLE 0x0008
+#define TD_ERROR_CNT 0x0010
+#define TD_COND_CODE 0x0020
+#define TD_CURR_BUFFER_PTR 0x0040
+#define TD_NEXT_PTR 0x0080
+#define TD_BUFFER_END_PTR 0x0100
+#define TD_PDATA 0x0200
+
+#define ED_FROM_TD_DIR 0x0
+#define ED_OUT_DIR 0x1
+#define ED_IN_DIR 0x2
+#define ED_FROM_TD_ALSO_DIR 0x3
+
+#define TD_SETUP_PID 0x00
+#define TD_OUT_PID 0x01
+#define TD_IN_PID 0x02
+#define TD_NODATA_PID 0x03
+
+#define HI_SPEED 0
+#define LO_SPEED 1
+
+#define TD_NO_ERROR 0x00
+#define TD_CRC_ERROR 0x01
+#define TD_BITSTUFFING_ERROR 0x02
+#define TD_TOGGLE_ERROR 0x03
+#define TD_DEVICE_STALL 0x04
+#define TD_NO_RESPONSE 0x05
+#define TD_PIDCHK_FAIL 0x06
+#define TD_PID_UNEXPECTED 0x07
+#define TD_DATA_OVERRUN 0x08
+#define TD_DATA_UNDERRUN 0x09
+#define TD_BUFFER_OVERRUN 0x0C
+#define TD_BUFFER_UNDERRUN 0x0D
+#define TD_TOBE_PROCESSED 0x0E
+#define TD_TOBE_PROCESSED_2 0x0F
+
+#define TD_NO_DELAY 0x7
+
+#define TD_INT 0x1
+#define TD_CTL 0x2
+#define TD_BLK 0x3
+
+typedef struct {
+ UINT32 Reserved:18;
+ UINT32 BufferRounding:1;
+ UINT32 DirPID:2;
+ UINT32 DelayInterrupt:3;
+ UINT32 DataToggle:2;
+ UINT32 ErrorCount:2;
+ UINT32 ConditionCode:4;
+} TD_DESCRIPTOR_WORD0;
+
+typedef struct _TD_DESCRIPTOR {
+ TD_DESCRIPTOR_WORD0 Word0;
+ UINT32 CurrBufferPointer; // 32-bit Physical Address of buffer
+ UINT32 NextTD; // 32-bit Physical Address of TD_DESCRIPTOR
+ UINT32 BufferEndPointer; // 32-bit Physical Address of buffer
+ UINT32 NextTDPointer; // 32-bit Physical Address of TD_DESCRIPTOR
+ UINT32 DataBuffer; // 32-bit Physical Address of buffer
+ UINT32 ActualSendLength;
+ UINT32 Reserved;
+} TD_DESCRIPTOR;
+
+typedef struct {
+ UINT32 FunctionAddress:7;
+ UINT32 EndPointNum:4;
+ UINT32 Direction:2;
+ UINT32 Speed:1;
+ UINT32 Skip:1;
+ UINT32 Format:1;
+ UINT32 MaxPacketSize:11;
+ UINT32 FreeSpace:5;
+} ED_DESCRIPTOR_WORD0;
+
+typedef struct {
+ UINT32 Halted:1;
+ UINT32 ToggleCarry:1;
+ UINT32 Zero:2;
+ UINT32 TdHeadPointer:28;
+} ED_DESCRIPTOR_WORD2;
+
+typedef struct _ED_DESCRIPTOR {
+ ED_DESCRIPTOR_WORD0 Word0;
+ UINT32 TdTailPointer; // 32-bit Physical Address of TD_DESCRIPTOR
+ ED_DESCRIPTOR_WORD2 Word2;
+ UINT32 NextED; // 32-bit Physical Address of ED_DESCRIPTOR
+} ED_DESCRIPTOR;
+
+#define TD_PTR(p) ((TD_DESCRIPTOR *)(UINTN)((p) << 4))
+#define ED_PTR(p) ((ED_DESCRIPTOR *)(UINTN)((p) << 4))
+#define RIGHT_SHIFT_4(p) ((UINT32)(p) >> 4)
+
+typedef enum {
+ CONTROL_LIST,
+ BULK_LIST,
+ INTERRUPT_LIST,
+ ISOCHRONOUS_LIST
+} DESCRIPTOR_LIST_TYPE;
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c
new file mode 100644
index 0000000000..f73a09bf4c
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c
@@ -0,0 +1,2488 @@
+/** @file
+This file contains the implementation of Usb Hc 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 "Ohci.h"
+
+/**
+ Provides software reset for the USB host controller.
+
+ @param This This EFI_USB_HC_PROTOCOL instance.
+ @param Attributes A bit mask of the reset operation to perform.
+
+ @retval EFI_SUCCESS The reset operation succeeded.
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
+ not currently supported by the host controller.
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciReset (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT16 Attributes
+ )
+{
+ EFI_STATUS Status;
+ USB_OHCI_HC_DEV *Ohc;
+ UINT8 Index;
+ UINT8 NumOfPorts;
+ UINT32 PowerOnGoodTime;
+ UINT32 Data32;
+ BOOLEAN Flag = FALSE;
+
+ if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+ if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {
+ gBS->Stall (50 * 1000);
+ Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall (50 * 1000);
+ //
+ // Wait for host controller reset.
+ //
+ PowerOnGoodTime = 50;
+ do {
+ gBS->Stall (1 * 1000);
+ Data32 = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ if ((Data32 & HC_RESET) == 0) {
+ Flag = TRUE;
+ break;
+ }
+ }while(PowerOnGoodTime--);
+ if (!Flag){
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ OhciFreeIntTransferMemory (Ohc);
+ Status = OhciInitializeInterruptList (Ohc);
+ OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);
+ if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) {
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall (50 * 1000);
+ }
+ //
+ // Initialize host controller operational registers
+ //
+ OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778);
+ OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);
+ OhciSetPeriodicStart (Ohc, 0x2a2f);
+ OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x3);
+ OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0);
+ OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0);
+ OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1);
+ //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);
+ //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);
+
+ OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0);
+ OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff);
+ OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE);
+ OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER);
+ OhciGetRootHubNumOfPorts (This, &NumOfPorts);
+ for (Index = 0; Index < NumOfPorts; Index++) {
+ if (!EFI_ERROR (OhciSetRootHubPortFeature (This, Index, EfiUsbPortReset))) {
+ gBS->Stall (200 * 1000);
+ OhciClearRootHubPortFeature (This, Index, EfiUsbPortReset);
+ gBS->Stall (1000);
+ OhciSetRootHubPortFeature (This, Index, EfiUsbPortEnable);
+ gBS->Stall (1000);
+ }
+ }
+ OhciSetMemoryPointer (Ohc, HC_HCCA, Ohc->HccaMemoryBlock);
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | BULK_ENABLE, 1); /*ISOCHRONOUS_ENABLE*/
+ OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);
+ gBS->Stall (50*1000);
+ //
+ // Wait till first SOF occurs, and then clear it
+ //
+ while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0);
+ OhciClearInterruptStatus (Ohc, START_OF_FRAME);
+ gBS->Stall (1000);
+
+ return Status;
+}
+
+/**
+ Retrieve the current state of the USB host controller.
+
+ @param This This EFI_USB_HC_PROTOCOL instance.
+ @param State Variable to return the current host controller
+ state.
+
+ @retval EFI_SUCCESS Host controller state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+ @retval EFI_DEVICE_ERROR An error was encountered while attempting to
+ retrieve the host controller's current state.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetState (
+ IN EFI_USB_HC_PROTOCOL *This,
+ OUT EFI_USB_HC_STATE *State
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ UINT32 FuncState;
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+ FuncState = OhciGetHcControl (Ohc, HC_FUNCTIONAL_STATE);
+
+ switch (FuncState) {
+ case HC_STATE_RESET:
+ case HC_STATE_RESUME:
+ *State = EfiUsbHcStateHalt;
+ break;
+
+ case HC_STATE_OPERATIONAL:
+ *State = EfiUsbHcStateOperational;
+ break;
+
+ case HC_STATE_SUSPEND:
+ *State = EfiUsbHcStateSuspend;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the USB host controller to a specific state.
+
+ @param This This EFI_USB_HC_PROTOCOL instance.
+ @param State The state of the host controller that will be set.
+
+ @retval EFI_SUCCESS The USB host controller was successfully placed
+ in the state specified by State.
+ @retval EFI_INVALID_PARAMETER State is invalid.
+ @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciSetState(
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN EFI_USB_HC_STATE State
+ )
+{
+ EFI_STATUS Status;
+ USB_OHCI_HC_DEV *Ohc;
+
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);
+
+ switch (State) {
+ case EfiUsbHcStateHalt:
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);
+ break;
+
+ case EfiUsbHcStateOperational:
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);
+ break;
+
+ case EfiUsbHcStateSuspend:
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_SUSPEND);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ gBS->Stall (1000);
+
+ return Status;
+}
+
+/**
+
+ Submits control transfer to a target USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+ @param MaxPaketLength Indicates the maximum packet size that the
+ default control transfer endpoint is capable of
+ sending or receiving.
+ @param Request A pointer to the USB device request that will be sent
+ to the USB device.
+ @param TransferDirection Specifies the data direction for the transfer.
+ There are three values available, DataIn, DataOut
+ and NoData.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param DataLength Indicates the size, in bytes, of the data buffer
+ specified by Data.
+ @param TimeOut Indicates the maximum time, in microseconds,
+ which the transfer is allowed to complete.
+ @param TransferResult A pointer to the detailed result information generated
+ by this control transfer.
+
+ @retval EFI_SUCCESS The control transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The control transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error.
+ Caller should check TranferResult for detailed error information.
+
+--*/
+
+
+EFI_STATUS
+EFIAPI
+OhciControlTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data OPTIONAL,
+ IN OUT UINTN *DataLength OPTIONAL,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ ED_DESCRIPTOR *HeadEd;
+ ED_DESCRIPTOR *Ed;
+ TD_DESCRIPTOR *HeadTd;
+ TD_DESCRIPTOR *SetupTd;
+ TD_DESCRIPTOR *DataTd;
+ TD_DESCRIPTOR *StatusTd;
+ TD_DESCRIPTOR *EmptyTd;
+ EFI_STATUS Status;
+ UINT32 DataPidDir;
+ UINT32 StatusPidDir;
+ UINTN TimeCount;
+ OHCI_ED_RESULT EdResult;
+
+ EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
+
+ UINTN ActualSendLength;
+ UINTN LeftLength;
+ UINT8 DataToggle;
+
+ VOID *ReqMapping = NULL;
+ UINTN ReqMapLength = 0;
+ EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0;
+
+ VOID *DataMapping = NULL;
+ UINTN DataMapLength = 0;
+ EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0;
+
+ HeadTd = NULL;
+ DataTd = NULL;
+
+ if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn &&
+ TransferDirection != EfiUsbNoData) ||
+ Request == NULL || DataLength == NULL || TransferResult == NULL ||
+ (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) ||
+ (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) ||
+ (IsSlowDevice && MaxPacketLength != 8) ||
+ (MaxPacketLength != 8 && MaxPacketLength != 16 &&
+ MaxPacketLength != 32 && MaxPacketLength != 64)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*DataLength > MAX_BYTES_PER_TD) {
+ DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\r\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);
+
+ if (TransferDirection == EfiUsbDataIn) {
+ DataPidDir = TD_IN_PID;
+ StatusPidDir = TD_OUT_PID;
+ } else {
+ DataPidDir = TD_OUT_PID;
+ StatusPidDir = TD_IN_PID;
+ }
+
+ Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n"));
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+ Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 0);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n"));
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall(20 * 1000);
+
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+ Ed = OhciCreateED (Ohc);
+ if (Ed == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\r\n"));
+ goto CTRL_EXIT;
+ }
+ OhciSetEDField (Ed, ED_SKIP, 1);
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+ OhciSetEDField (Ed, ED_ENDPT_NUM, 0);
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+ OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);
+ OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+ OhciSetEDField (Ed, ED_PDATA, 0);
+ OhciSetEDField (Ed, ED_ZERO, 0);
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);
+ HeadEd = OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL);
+ //
+ // Setup Stage
+ //
+ if(Request != NULL) {
+ ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST);
+ MapOp = EfiPciIoOperationBusMasterRead;
+ Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Request, &ReqMapLength, &ReqMapPhyAddr, &ReqMapping);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to Map Request Buffer\r\n"));
+ goto FREE_ED_BUFF;
+ }
+ }
+ SetupTd = OhciCreateTD (Ohc);
+ if (SetupTd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n"));
+ goto UNMAP_SETUP_BUFF;
+ }
+ HeadTd = SetupTd;
+ OhciSetTDField (SetupTd, TD_PDATA, 0);
+ OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1);
+ OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID);
+ OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY);
+ OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2);
+ OhciSetTDField (SetupTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINT32)ReqMapPhyAddr);
+ OhciSetTDField (SetupTd, TD_NEXT_PTR, 0);
+ OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINT32)(ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1));
+ SetupTd->ActualSendLength = sizeof (EFI_USB_DEVICE_REQUEST);
+ SetupTd->DataBuffer = (UINT32)ReqMapPhyAddr;
+ SetupTd->NextTDPointer = 0;
+
+ if (TransferDirection == EfiUsbDataIn) {
+ MapOp = EfiPciIoOperationBusMasterWrite;
+ } else {
+ MapOp = EfiPciIoOperationBusMasterRead;
+ }
+ DataMapLength = *DataLength;
+ if ((Data != NULL) && (DataMapLength != 0)) {
+ Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, Data, &DataMapLength, &DataMapPhyAddr, &DataMapping);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail To Map Data Buffer\r\n"));
+ goto FREE_TD_BUFF;
+ }
+ }
+ //
+ //Data Stage
+ //
+ LeftLength = DataMapLength;
+ ActualSendLength = DataMapLength;
+ DataToggle = 1;
+ while (LeftLength > 0) {
+ ActualSendLength = LeftLength;
+ if (LeftLength > MaxPacketLength) {
+ ActualSendLength = MaxPacketLength;
+ }
+ DataTd = OhciCreateTD (Ohc);
+ if (DataTd == NULL) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto UNMAP_DATA_BUFF;
+ }
+ OhciSetTDField (DataTd, TD_PDATA, 0);
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle);
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr);
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(DataMapPhyAddr + ActualSendLength - 1));
+ OhciSetTDField (DataTd, TD_NEXT_PTR, 0);
+ DataTd->ActualSendLength = (UINT32)ActualSendLength;
+ DataTd->DataBuffer = (UINT32)DataMapPhyAddr;
+ DataTd->NextTDPointer = 0;
+ OhciLinkTD (HeadTd, DataTd);
+ DataToggle ^= 1;
+ DataMapPhyAddr += ActualSendLength;
+ LeftLength -= ActualSendLength;
+ }
+ //
+ // Status Stage
+ //
+ StatusTd = OhciCreateTD (Ohc);
+ if (StatusTd == NULL) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto UNMAP_DATA_BUFF;
+ }
+ OhciSetTDField (StatusTd, TD_PDATA, 0);
+ OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1);
+ OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir);
+ OhciSetTDField (StatusTd, TD_DELAY_INT, 7);
+ OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3);
+ OhciSetTDField (StatusTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, 0);
+ OhciSetTDField (StatusTd, TD_NEXT_PTR, 0);
+ OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, 0);
+ StatusTd->ActualSendLength = 0;
+ StatusTd->DataBuffer = 0;
+ StatusTd->NextTDPointer = 0;
+ OhciLinkTD (HeadTd, StatusTd);
+ //
+ // Empty Stage
+ //
+ EmptyTd = OhciCreateTD (Ohc);
+ if (EmptyTd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto UNMAP_DATA_BUFF;
+ }
+ OhciSetTDField (EmptyTd, TD_PDATA, 0);
+ OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);
+ OhciSetTDField (EmptyTd, TD_DIR_PID, 0);
+ OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);
+ //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
+ EmptyTd->Word0.DataToggle = 0;
+ OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (EmptyTd, TD_COND_CODE, 0);
+ OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);
+ OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);
+ OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);
+ EmptyTd->ActualSendLength = 0;
+ EmptyTd->DataBuffer = 0;
+ EmptyTd->NextTDPointer = 0;
+ OhciLinkTD (HeadTd, EmptyTd);
+ Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;
+ OhciAttachTDListToED (Ed, HeadTd);
+ //
+ // For debugging, dump ED & TD buffer befor transferring
+ //
+ //
+ //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE);
+ //
+ OhciSetEDField (Ed, ED_SKIP, 0);
+ Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 1);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n"));
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+ goto UNMAP_DATA_BUFF;
+ }
+ Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n"));
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+ goto UNMAP_DATA_BUFF;
+ }
+ gBS->Stall(20 * 1000);
+
+
+ TimeCount = 0;
+ Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);
+
+ while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {
+ gBS->Stall (1000);
+ TimeCount++;
+ Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);
+ }
+ //
+ // For debugging, dump ED & TD buffer after transferring
+ //
+ //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE);
+ //
+ *TransferResult = ConvertErrorCode (EdResult.ErrorCode);
+
+ if (EdResult.ErrorCode != TD_NO_ERROR) {
+ if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {
+ DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut));
+ } else {
+ DEBUG ((EFI_D_INFO, "Control pipe broken\r\n"));
+ }
+ *DataLength = 0;
+ } else {
+ DEBUG ((EFI_D_INFO, "Control transfer successed\r\n"));
+ }
+
+UNMAP_DATA_BUFF:
+ OhciSetEDField (Ed, ED_SKIP, 1);
+ if (HeadEd == Ed) {
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+ } else {
+ HeadEd->NextED = Ed->NextED;
+ }
+ if(DataMapping != NULL) {
+ Ohc->PciIo->Unmap(Ohc->PciIo, DataMapping);
+ }
+
+FREE_TD_BUFF:
+ while (HeadTd) {
+ DataTd = HeadTd;
+ HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+ }
+
+UNMAP_SETUP_BUFF:
+ if(ReqMapping != NULL) {
+ Ohc->PciIo->Unmap(Ohc->PciIo, ReqMapping);
+ }
+
+FREE_ED_BUFF:
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+CTRL_EXIT:
+ return Status;
+}
+
+/**
+
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress The combination of an endpoint number and an
+ endpoint direction of the target USB device.
+ Each endpoint address supports data transfer in
+ one direction except the control endpoint
+ (whose default endpoint address is 0).
+ It is the caller's responsibility to make sure that
+ the EndPointAddress represents a bulk endpoint.
+ @param MaximumPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param DataLength When input, indicates the size, in bytes, of the data buffer
+ specified by Data. When output, indicates the actually
+ transferred data size.
+ @param DataToggle A pointer to the data toggle value. On input, it indicates
+ the initial data toggle value the bulk transfer should adopt;
+ on output, it is updated to indicate the data toggle value
+ of the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in microseconds, which the
+ transfer is allowed to complete.
+ TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The bulk transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The bulk transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.
+ Caller should check TranferResult for detailed error information.
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciBulkTransfer(
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaxPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ ED_DESCRIPTOR *HeadEd;
+ ED_DESCRIPTOR *Ed;
+ UINT8 EdDir;
+ UINT32 DataPidDir;
+ TD_DESCRIPTOR *HeadTd;
+ TD_DESCRIPTOR *DataTd;
+ TD_DESCRIPTOR *EmptyTd;
+ EFI_STATUS Status;
+ EFI_USB_DATA_DIRECTION TransferDirection;
+ UINT8 EndPointNum;
+ UINTN TimeCount;
+ OHCI_ED_RESULT EdResult;
+
+ EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
+ VOID *Mapping;
+ UINTN MapLength;
+ EFI_PHYSICAL_ADDRESS MapPyhAddr;
+ UINTN LeftLength;
+ UINTN ActualSendLength;
+ BOOLEAN FirstTD;
+
+ Mapping = NULL;
+ MapLength = 0;
+ MapPyhAddr = 0;
+ LeftLength = 0;
+ Status = EFI_SUCCESS;
+
+ if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||
+ *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||
+ (MaxPacketLength != 8 && MaxPacketLength != 16 &&
+ MaxPacketLength != 32 && MaxPacketLength != 64)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+ if ((EndPointAddress & 0x80) != 0) {
+ TransferDirection = EfiUsbDataIn;
+ EdDir = ED_IN_DIR;
+ DataPidDir = TD_IN_PID;
+ MapOp = EfiPciIoOperationBusMasterWrite;
+ } else {
+ TransferDirection = EfiUsbDataOut;
+ EdDir = ED_OUT_DIR;
+ DataPidDir = TD_OUT_PID;
+ MapOp = EfiPciIoOperationBusMasterRead;
+ }
+
+ EndPointNum = (EndPointAddress & 0xF);
+ EdResult.NextToggle = *DataToggle;
+
+ Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n"));
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+ Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n"));
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall(20 * 1000);
+
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+
+ Ed = OhciCreateED (Ohc);
+ if (Ed == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ OhciSetEDField (Ed, ED_SKIP, 1);
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+ OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+ OhciSetEDField (Ed, ED_SPEED, HI_SPEED);
+ OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+ OhciSetEDField (Ed, ED_PDATA, 0);
+ OhciSetEDField (Ed, ED_ZERO, 0);
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);
+ HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);
+
+ if(Data != NULL) {
+ MapLength = *DataLength;
+ Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n"));
+ goto FREE_ED_BUFF;
+ }
+ }
+ //
+ //Data Stage
+ //
+ LeftLength = MapLength;
+ ActualSendLength = MapLength;
+ HeadTd = NULL;
+ FirstTD = TRUE;
+ while (LeftLength > 0) {
+ ActualSendLength = LeftLength;
+ if (LeftLength > MaxPacketLength) {
+ ActualSendLength = MaxPacketLength;
+ }
+ DataTd = OhciCreateTD (Ohc);
+ if (DataTd == NULL) {
+ DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FREE_OHCI_TDBUFF;
+ }
+ OhciSetTDField (DataTd, TD_PDATA, 0);
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));
+ OhciSetTDField (DataTd, TD_NEXT_PTR, 0);
+ DataTd->ActualSendLength = (UINT32)ActualSendLength;
+ DataTd->DataBuffer = (UINT32)MapPyhAddr;
+ DataTd->NextTDPointer = 0;
+ if (FirstTD) {
+ HeadTd = DataTd;
+ FirstTD = FALSE;
+ } else {
+ OhciLinkTD (HeadTd, DataTd);
+ }
+ *DataToggle ^= 1;
+ MapPyhAddr += ActualSendLength;
+ LeftLength -= ActualSendLength;
+ }
+ //
+ // Empty Stage
+ //
+ EmptyTd = OhciCreateTD (Ohc);
+ if (EmptyTd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n"));
+ goto FREE_OHCI_TDBUFF;
+ }
+ OhciSetTDField (EmptyTd, TD_PDATA, 0);
+ OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);
+ OhciSetTDField (EmptyTd, TD_DIR_PID, 0);
+ OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);
+ //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
+ EmptyTd->Word0.DataToggle = 0;
+ OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (EmptyTd, TD_COND_CODE, 0);
+ OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);
+ OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);
+ OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);
+ EmptyTd->ActualSendLength = 0;
+ EmptyTd->DataBuffer = 0;
+ EmptyTd->NextTDPointer = 0;
+ OhciLinkTD (HeadTd, EmptyTd);
+ Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;
+ OhciAttachTDListToED (Ed, HeadTd);
+
+ OhciSetEDField (Ed, ED_SKIP, 0);
+ Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);
+ if (EFI_ERROR(Status)) {
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n"));
+ goto FREE_OHCI_TDBUFF;
+ }
+ Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1);
+ if (EFI_ERROR(Status)) {
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n"));
+ goto FREE_OHCI_TDBUFF;
+ }
+ gBS->Stall(20 * 1000);
+
+ TimeCount = 0;
+ Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);
+ while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {
+ gBS->Stall (1000);
+ TimeCount++;
+ Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);
+ }
+
+ *TransferResult = ConvertErrorCode (EdResult.ErrorCode);
+
+ if (EdResult.ErrorCode != TD_NO_ERROR) {
+ if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {
+ DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));
+ } else {
+ DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));
+ *DataToggle = EdResult.NextToggle;
+ }
+ *DataLength = 0;
+ } else {
+ DEBUG ((EFI_D_INFO, "Bulk transfer successed\r\n"));
+ }
+ //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);
+
+FREE_OHCI_TDBUFF:
+ OhciSetEDField (Ed, ED_SKIP, 1);
+ if (HeadEd == Ed) {
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+ }else {
+ HeadEd->NextED = Ed->NextED;
+ }
+ while (HeadTd) {
+ DataTd = HeadTd;
+ HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+ }
+
+ if(Mapping != NULL) {
+ Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);
+ }
+
+FREE_ED_BUFF:
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+ return Status;
+}
+/**
+
+ Submits an interrupt transfer to an interrupt endpoint of a USB device.
+
+ @param Ohc Device private data
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress The combination of an endpoint number and an endpoint
+ direction of the target USB device. Each endpoint address
+ supports data transfer in one direction except the
+ control endpoint (whose default endpoint address is 0).
+ It is the caller's responsibility to make sure that
+ the EndPointAddress represents an interrupt endpoint.
+ @param IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+ @param MaxPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+ @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
+ the host and the target interrupt endpoint.
+ If FALSE, the specified asynchronous interrupt pipe
+ is canceled.
+ @param DataToggle A pointer to the data toggle value. On input, it is valid
+ when IsNewTransfer is TRUE, and it indicates the initial
+ data toggle value the asynchronous interrupt transfer
+ should adopt.
+ On output, it is valid when IsNewTransfer is FALSE,
+ and it is updated to indicate the data toggle value of
+ the subsequent asynchronous interrupt transfer.
+ @param PollingInterval Indicates the interval, in milliseconds, that the
+ asynchronous interrupt transfer is polled.
+ This parameter is required when IsNewTransfer is TRUE.
+ @param UCBuffer Uncacheable buffer
+ @param DataLength Indicates the length of data to be received at the
+ rate specified by PollingInterval from the target
+ asynchronous interrupt endpoint. This parameter
+ is only required when IsNewTransfer is TRUE.
+ @param CallBackFunction The Callback function.This function is called at the
+ rate specified by PollingInterval.This parameter is
+ only required when IsNewTransfer is TRUE.
+ @param Context The context that is passed to the CallBackFunction.
+ This is an optional parameter and may be NULL.
+ @param IsPeriodic Periodic interrupt or not
+ @param OutputED The correspoding ED carried out
+ @param OutputTD The correspoding TD carried out
+
+
+ @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully
+ submitted or canceled.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+
+EFI_STATUS
+OhciInterruptTransfer (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle OPTIONAL,
+ IN UINTN PollingInterval OPTIONAL,
+ IN VOID *UCBuffer OPTIONAL,
+ IN UINTN DataLength OPTIONAL,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,
+ IN VOID *Context OPTIONAL,
+ IN BOOLEAN IsPeriodic OPTIONAL,
+ OUT ED_DESCRIPTOR **OutputED OPTIONAL,
+ OUT TD_DESCRIPTOR **OutputTD OPTIONAL
+ )
+{
+ ED_DESCRIPTOR *Ed;
+ UINT8 EdDir;
+ ED_DESCRIPTOR *HeadEd;
+ TD_DESCRIPTOR *HeadTd;
+ TD_DESCRIPTOR *DataTd;
+ TD_DESCRIPTOR *EmptTd;
+ UINTN Depth;
+ UINTN Index;
+ EFI_STATUS Status;
+ UINT8 EndPointNum;
+ UINT32 DataPidDir;
+ EFI_USB_DATA_DIRECTION TransferDirection;
+ INTERRUPT_CONTEXT_ENTRY *Entry;
+ EFI_TPL OldTpl;
+ BOOLEAN FirstTD;
+
+ VOID *Mapping;
+ UINTN MapLength;
+ EFI_PHYSICAL_ADDRESS MapPyhAddr;
+ UINTN LeftLength;
+ UINTN ActualSendLength;
+
+
+ if (DataLength > MAX_BYTES_PER_TD) {
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Error param\r\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((EndPointAddress & 0x80) != 0) {
+ TransferDirection = EfiUsbDataIn;
+ EdDir = ED_IN_DIR;
+ DataPidDir = TD_IN_PID;
+ } else {
+ TransferDirection = EfiUsbDataOut;
+ EdDir = ED_OUT_DIR;
+ DataPidDir = TD_OUT_PID;
+ }
+
+ EndPointNum = (EndPointAddress & 0xF);
+
+ if (!IsNewTransfer) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0);
+ OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle);
+ Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum);
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+ }
+ MapLength = DataLength;
+ Status = Ohc->PciIo->Map(
+ Ohc->PciIo,
+ EfiPciIoOperationBusMasterWrite,
+ UCBuffer,
+ &MapLength,
+ &MapPyhAddr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n"));
+ goto EXIT;
+ }
+ Depth = 5;
+ Index = 1;
+ while (PollingInterval >= Index * 2 && Depth > 0) {
+ Index *= 2;
+ Depth--;
+ }
+ //
+ //ED Stage
+ //
+ HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth);
+ if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) {
+ OhciSetEDField (Ed, ED_SKIP, 1);
+ } else {
+ Ed = OhciCreateED (Ohc);
+ if (Ed == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n"));
+ goto UNMAP_OHCI_XBUFF;
+ }
+ OhciSetEDField (Ed, ED_SKIP, 1);
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+ OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+ OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);
+ OhciSetEDField (Ed, ED_FORMAT, 0);
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+ OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0);
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);
+ OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd);
+ }
+ //
+ //Data Stage
+ //
+ LeftLength = MapLength;
+ ActualSendLength = MapLength;
+ HeadTd = NULL;
+ FirstTD = TRUE;
+ while (LeftLength > 0) {
+ ActualSendLength = LeftLength;
+ if (LeftLength > MaxPacketLength) {
+ ActualSendLength = MaxPacketLength;
+ }
+ DataTd = OhciCreateTD (Ohc);
+ if (DataTd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
+ goto FREE_OHCI_TDBUFF;
+ }
+ OhciSetTDField (DataTd, TD_PDATA, 0);
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));
+ OhciSetTDField (DataTd, TD_NEXT_PTR, 0);
+ DataTd->ActualSendLength = (UINT32)ActualSendLength;
+ DataTd->DataBuffer = (UINT32)MapPyhAddr;
+ DataTd->NextTDPointer = 0;
+ if (FirstTD) {
+ HeadTd = DataTd;
+ FirstTD = FALSE;
+ } else {
+ OhciLinkTD (HeadTd, DataTd);
+ }
+ *DataToggle ^= 1;
+ MapPyhAddr += ActualSendLength;
+ LeftLength -= ActualSendLength;
+ }
+
+ EmptTd = OhciCreateTD (Ohc);
+ if (EmptTd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n"));
+ goto FREE_OHCI_TDBUFF;
+ }
+ OhciSetTDField (EmptTd, TD_PDATA, 0);
+ OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0);
+ OhciSetTDField (EmptTd, TD_DIR_PID, 0);
+ OhciSetTDField (EmptTd, TD_DELAY_INT, 0);
+ //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle);
+ EmptTd->Word0.DataToggle = 0;
+ OhciSetTDField (EmptTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (EmptTd, TD_COND_CODE, 0);
+ OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0);
+ OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0);
+ OhciSetTDField (EmptTd, TD_NEXT_PTR, 0);
+ EmptTd->ActualSendLength = 0;
+ EmptTd->DataBuffer = 0;
+ EmptTd->NextTDPointer = 0;
+ OhciLinkTD (HeadTd, EmptTd);
+ Ed->TdTailPointer = (UINT32)(UINTN)EmptTd;
+ OhciAttachTDListToED (Ed, HeadTd);
+
+ if (OutputED != NULL) {
+ *OutputED = Ed;
+ }
+ if (OutputTD != NULL) {
+ *OutputTD = HeadTd;
+ }
+
+ if (CallBackFunction != NULL) {
+ Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY));
+ if (Entry == NULL) {
+ goto FREE_OHCI_TDBUFF;
+ }
+
+ Entry->DeviceAddress = DeviceAddress;
+ Entry->EndPointAddress = EndPointAddress;
+ Entry->Ed = Ed;
+ Entry->DataTd = HeadTd;
+ Entry->IsSlowDevice = IsSlowDevice;
+ Entry->MaxPacketLength = MaxPacketLength;
+ Entry->PollingInterval = PollingInterval;
+ Entry->CallBackFunction = CallBackFunction;
+ Entry->Context = Context;
+ Entry->IsPeriodic = IsPeriodic;
+ Entry->UCBuffer = UCBuffer;
+ Entry->UCBufferMapping = Mapping;
+ Entry->DataLength = DataLength;
+ Entry->Toggle = DataToggle;
+ Entry->NextEntry = NULL;
+ OhciAddInterruptContextEntry (Ohc, Entry);
+ }
+ OhciSetEDField (Ed, ED_SKIP, 0);
+
+ if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) {
+ Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);
+ gBS->Stall (1000);
+ }
+
+ return EFI_SUCCESS;
+
+FREE_OHCI_TDBUFF:
+ while (HeadTd) {
+ DataTd = HeadTd;
+ HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+ }
+
+//FREE_OHCI_EDBUFF:
+ if ((HeadEd != Ed) && HeadEd && Ed) {
+ while(HeadEd->NextED != (UINT32)(UINTN)Ed) {
+ HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED);
+ }
+ HeadEd->NextED = Ed->NextED;
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+ }
+
+UNMAP_OHCI_XBUFF:
+ Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);
+
+EXIT:
+ return Status;
+}
+
+/**
+
+ Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress The combination of an endpoint number and an endpoint
+ direction of the target USB device. Each endpoint address
+ supports data transfer in one direction except the
+ control endpoint (whose default endpoint address is 0).
+ It is the caller's responsibility to make sure that
+ the EndPointAddress represents an interrupt endpoint.
+ @param IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+ @param MaxiumPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+ @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
+ the host and the target interrupt endpoint.
+ If FALSE, the specified asynchronous interrupt pipe
+ is canceled.
+ @param DataToggle A pointer to the data toggle value. On input, it is valid
+ when IsNewTransfer is TRUE, and it indicates the initial
+ data toggle value the asynchronous interrupt transfer
+ should adopt.
+ On output, it is valid when IsNewTransfer is FALSE,
+ and it is updated to indicate the data toggle value of
+ the subsequent asynchronous interrupt transfer.
+ @param PollingInterval Indicates the interval, in milliseconds, that the
+ asynchronous interrupt transfer is polled.
+ This parameter is required when IsNewTransfer is TRUE.
+ @param DataLength Indicates the length of data to be received at the
+ rate specified by PollingInterval from the target
+ asynchronous interrupt endpoint. This parameter
+ is only required when IsNewTransfer is TRUE.
+ @param CallBackFunction The Callback function.This function is called at the
+ rate specified by PollingInterval.This parameter is
+ only required when IsNewTransfer is TRUE.
+ @param Context The context that is passed to the CallBackFunction.
+ This is an optional parameter and may be NULL.
+
+ @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully
+ submitted or canceled.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciAsyncInterruptTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle OPTIONAL,
+ IN UINTN PollingInterval OPTIONAL,
+ IN UINTN DataLength OPTIONAL,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,
+ IN VOID *Context OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ USB_OHCI_HC_DEV *Ohc;
+ VOID *UCBuffer;
+
+ if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 ||
+ (IsNewTransfer && (DataLength == 0 ||
+ (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+ if ( IsNewTransfer ) {
+ UCBuffer = AllocatePool(DataLength);
+ if (UCBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ UCBuffer = NULL;
+ }
+ Status = OhciInterruptTransfer (
+ Ohc,
+ DeviceAddress,
+ EndPointAddress,
+ IsSlowDevice,
+ MaxPacketLength,
+ IsNewTransfer,
+ DataToggle,
+ PollingInterval,
+ UCBuffer,
+ DataLength,
+ CallBackFunction,
+ Context,
+ TRUE,
+ NULL,
+ NULL
+ );
+ if ( IsNewTransfer ) {
+ if (EFI_ERROR(Status)) {
+ gBS->FreePool (UCBuffer);
+ }
+ }
+ return Status;
+}
+
+
+/**
+
+ Submits synchronous interrupt transfer to an interrupt endpoint
+ of a USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress The combination of an endpoint number and an endpoint
+ direction of the target USB device. Each endpoint
+ address supports data transfer in one direction
+ except the control endpoint (whose default
+ endpoint address is 0). It is the caller's responsibility
+ to make sure that the EndPointAddress represents
+ an interrupt endpoint.
+ @param IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+ @param MaxPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param DataLength On input, the size, in bytes, of the data buffer specified
+ by Data. On output, the number of bytes transferred.
+ @param DataToggle A pointer to the data toggle value. On input, it indicates
+ the initial data toggle value the synchronous interrupt
+ transfer should adopt;
+ on output, it is updated to indicate the data toggle value
+ of the subsequent synchronous interrupt transfer.
+ @param TimeOut Indicates the maximum time, in microseconds, which the
+ transfer is allowed to complete.
+ @param TransferResult A pointer to the detailed result information from
+ the synchronous interrupt transfer.
+
+ @retval EFI_UNSUPPORTED This interface not available.
+ @retval EFI_INVALID_PARAMETER Parameters not follow spec
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciSyncInterruptTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ EFI_STATUS Status;
+ ED_DESCRIPTOR *Ed;
+ TD_DESCRIPTOR *HeadTd;
+ OHCI_ED_RESULT EdResult;
+ VOID *UCBuffer;
+
+ if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 ||
+ (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) ||
+ DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+ UCBuffer = AllocatePool (*DataLength);
+ if (UCBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = OhciInterruptTransfer (
+ Ohc,
+ DeviceAddress,
+ EndPointAddress,
+ IsSlowDevice,
+ MaxPacketLength,
+ TRUE,
+ DataToggle,
+ 1,
+ UCBuffer,
+ *DataLength,
+ NULL,
+ NULL,
+ FALSE,
+ &Ed,
+ &HeadTd
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);
+ while (Status == EFI_NOT_READY && TimeOut > 0) {
+ gBS->Stall (1000);
+ TimeOut--;
+ Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);
+ }
+
+ *TransferResult = ConvertErrorCode (EdResult.ErrorCode);
+ }
+ CopyMem(Data, UCBuffer, *DataLength);
+ Status = OhciInterruptTransfer (
+ Ohc,
+ DeviceAddress,
+ EndPointAddress,
+ IsSlowDevice,
+ MaxPacketLength,
+ FALSE,
+ DataToggle,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ FALSE,
+ NULL,
+ NULL
+ );
+
+ return Status;
+}
+/**
+
+ Submits isochronous transfer to a target USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress End point address
+ @param MaximumPacketLength Indicates the maximum packet size that the
+ default control transfer endpoint is capable of
+ sending or receiving.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param DataLength Indicates the size, in bytes, of the data buffer
+ specified by Data.
+ @param TransferResult A pointer to the detailed result information generated
+ by this control transfer.
+
+ @retval EFI_UNSUPPORTED This interface not available
+ @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciIsochronousTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN DataLength,
+ OUT UINT32 *TransferResult
+ )
+{
+ if (Data == NULL || DataLength == 0 || TransferResult == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Submits Async isochronous transfer to a target USB device.
+
+ @param his A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress End point address
+ @param MaximumPacketLength Indicates the maximum packet size that the
+ default control transfer endpoint is capable of
+ sending or receiving.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param IsochronousCallBack When the transfer complete, the call back function will be called
+ @param Context Pass to the call back function as parameter
+
+ @retval EFI_UNSUPPORTED This interface not available
+ @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciAsyncIsochronousTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN DataLength,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context OPTIONAL
+ )
+{
+
+ if (Data == NULL || DataLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Retrieves the number of root hub ports.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param NumOfPorts A pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+**/
+EFI_STATUS
+EFIAPI
+OhciGetRootHubNumOfPorts (
+ IN EFI_USB_HC_PROTOCOL *This,
+ OUT UINT8 *NumOfPorts
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+ if (NumOfPorts == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);
+
+ return EFI_SUCCESS;
+}
+/**
+
+ Retrieves the current status of a USB root hub port.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.
+ @param PortNumber Specifies the root hub port from which the status
+ is to be retrieved. This value is zero-based. For example,
+ if a root hub has two ports, then the first port is numbered 0,
+ and the second port is numbered 1.
+ @param PortStatus A pointer to the current port status bits and
+ port status change bits.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber
+ was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER Port number not valid
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubPortStatus (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ UINT8 NumOfPorts;
+
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+ OhciGetRootHubNumOfPorts (This, &NumOfPorts);
+ if (PortNumber >= NumOfPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_POWER;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+
+ Sets a feature for the specified root hub port.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be set.
+ @param PortFeature Indicates the feature selector associated
+ with the feature set request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for the
+ USB root hub port specified by PortNumber.
+ @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+**/
+EFI_STATUS
+EFIAPI
+OhciSetRootHubPortFeature (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ EFI_STATUS Status;
+ UINT8 NumOfPorts;
+ UINTN RetryTimes;
+
+ OhciGetRootHubNumOfPorts (This, &NumOfPorts);
+ if (PortNumber >= NumOfPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+ Status = EFI_SUCCESS;
+
+
+ switch (PortFeature) {
+ case EfiUsbPortPower:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortReset:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||
+ OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);
+ break;
+
+ case EfiUsbPortEnable:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+
+ case EfiUsbPortSuspend:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+
+ Clears a feature for the specified root hub port.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the
+ USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_DEVICE_ERROR Some error happened when clearing feature
+**/
+EFI_STATUS
+EFIAPI
+OhciClearRootHubPortFeature (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ EFI_STATUS Status;
+ UINT8 NumOfPorts;
+ UINTN RetryTimes;
+
+
+ OhciGetRootHubNumOfPorts (This, &NumOfPorts);
+ if (PortNumber >= NumOfPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+ Status = EFI_SUCCESS;
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortSuspend:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortReset:
+ break;
+
+ case EfiUsbPortPower:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortConnectChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortResetChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+
+ case EfiUsbPortEnableChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortSuspendChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortOverCurrentChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ gBS->Stall (1000);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = {
+ OHCIDriverBindingSupported,
+ OHCIDriverBindingStart,
+ OHCIDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+
+/**
+ Entry point for EFI drivers.
+
+ @param ImageHandle EFI_HANDLE.
+ @param SystemTable EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Driver is successfully loaded.
+ @return Others Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gOhciDriverBinding,
+ ImageHandle,
+ &gOhciComponentName,
+ &gOhciComponentName2
+ );
+}
+
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has UsbHcProtocol installed will be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB_CLASSC UsbClassCReg;
+ //
+ // Test whether there is PCI IO Protocol attached on the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_CLASSCODE_OFFSET,
+ sizeof (USB_CLASSC) / sizeof (UINT8),
+ &UsbClassCReg
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+ }
+ //
+ // Test whether the controller belongs to OHCI type
+ //
+ if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
+ (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
+ (UsbClassCReg.ProgInterface != PCI_IF_OHCI)
+ ) {
+
+ Status = EFI_UNSUPPORTED;
+ }
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+
+}
+
+/**
+
+ Allocate and initialize the empty OHCI device.
+
+ @param PciIo The PCIIO to use.
+ @param OriginalPciAttributes The original PCI attributes.
+
+ @return Allocated OHCI device If err, return NULL.
+
+**/
+
+USB_OHCI_HC_DEV *
+OhciAllocateDev (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT64 OriginalPciAttributes
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ EFI_STATUS Status;
+ VOID *Buf;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *Map;
+ UINTN Pages;
+ UINTN Bytes;
+
+ Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV));
+ if (Ohc == NULL) {
+ return NULL;
+ }
+
+ Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE;
+ Ohc->PciIo = PciIo;
+
+ Ohc->UsbHc.Reset = OhciReset;
+ Ohc->UsbHc.GetState = OhciGetState;
+ Ohc->UsbHc.SetState = OhciSetState;
+ Ohc->UsbHc.ControlTransfer = OhciControlTransfer;
+ Ohc->UsbHc.BulkTransfer = OhciBulkTransfer;
+ Ohc->UsbHc.AsyncInterruptTransfer = OhciAsyncInterruptTransfer;
+ Ohc->UsbHc.SyncInterruptTransfer = OhciSyncInterruptTransfer;
+ Ohc->UsbHc.IsochronousTransfer = OhciIsochronousTransfer;
+ Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer;
+ Ohc->UsbHc.GetRootHubPortNumber = OhciGetRootHubNumOfPorts;
+ Ohc->UsbHc.GetRootHubPortStatus = OhciGetRootHubPortStatus;
+ Ohc->UsbHc.SetRootHubPortFeature = OhciSetRootHubPortFeature;
+ Ohc->UsbHc.ClearRootHubPortFeature = OhciClearRootHubPortFeature;
+ Ohc->UsbHc.MajorRevision = 0x1;
+ Ohc->UsbHc.MinorRevision = 0x1;
+
+ Ohc->OriginalPciAttributes = OriginalPciAttributes;
+
+ Ohc->HccaMemoryBlock = NULL;
+ Ohc->HccaMemoryMapping = NULL;
+ Ohc->HccaMemoryBuf = NULL;
+ Ohc->HccaMemoryPages = 0;
+ Ohc->InterruptContextList = NULL;
+ Ohc->ControllerNameTable = NULL;
+ Ohc->HouseKeeperTimer = NULL;
+
+ Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0);
+ if(Ohc->MemPool == NULL) {
+ goto FREE_DEV_BUFFER;
+ }
+
+ Bytes = 4096;
+ Pages = EFI_SIZE_TO_PAGES (Bytes);
+
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Pages,
+ &Buf,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_MEM_POOL;
+ }
+
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ Buf,
+ &Bytes,
+ &PhyAddr,
+ &Map
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != 4096)) {
+ goto FREE_MEM_PAGE;
+ }
+
+ Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr;
+ Ohc->HccaMemoryMapping = Map;
+ Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf;
+ Ohc->HccaMemoryPages = Pages;
+
+ return Ohc;
+
+FREE_MEM_PAGE:
+ PciIo->FreeBuffer (PciIo, Pages, Buf);
+FREE_MEM_POOL:
+ UsbHcFreeMemPool (Ohc->MemPool);
+FREE_DEV_BUFFER:
+ FreePool(Ohc);
+
+ return NULL;
+}
+/**
+
+ Free the OHCI device and release its associated resources.
+
+ @param Ohc The OHCI device to release.
+
+**/
+VOID
+OhciFreeDev (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ OhciFreeFixedIntMemory (Ohc);
+
+ if (Ohc->HouseKeeperTimer != NULL) {
+ gBS->CloseEvent (Ohc->HouseKeeperTimer);
+ }
+
+ if (Ohc->ExitBootServiceEvent != NULL) {
+ gBS->CloseEvent (Ohc->ExitBootServiceEvent);
+ }
+
+ if (Ohc->MemPool != NULL) {
+ UsbHcFreeMemPool (Ohc->MemPool);
+ }
+
+ if (Ohc->HccaMemoryMapping != NULL ) {
+ Ohc->PciIo->FreeBuffer (Ohc->PciIo, Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf);
+ }
+
+ if (Ohc->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (Ohc->ControllerNameTable);
+ }
+
+ FreePool (Ohc);
+}
+/**
+
+ Uninstall all Ohci Interface.
+
+ @param Controller Controller handle.
+ @param This Protocol instance pointer.
+
+**/
+VOID
+OhciCleanDevUp (
+ IN EFI_HANDLE Controller,
+ IN EFI_USB_HC_PROTOCOL *This
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+
+ //
+ // Retrieve private context structure
+ //
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);
+
+ //
+ // Uninstall the USB_HC and USB_HC2 protocol
+ //
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ &Ohc->UsbHc
+ );
+
+ //
+ // Cancel the timer event
+ //
+ gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0);
+
+ //
+ // Stop the host controller
+ //
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);
+ This->Reset (This, EFI_USB_HC_RESET_GLOBAL);
+ This->SetState (This, EfiUsbHcStateHalt);
+
+ //
+ // Free resources
+ //
+ OhciFreeDynamicIntMemory (Ohc);
+
+ //
+ // Restore original PCI attributes
+ //
+ Ohc->PciIo->Attributes (
+ Ohc->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Ohc->OriginalPciAttributes,
+ NULL
+ );
+
+ //
+ // Free the private context structure
+ //
+ OhciFreeDev (Ohc);
+}
+
+/**
+
+ One notified function to stop the Host Controller when gBS->ExitBootServices() called.
+
+ @param Event Pointer to this event
+ @param Context Event hanlder private data
+**/
+VOID
+EFIAPI
+OhcExitBootService (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ EFI_USB_HC_PROTOCOL *UsbHc;
+ Ohc = (USB_OHCI_HC_DEV *) Context;
+
+ UsbHc = &Ohc->UsbHc;
+ //
+ // Stop the Host Controller
+ //
+ //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT);
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);
+ UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL);
+ UsbHc->SetState (UsbHc, EfiUsbHcStateHalt);
+
+ return;
+}
+
+
+/**
+ Starting the Usb OHCI Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB_OHCI_HC_DEV *Ohc;
+ UINT64 Supports;
+ UINT64 OriginalPciAttributes;
+ BOOLEAN PciAttributesSaved;
+
+ //
+ // Open PCIIO, then enable the HC device and turn off emulation
+ //
+ Ohc = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PciAttributesSaved = FALSE;
+ //
+ // Save original PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &OriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PCIIO;
+ }
+ PciAttributesSaved = TRUE;
+
+ //
+ // Robustnesss improvement such as for UoL
+ // Default is not required.
+ //
+ //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
+ // OhciTurnOffUsbEmulation (PciIo);
+ //}
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PCIIO;
+ }
+ //
+ //Allocate memory for OHC private data structure
+ //
+ Ohc = OhciAllocateDev(PciIo, OriginalPciAttributes);
+ if (Ohc == NULL){
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CLOSE_PCIIO;
+ }
+
+ //Status = OhciInitializeInterruptList ( Uhc );
+ //if (EFI_ERROR (Status)) {
+ // goto FREE_OHC;
+ //}
+
+ //
+ // Set 0.01 s timer
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OhciHouseKeeper,
+ Ohc,
+ &Ohc->HouseKeeperTimer
+ );
+ if (EFI_ERROR (Status)) {
+ goto FREE_OHC;
+ }
+
+ Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10);
+ if (EFI_ERROR (Status)) {
+ goto FREE_OHC;
+ }
+
+ //
+ //Install Host Controller Protocol
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiUsbHcProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Ohc->UsbHc
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Install protocol error"));
+ goto FREE_OHC;
+ }
+ //
+ // Create event to stop the HC when exit boot service.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OhcExitBootService,
+ Ohc,
+ &gEfiEventExitBootServicesGuid,
+ &Ohc->ExitBootServiceEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Create exit boot event error"));
+ goto UNINSTALL_USBHC;
+ }
+ AddUnicodeString2 (
+ "eng",
+ gOhciComponentName.SupportedLanguages,
+ &Ohc->ControllerNameTable,
+ L"Usb Universal Host Controller",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gOhciComponentName2.SupportedLanguages,
+ &Ohc->ControllerNameTable,
+ L"Usb Universal Host Controller",
+ FALSE
+ );
+
+ return EFI_SUCCESS;
+
+UNINSTALL_USBHC:
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ &Ohc->UsbHc,
+ NULL
+ );
+
+FREE_OHC:
+ OhciFreeDev (Ohc);
+
+CLOSE_PCIIO:
+ if (PciAttributesSaved) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ OriginalPciAttributes,
+ NULL
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_HC_PROTOCOL *UsbHc;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ (VOID **)&UsbHc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OhciCleanDevUp(Controller, UsbHc);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_SUCCESS;
+}
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h
new file mode 100644
index 0000000000..1bfe4a8b7f
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h
@@ -0,0 +1,669 @@
+/** @file
+Provides the definition of Usb Hc Protocol and OHCI controller
+private data structure.
+
+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 _OHCI_H
+#define _OHCI_H
+
+
+#include <Uefi.h>
+
+#include <Protocol/UsbHostController.h>
+#include <Protocol/PciIo.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+
+typedef struct _USB_OHCI_HC_DEV USB_OHCI_HC_DEV;
+
+#include "UsbHcMem.h"
+#include "OhciReg.h"
+#include "OhciSched.h"
+#include "OhciUrb.h"
+#include "Descriptor.h"
+#include "ComponentName.h"
+#include "OhciDebug.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2;
+
+#define USB_OHCI_HC_DEV_SIGNATURE SIGNATURE_32('o','h','c','i')
+
+typedef struct _HCCA_MEMORY_BLOCK{
+ UINT32 HccaInterruptTable[32]; // 32-bit Physical Address to ED_DESCRIPTOR
+ UINT16 HccaFrameNumber;
+ UINT16 HccaPad;
+ UINT32 HccaDoneHead; // 32-bit Physical Address to TD_DESCRIPTOR
+ UINT8 Reserved[116];
+} HCCA_MEMORY_BLOCK;
+
+
+struct _USB_OHCI_HC_DEV {
+ UINTN Signature;
+ EFI_USB_HC_PROTOCOL UsbHc;
+ EFI_USB2_HC_PROTOCOL Usb2Hc;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 OriginalPciAttributes;
+
+ HCCA_MEMORY_BLOCK *HccaMemoryBlock;
+ VOID *HccaMemoryBuf;
+ VOID *HccaMemoryMapping;
+ UINTN HccaMemoryPages;
+
+ ED_DESCRIPTOR *IntervalList[6][32];
+ INTERRUPT_CONTEXT_ENTRY *InterruptContextList;
+ VOID *MemPool;
+
+ UINT32 ToggleFlag;
+
+ EFI_EVENT HouseKeeperTimer;
+ //
+ // ExitBootServicesEvent is used to stop the OHC DMA operation
+ // after exit boot service.
+ //
+ EFI_EVENT ExitBootServiceEvent;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+};
+
+#define USB_OHCI_HC_DEV_FROM_THIS(a) CR(a, USB_OHCI_HC_DEV, UsbHc, USB_OHCI_HC_DEV_SIGNATURE)
+#define USB2_OHCI_HC_DEV_FROM_THIS(a) CR(a, USB_OHCI_HC_DEV, Usb2Hc, USB_OHCI_HC_DEV_SIGNATURE)
+
+//
+// Func List
+//
+
+/**
+ Provides software reset for the USB host controller.
+
+ @param This This EFI_USB_HC_PROTOCOL instance.
+ @param Attributes A bit mask of the reset operation to perform.
+
+ @retval EFI_SUCCESS The reset operation succeeded.
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
+ not currently supported by the host controller.
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciReset (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT16 Attributes
+ );
+/**
+ Retrieve the current state of the USB host controller.
+
+ @param This This EFI_USB_HC_PROTOCOL instance.
+ @param State Variable to return the current host controller
+ state.
+
+ @retval EFI_SUCCESS Host controller state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+ @retval EFI_DEVICE_ERROR An error was encountered while attempting to
+ retrieve the host controller's current state.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetState (
+ IN EFI_USB_HC_PROTOCOL *This,
+ OUT EFI_USB_HC_STATE *State
+ );
+/**
+ Sets the USB host controller to a specific state.
+
+ @param This This EFI_USB_HC_PROTOCOL instance.
+ @param State The state of the host controller that will be set.
+
+ @retval EFI_SUCCESS The USB host controller was successfully placed
+ in the state specified by State.
+ @retval EFI_INVALID_PARAMETER State is invalid.
+ @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciSetState(
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN EFI_USB_HC_STATE State
+ );
+/**
+
+ Submits control transfer to a target USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+ @param MaxPaketLength Indicates the maximum packet size that the
+ default control transfer endpoint is capable of
+ sending or receiving.
+ @param Request A pointer to the USB device request that will be sent
+ to the USB device.
+ @param TransferDirection Specifies the data direction for the transfer.
+ There are three values available, DataIn, DataOut
+ and NoData.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param DataLength Indicates the size, in bytes, of the data buffer
+ specified by Data.
+ @param TimeOut Indicates the maximum time, in microseconds,
+ which the transfer is allowed to complete.
+ @param TransferResult A pointer to the detailed result information generated
+ by this control transfer.
+
+ @retval EFI_SUCCESS The control transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The control transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error.
+ Caller should check TranferResult for detailed error information.
+
+--*/
+
+
+EFI_STATUS
+EFIAPI
+OhciControlTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data OPTIONAL,
+ IN OUT UINTN *DataLength OPTIONAL,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+/**
+
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress The combination of an endpoint number and an
+ endpoint direction of the target USB device.
+ Each endpoint address supports data transfer in
+ one direction except the control endpoint
+ (whose default endpoint address is 0).
+ It is the caller's responsibility to make sure that
+ the EndPointAddress represents a bulk endpoint.
+ @param MaximumPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param DataLength When input, indicates the size, in bytes, of the data buffer
+ specified by Data. When output, indicates the actually
+ transferred data size.
+ @param DataToggle A pointer to the data toggle value. On input, it indicates
+ the initial data toggle value the bulk transfer should adopt;
+ on output, it is updated to indicate the data toggle value
+ of the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in microseconds, which the
+ transfer is allowed to complete.
+ TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The bulk transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The bulk transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.
+ Caller should check TranferResult for detailed error information.
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciBulkTransfer(
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaxPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+/**
+
+ Submits an interrupt transfer to an interrupt endpoint of a USB device.
+
+ @param Ohc Device private data
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress The combination of an endpoint number and an endpoint
+ direction of the target USB device. Each endpoint address
+ supports data transfer in one direction except the
+ control endpoint (whose default endpoint address is 0).
+ It is the caller's responsibility to make sure that
+ the EndPointAddress represents an interrupt endpoint.
+ @param IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+ @param MaxPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+ @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
+ the host and the target interrupt endpoint.
+ If FALSE, the specified asynchronous interrupt pipe
+ is canceled.
+ @param DataToggle A pointer to the data toggle value. On input, it is valid
+ when IsNewTransfer is TRUE, and it indicates the initial
+ data toggle value the asynchronous interrupt transfer
+ should adopt.
+ On output, it is valid when IsNewTransfer is FALSE,
+ and it is updated to indicate the data toggle value of
+ the subsequent asynchronous interrupt transfer.
+ @param PollingInterval Indicates the interval, in milliseconds, that the
+ asynchronous interrupt transfer is polled.
+ This parameter is required when IsNewTransfer is TRUE.
+ @param UCBuffer Uncacheable buffer
+ @param DataLength Indicates the length of data to be received at the
+ rate specified by PollingInterval from the target
+ asynchronous interrupt endpoint. This parameter
+ is only required when IsNewTransfer is TRUE.
+ @param CallBackFunction The Callback function.This function is called at the
+ rate specified by PollingInterval.This parameter is
+ only required when IsNewTransfer is TRUE.
+ @param Context The context that is passed to the CallBackFunction.
+ This is an optional parameter and may be NULL.
+ @param IsPeriodic Periodic interrupt or not
+ @param OutputED The correspoding ED carried out
+ @param OutputTD The correspoding TD carried out
+
+
+ @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully
+ submitted or canceled.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+
+EFI_STATUS
+OhciInterruptTransfer (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle OPTIONAL,
+ IN UINTN PollingInterval OPTIONAL,
+ IN VOID *UCBuffer OPTIONAL,
+ IN UINTN DataLength OPTIONAL,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,
+ IN VOID *Context OPTIONAL,
+ IN BOOLEAN IsPeriodic OPTIONAL,
+ OUT ED_DESCRIPTOR **OutputED OPTIONAL,
+ OUT TD_DESCRIPTOR **OutputTD OPTIONAL
+ );
+/**
+
+ Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress The combination of an endpoint number and an endpoint
+ direction of the target USB device. Each endpoint address
+ supports data transfer in one direction except the
+ control endpoint (whose default endpoint address is 0).
+ It is the caller's responsibility to make sure that
+ the EndPointAddress represents an interrupt endpoint.
+ @param IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+ @param MaxiumPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+ @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
+ the host and the target interrupt endpoint.
+ If FALSE, the specified asynchronous interrupt pipe
+ is canceled.
+ @param DataToggle A pointer to the data toggle value. On input, it is valid
+ when IsNewTransfer is TRUE, and it indicates the initial
+ data toggle value the asynchronous interrupt transfer
+ should adopt.
+ On output, it is valid when IsNewTransfer is FALSE,
+ and it is updated to indicate the data toggle value of
+ the subsequent asynchronous interrupt transfer.
+ @param PollingInterval Indicates the interval, in milliseconds, that the
+ asynchronous interrupt transfer is polled.
+ This parameter is required when IsNewTransfer is TRUE.
+ @param DataLength Indicates the length of data to be received at the
+ rate specified by PollingInterval from the target
+ asynchronous interrupt endpoint. This parameter
+ is only required when IsNewTransfer is TRUE.
+ @param CallBackFunction The Callback function.This function is called at the
+ rate specified by PollingInterval.This parameter is
+ only required when IsNewTransfer is TRUE.
+ @param Context The context that is passed to the CallBackFunction.
+ This is an optional parameter and may be NULL.
+
+ @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully
+ submitted or canceled.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciAsyncInterruptTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle OPTIONAL,
+ IN UINTN PollingInterval OPTIONAL,
+ IN UINTN DataLength OPTIONAL,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,
+ IN VOID *Context OPTIONAL
+ );
+/**
+
+ Submits synchronous interrupt transfer to an interrupt endpoint
+ of a USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress The combination of an endpoint number and an endpoint
+ direction of the target USB device. Each endpoint
+ address supports data transfer in one direction
+ except the control endpoint (whose default
+ endpoint address is 0). It is the caller's responsibility
+ to make sure that the EndPointAddress represents
+ an interrupt endpoint.
+ @param IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+ @param MaxPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param DataLength On input, the size, in bytes, of the data buffer specified
+ by Data. On output, the number of bytes transferred.
+ @param DataToggle A pointer to the data toggle value. On input, it indicates
+ the initial data toggle value the synchronous interrupt
+ transfer should adopt;
+ on output, it is updated to indicate the data toggle value
+ of the subsequent synchronous interrupt transfer.
+ @param TimeOut Indicates the maximum time, in microseconds, which the
+ transfer is allowed to complete.
+ @param TransferResult A pointer to the detailed result information from
+ the synchronous interrupt transfer.
+
+ @retval EFI_UNSUPPORTED This interface not available.
+ @retval EFI_INVALID_PARAMETER Parameters not follow spec
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciSyncInterruptTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+/**
+
+ Submits isochronous transfer to a target USB device.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress End point address
+ @param MaximumPacketLength Indicates the maximum packet size that the
+ default control transfer endpoint is capable of
+ sending or receiving.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param DataLength Indicates the size, in bytes, of the data buffer
+ specified by Data.
+ @param TransferResult A pointer to the detailed result information generated
+ by this control transfer.
+
+ @retval EFI_UNSUPPORTED This interface not available
+ @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL
+
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciIsochronousTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN DataLength,
+ OUT UINT32 *TransferResult
+ );
+/**
+
+ Submits Async isochronous transfer to a target USB device.
+
+ @param his A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ @param EndPointAddress End point address
+ @param MaximumPacketLength Indicates the maximum packet size that the
+ default control transfer endpoint is capable of
+ sending or receiving.
+ @param Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ @param IsochronousCallBack When the transfer complete, the call back function will be called
+ @param Context Pass to the call back function as parameter
+
+ @retval EFI_UNSUPPORTED This interface not available
+ @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciAsyncIsochronousTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN DataLength,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context OPTIONAL
+ );
+
+/**
+
+ Retrieves the number of root hub ports.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param NumOfPorts A pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+**/
+EFI_STATUS
+EFIAPI
+OhciGetRootHubNumOfPorts (
+ IN EFI_USB_HC_PROTOCOL *This,
+ OUT UINT8 *NumOfPorts
+ );
+/**
+
+ Retrieves the current status of a USB root hub port.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.
+ @param PortNumber Specifies the root hub port from which the status
+ is to be retrieved. This value is zero-based. For example,
+ if a root hub has two ports, then the first port is numbered 0,
+ and the second port is numbered 1.
+ @param PortStatus A pointer to the current port status bits and
+ port status change bits.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber
+ was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER Port number not valid
+**/
+
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubPortStatus (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ );
+
+/**
+
+ Sets a feature for the specified root hub port.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be set.
+ @param PortFeature Indicates the feature selector associated
+ with the feature set request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for the
+ USB root hub port specified by PortNumber.
+ @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+**/
+EFI_STATUS
+EFIAPI
+OhciSetRootHubPortFeature (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+/**
+
+ Clears a feature for the specified root hub port.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the
+ USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_DEVICE_ERROR Some error happened when clearing feature
+**/
+EFI_STATUS
+EFIAPI
+OhciClearRootHubPortFeature (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+
+/**
+ Test to see if this driver supports ControllerHandle. Any
+ ControllerHandle that has UsbHcProtocol installed will be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @return EFI_SUCCESS This driver supports this device.
+ @return EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+
+OHCIDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starting the Usb OHCI Driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.
+ @param ChildHandleBuffer List of handles for the children we need to stop.
+
+ @return EFI_SUCCESS
+ @return others
+
+**/
+EFI_STATUS
+EFIAPI
+OHCIDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c
new file mode 100644
index 0000000000..69d268a4dd
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c
@@ -0,0 +1,84 @@
+/** @file
+This file provides the information dump support for OHCI when in debug mode.
+
+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 "Ohci.h"
+
+
+/*++
+
+ Print the data of ED and the TDs attached to the ED
+
+ @param Uhc Pointer to OHCI private data
+ @param Ed Pointer to a ED to free
+ @param Td Pointer to the Td head
+
+ @retval EFI_SUCCESS ED
+
+**/
+EFI_STATUS
+OhciDumpEdTdInfo (
+ IN USB_OHCI_HC_DEV *Uhc,
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *Td,
+ BOOLEAN Stage
+ )
+{
+ UINT32 Index;
+
+ if (Stage) {
+ DEBUG ((EFI_D_INFO, "\n Before executing command\n"));
+ }else{
+ DEBUG ((EFI_D_INFO, "\n after executing command\n"));
+ }
+ if (Ed != NULL) {
+ DEBUG ((EFI_D_INFO, "\nED Address:%p, ED buffer:\n", Ed));
+ DEBUG ((EFI_D_INFO, "DWord0 :TD Tail :TD Head :Next ED\n"));
+ for (Index = 0; Index < sizeof (ED_DESCRIPTOR)/4; Index ++) {
+ DEBUG ((EFI_D_INFO, "%8x ", *((UINT32*)(Ed) + Index) ));
+ }
+ DEBUG ((EFI_D_INFO, "\nNext TD buffer:%p\n", Td));
+ }
+ while (Td != NULL) {
+ if (Td->Word0.DirPID == TD_SETUP_PID) {
+ DEBUG ((EFI_D_INFO, "\nSetup PID "));
+ }else if (Td->Word0.DirPID == TD_OUT_PID) {
+ DEBUG ((EFI_D_INFO, "\nOut PID "));
+ }else if (Td->Word0.DirPID == TD_IN_PID) {
+ DEBUG ((EFI_D_INFO, "\nIn PID "));
+ }else if (Td->Word0.DirPID == TD_NODATA_PID) {
+ DEBUG ((EFI_D_INFO, "\nNo data PID "));
+ }
+ DEBUG ((EFI_D_INFO, "TD Address:%p, TD buffer:\n", Td));
+ DEBUG ((EFI_D_INFO, "DWord0 :CuBuffer:Next TD :Buff End:Next TD :DataBuff:ActLength\n"));
+ for (Index = 0; Index < sizeof (TD_DESCRIPTOR)/4; Index ++) {
+ DEBUG ((EFI_D_INFO, "%8x ", *((UINT32*)(Td) + Index) ));
+ }
+ DEBUG ((EFI_D_INFO, "\nCurrent TD Data buffer(size%d)\n", (UINT32)Td->ActualSendLength));
+ for (Index = 0; Index < Td->ActualSendLength; Index ++) {
+ DEBUG ((EFI_D_INFO, "%2x ", *(UINT8 *)(UINTN)(Td->DataBuffer + Index) ));
+ }
+ Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer);
+ }
+ DEBUG ((EFI_D_INFO, "\n TD buffer End\n"));
+
+ return EFI_SUCCESS;
+}
+
+
+
+
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h
new file mode 100644
index 0000000000..9217157a45
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h
@@ -0,0 +1,48 @@
+/** @file
+This file contains the definination for host controller
+debug support 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.
+
+**/
+
+
+
+/*++
+
+Routine Description:
+
+ Print the data of ED and the TDs attached to the ED
+
+ @param Uhc Pointer to OHCI private data
+ @param Ed Pointer to a ED to free
+ @param Td Pointer to the Td head
+
+ @retval EFI_SUCCESS ED
+
+**/
+EFI_STATUS
+OhciDumpEdTdInfo (
+ IN USB_OHCI_HC_DEV *Uhc,
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *Td,
+ BOOLEAN Stage
+ );
+
+
+
+
+
+
+
+
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf
new file mode 100644
index 0000000000..1d3f950b06
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf
@@ -0,0 +1,77 @@
+## @file
+# OHCI USB Host Controller UEFI 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 = OhciDxe
+ FILE_GUID = 4ACA697E-F883-446f-98F7-096416FFFFFF
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = OHCIDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gOhciDriverBinding
+# COMPONENT_NAME = gOhciComponentName
+# COMPONENT_NAME2 = gOhciComponentName2
+#
+[Sources]
+ Descriptor.h
+ Ohci.c
+ Ohci.h
+ OhciSched.c
+ OhciSched.h
+ OhciReg.c
+ OhciReg.h
+ OhciUrb.c
+ OhciUrb.h
+ OhciDebug.c
+ OhciDebug.h
+ ComponentName.c
+ ComponentName.h
+ UsbHcMem.c
+ UsbHcMem.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiUsbHcProtocolGuid ## BY_START
+
+#
+# [Event]
+# ##
+# # Periodic timer event for checking the result of interrupt transfer execution.
+# #
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+#
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c
new file mode 100644
index 0000000000..09f591d858
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c
@@ -0,0 +1,1399 @@
+/** @file
+The OHCI register operation 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.
+
+**/
+
+
+#include "Ohci.h"
+
+/**
+
+ Get OHCI operational reg value
+
+ @param PciIo PciIo protocol instance
+ @param Offset Offset of the operational reg
+
+ @retval Value of the register
+
+**/
+UINT32
+OhciGetOperationalReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Value;
+ EFI_STATUS Status;
+
+ Status = PciIo->Mem.Read(PciIo, EfiPciIoWidthUint32, OHC_BAR_INDEX, Offset, 1, &Value);
+
+ return Value;
+}
+/**
+
+ Set OHCI operational reg value
+
+ @param PciIo PCI Bus Io protocol instance
+ @param Offset Offset of the operational reg
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set to the reg
+
+**/
+
+
+EFI_STATUS
+OhciSetOperationalReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN VOID *Value
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PciIo->Mem.Write(PciIo, EfiPciIoWidthUint32, OHC_BAR_INDEX, Offset, 1, Value);
+
+ return Status;
+}
+/**
+
+ Get HcRevision reg value
+
+ @param PciIo PCI Bus Io protocol instance
+
+ @retval Value of the register
+
+**/
+
+
+UINT32
+OhciGetHcRevision (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ return OhciGetOperationalReg (PciIo, HC_REVISION);
+}
+/**
+
+ Set HcReset reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcReset (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcRESET Reset;
+
+ Status = EFI_SUCCESS;
+ *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR);
+
+ if (Field & RESET_SYSTEM_BUS) {
+ Reset.FSBIR = Value;
+ }
+
+ if (Field & RESET_HOST_CONTROLLER) {
+ Reset.FHR = Value;
+ }
+
+ if (Field & RESET_CLOCK_GENERATION) {
+ Reset.CGR = Value;
+ }
+
+ if (Field & RESET_SSE_GLOBAL) {
+ Reset.SSE = Value;
+ }
+
+ if (Field & RESET_PSPL) {
+ Reset.PSPL = Value;
+ }
+
+ if (Field & RESET_PCPL) {
+ Reset.PCPL = Value;
+ }
+
+ if (Field & RESET_SSEP1) {
+ Reset.SSEP1 = Value;
+ }
+
+ if (Field & RESET_SSEP2) {
+ Reset.SSEP2 = Value;
+ }
+
+ if (Field & RESET_SSEP3) {
+ Reset.SSEP3 = Value;
+ }
+
+ OhciSetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR, &Reset);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get specific field of HcReset reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcReset (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Field
+ )
+{
+ HcRESET Reset;
+ UINT32 Value;
+
+
+ *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR);
+ Value = 0;
+
+ switch (Field) {
+ case RESET_SYSTEM_BUS:
+ Value = Reset.FSBIR;
+ break;
+
+ case RESET_HOST_CONTROLLER:
+ Value = Reset.FHR;
+ break;
+
+ case RESET_CLOCK_GENERATION:
+ Value = Reset.CGR;
+ break;
+
+ case RESET_SSE_GLOBAL:
+ Value = Reset.SSE;
+ break;
+
+ case RESET_PSPL:
+ Value = Reset.PSPL;
+ break;
+
+ case RESET_PCPL:
+ Value = Reset.PCPL;
+ break;
+
+ case RESET_SSEP1:
+ Value = Reset.SSEP1;
+ break;
+
+ case RESET_SSEP2:
+ Value = Reset.SSEP2;
+ break;
+
+ case RESET_SSEP3:
+ Value = Reset.SSEP3;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+
+ return Value;
+}
+
+/**
+
+ Set HcControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcCONTROL Control;
+
+
+
+ *(UINT32 *) &Control = OhciGetOperationalReg (Ohc->PciIo, HC_CONTROL);
+
+ if (Field & CONTROL_BULK_RATIO) {
+ Control.ControlBulkRatio = Value;
+ }
+
+ if (Field & HC_FUNCTIONAL_STATE) {
+ Control.FunctionalState = Value;
+ }
+
+ if (Field & PERIODIC_ENABLE) {
+ Control.PeriodicEnable = Value;
+ }
+
+ if (Field & CONTROL_ENABLE) {
+ Control.ControlEnable = Value;
+ }
+
+ if (Field & ISOCHRONOUS_ENABLE) {
+ Control.IsochronousEnable = Value;
+ }
+
+ if (Field & BULK_ENABLE) {
+ Control.BulkEnable = Value;
+ }
+
+ if (Field & INTERRUPT_ROUTING) {
+ Control.InterruptRouting = Value;
+ }
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_CONTROL, &Control);
+
+ return Status;
+}
+
+
+/**
+
+ Get specific field of HcControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+
+UINT32
+OhciGetHcControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcCONTROL Control;
+
+ *(UINT32 *) &Control = OhciGetOperationalReg (Ohc->PciIo, HC_CONTROL);
+
+ switch (Field) {
+ case CONTROL_BULK_RATIO:
+ return Control.ControlBulkRatio;
+ break;
+ case PERIODIC_ENABLE:
+ return Control.PeriodicEnable;
+ break;
+ case CONTROL_ENABLE:
+ return Control.ControlEnable;
+ break;
+ case BULK_ENABLE:
+ return Control.BulkEnable;
+ break;
+ case ISOCHRONOUS_ENABLE:
+ return Control.IsochronousEnable;
+ break;
+ case HC_FUNCTIONAL_STATE:
+ return Control.FunctionalState;
+ break;
+ case INTERRUPT_ROUTING:
+ return Control.InterruptRouting;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set HcCommand reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcCommandStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcCOMMAND_STATUS CommandStatus;
+
+ ZeroMem (&CommandStatus, sizeof (HcCOMMAND_STATUS));
+
+ if(Field & HC_RESET){
+ CommandStatus.HcReset = Value;
+ }
+
+ if(Field & CONTROL_LIST_FILLED){
+ CommandStatus.ControlListFilled = Value;
+ }
+
+ if(Field & BULK_LIST_FILLED){
+ CommandStatus.BulkListFilled = Value;
+ }
+
+ if(Field & CHANGE_OWNER_REQUEST){
+ CommandStatus.ChangeOwnerRequest = Value;
+ }
+
+ if(Field & SCHEDULE_OVERRUN_COUNT){
+ CommandStatus.ScheduleOverrunCount = Value;
+ }
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS, &CommandStatus);
+
+ return Status;
+}
+
+/**
+
+ Get specific field of HcCommand reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcCommandStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcCOMMAND_STATUS CommandStatus;
+
+ *(UINT32 *) &CommandStatus = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS);
+
+ switch (Field){
+ case HC_RESET:
+ return CommandStatus.HcReset;
+ break;
+ case CONTROL_LIST_FILLED:
+ return CommandStatus.ControlListFilled;
+ break;
+ case BULK_LIST_FILLED:
+ return CommandStatus.BulkListFilled;
+ break;
+ case CHANGE_OWNER_REQUEST:
+ return CommandStatus.ChangeOwnerRequest;
+ break;
+ case SCHEDULE_OVERRUN_COUNT:
+ return CommandStatus.ScheduleOverrunCount;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Clear specific fields of Interrupt Status
+
+ @param Ohc UHC private data
+ @param Field Field to clear
+
+ @retval EFI_SUCCESS Fields cleared
+
+**/
+
+EFI_STATUS
+OhciClearInterruptStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ EFI_STATUS Status;
+ HcINTERRUPT_STATUS InterruptStatus;
+
+ ZeroMem (&InterruptStatus, sizeof (HcINTERRUPT_STATUS));
+
+ if(Field & SCHEDULE_OVERRUN){
+ InterruptStatus.SchedulingOverrun = 1;
+ }
+
+ if(Field & WRITEBACK_DONE_HEAD){
+ InterruptStatus.WriteBackDone = 1;
+ }
+ if(Field & START_OF_FRAME){
+ InterruptStatus.Sof = 1;
+ }
+
+ if(Field & RESUME_DETECT){
+ InterruptStatus.ResumeDetected = 1;
+ }
+
+ if(Field & UNRECOVERABLE_ERROR){
+ InterruptStatus.UnrecoverableError = 1;
+ }
+
+ if(Field & FRAME_NUMBER_OVERFLOW){
+ InterruptStatus.FrameNumOverflow = 1;
+ }
+
+ if(Field & ROOTHUB_STATUS_CHANGE){
+ InterruptStatus.RHStatusChange = 1;
+ }
+
+ if(Field & OWNERSHIP_CHANGE){
+ InterruptStatus.OwnerChange = 1;
+ }
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_STATUS, &InterruptStatus);
+
+ return Status;
+}
+
+/**
+
+ Get fields of HcInterrupt reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcINTERRUPT_STATUS InterruptStatus;
+
+ *(UINT32 *) &InterruptStatus = OhciGetOperationalReg (Ohc->PciIo, HC_INTERRUPT_STATUS);
+
+ switch (Field){
+ case SCHEDULE_OVERRUN:
+ return InterruptStatus.SchedulingOverrun;
+ break;
+
+ case WRITEBACK_DONE_HEAD:
+ return InterruptStatus.WriteBackDone;
+ break;
+
+ case START_OF_FRAME:
+ return InterruptStatus.Sof;
+ break;
+
+ case RESUME_DETECT:
+ return InterruptStatus.ResumeDetected;
+ break;
+
+ case UNRECOVERABLE_ERROR:
+ return InterruptStatus.UnrecoverableError;
+ break;
+
+ case FRAME_NUMBER_OVERFLOW:
+ return InterruptStatus.FrameNumOverflow;
+ break;
+
+ case ROOTHUB_STATUS_CHANGE:
+ return InterruptStatus.RHStatusChange;
+ break;
+
+ case OWNERSHIP_CHANGE:
+ return InterruptStatus.OwnerChange;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set Interrupt Control reg value
+
+ @param Ohc UHC private data
+ @param StatEnable Enable or Disable
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetInterruptControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN BOOLEAN StatEnable,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcINTERRUPT_CONTROL InterruptState;
+
+
+ ZeroMem (&InterruptState, sizeof (HcINTERRUPT_CONTROL));
+
+ if(Field & SCHEDULE_OVERRUN) {
+ InterruptState.SchedulingOverrunInt = Value;
+ }
+
+ if(Field & WRITEBACK_DONE_HEAD) {
+ InterruptState.WriteBackDoneInt = Value;
+ }
+ if(Field & START_OF_FRAME) {
+ InterruptState.SofInt = Value;
+ }
+
+ if(Field & RESUME_DETECT) {
+ InterruptState.ResumeDetectedInt = Value;
+ }
+
+ if(Field & UNRECOVERABLE_ERROR) {
+ InterruptState.UnrecoverableErrorInt = Value;
+ }
+
+ if(Field & FRAME_NUMBER_OVERFLOW) {
+ InterruptState.FrameNumOverflowInt = Value;
+ }
+
+ if(Field & ROOTHUB_STATUS_CHANGE) {
+ InterruptState.RHStatusChangeInt = Value;
+ }
+
+ if(Field & OWNERSHIP_CHANGE) {
+ InterruptState.OwnerChangedInt = Value;
+ }
+
+ if(Field & MASTER_INTERRUPT) {
+ InterruptState.MasterInterruptEnable = Value;
+ }
+
+ if (StatEnable) {
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_ENABLE, &InterruptState);
+ } else {
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_DISABLE, &InterruptState);
+ }
+
+ return Status;
+}
+
+/**
+
+ Get field of HcInterruptControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcINTERRUPT_CONTROL InterruptState;
+
+ *(UINT32 *) &InterruptState = OhciGetOperationalReg (Ohc->PciIo, HC_INTERRUPT_ENABLE);
+
+ switch (Field){
+ case SCHEDULE_OVERRUN:
+ return InterruptState.SchedulingOverrunInt;
+ break;
+
+ case WRITEBACK_DONE_HEAD:
+ return InterruptState.WriteBackDoneInt;
+ break;
+
+ case START_OF_FRAME:
+ return InterruptState.SofInt;
+ break;
+
+ case RESUME_DETECT:
+ return InterruptState.ResumeDetectedInt;
+ break;
+
+ case UNRECOVERABLE_ERROR:
+ return InterruptState.UnrecoverableErrorInt;
+ break;
+
+ case FRAME_NUMBER_OVERFLOW:
+ return InterruptState.FrameNumOverflowInt;
+ break;
+
+ case ROOTHUB_STATUS_CHANGE:
+ return InterruptState.RHStatusChangeInt;
+ break;
+
+ case OWNERSHIP_CHANGE:
+ return InterruptState.OwnerChangedInt;
+ break;
+
+ case MASTER_INTERRUPT:
+ return InterruptState.MasterInterruptEnable;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set memory pointer of specific type
+
+ @param Ohc UHC private data
+ @param PointerType Type of the pointer to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Memory pointer set
+
+**/
+
+EFI_STATUS
+OhciSetMemoryPointer(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 PointerType,
+ IN VOID *Value
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Verify;
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, PointerType, &Value);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Verify = OhciGetOperationalReg (Ohc->PciIo, PointerType);
+
+ while (Verify != (UINT32)(UINTN) Value) {
+ gBS->Stall(1000);
+ Verify = OhciGetOperationalReg (Ohc->PciIo, PointerType);
+ };
+
+
+ return Status;
+}
+
+/**
+
+ Get memory pointer of specific type
+
+ @param Ohc UHC private data
+ @param PointerType Type of pointer
+
+ @retval Memory pointer of the specific type
+
+**/
+
+VOID *
+OhciGetMemoryPointer (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 PointerType
+ )
+{
+
+ return (VOID *)(UINTN) OhciGetOperationalReg (Ohc->PciIo, PointerType);
+}
+
+
+/**
+
+ Set Frame Interval value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameInterval (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcFRM_INTERVAL FrameInterval;
+
+
+ *(UINT32 *) &FrameInterval = OhciGetOperationalReg(Ohc->PciIo, HC_FRM_INTERVAL);
+
+ if (Field & FRAME_INTERVAL) {
+ FrameInterval.FrmIntervalToggle = !FrameInterval.FrmIntervalToggle;
+ FrameInterval.FrameInterval = Value;
+ }
+
+ if (Field & FS_LARGEST_DATA_PACKET) {
+ FrameInterval.FSMaxDataPacket = Value;
+ }
+
+ if (Field & FRMINT_TOGGLE) {
+ FrameInterval.FrmIntervalToggle = Value;
+ }
+
+ Status = OhciSetOperationalReg (
+ Ohc->PciIo,
+ HC_FRM_INTERVAL,
+ &FrameInterval
+ );
+
+ return Status;
+}
+
+
+/**
+
+ Get field of frame interval reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetFrameInterval (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcFRM_INTERVAL FrameInterval;
+
+ *(UINT32 *) &FrameInterval = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_INTERVAL);
+
+ switch (Field){
+ case FRAME_INTERVAL:
+ return FrameInterval.FrameInterval;
+ break;
+
+ case FS_LARGEST_DATA_PACKET:
+ return FrameInterval.FSMaxDataPacket;
+ break;
+
+ case FRMINT_TOGGLE:
+ return FrameInterval.FrmIntervalToggle;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set Frame Remaining reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameRemaining (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcFRAME_REMAINING FrameRemaining;
+
+
+ *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING);
+
+ FrameRemaining.FrameRemaining = Value;
+ FrameRemaining.FrameRemainingToggle = !FrameRemaining.FrameRemainingToggle;
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING, &FrameRemaining);
+
+ return Status;
+}
+/**
+
+ Get value of frame remaining reg
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of frame remaining reg
+
+**/
+UINT32
+OhciGetFrameRemaining (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+
+{
+ HcFRAME_REMAINING FrameRemaining;
+
+
+ *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING);
+
+ switch (Field){
+ case FRAME_REMAINING:
+ return FrameRemaining.FrameRemaining;
+ break;
+
+ case FRAME_REMAIN_TOGGLE:
+ return FrameRemaining.FrameRemainingToggle;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set frame number reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameNumber(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_FRM_NUMBER, &Value);
+
+ return Status;
+}
+
+/**
+
+ Get frame number reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of frame number reg
+
+**/
+
+UINT32
+OhciGetFrameNumber (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ return OhciGetOperationalReg(Ohc->PciIo, HC_FRM_NUMBER);
+}
+
+/**
+
+ Set period start reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetPeriodicStart (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_PERIODIC_START, &Value);
+
+ return Status;
+}
+
+
+/**
+
+ Get periodic start reg value
+
+ @param Ohc UHC private data
+
+ @param Value of periodic start reg
+
+**/
+
+UINT32
+OhciGetPeriodicStart (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ return OhciGetOperationalReg(Ohc->PciIo, HC_PERIODIC_START);
+}
+
+
+/**
+
+ Set Ls Threshold reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetLsThreshold (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_LS_THREASHOLD, &Value);
+
+ return Status;
+}
+
+
+/**
+
+ Get Ls Threshold reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of Ls Threshold reg
+
+**/
+
+UINT32
+OhciGetLsThreshold (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ return OhciGetOperationalReg(Ohc->PciIo, HC_LS_THREASHOLD);
+}
+
+/**
+
+ Set Root Hub Descriptor reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetRootHubDescriptor (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcRH_DESC_A DescriptorA;
+ HcRH_DESC_B DescriptorB;
+
+
+ if (Field & (RH_DEV_REMOVABLE | RH_PORT_PWR_CTRL_MASK)) {
+ *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_B);
+
+ if(Field & RH_DEV_REMOVABLE) {
+ DescriptorB.DeviceRemovable = Value;
+ }
+ if(Field & RH_PORT_PWR_CTRL_MASK) {
+ DescriptorB.PortPowerControlMask = Value;
+ }
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_DESC_B, &DescriptorB);
+
+ return Status;
+ }
+
+ *(UINT32 *)&DescriptorA = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_A);
+
+ if(Field & RH_NUM_DS_PORTS) {
+ DescriptorA.NumDownStrmPorts = Value;
+ }
+ if(Field & RH_NO_PSWITCH) {
+ DescriptorA.NoPowerSwitch = Value;
+ }
+ if(Field & RH_PSWITCH_MODE) {
+ DescriptorA.PowerSwitchMode = Value;
+ }
+ if(Field & RH_DEVICE_TYPE) {
+ DescriptorA.DeviceType = Value;
+ }
+ if(Field & RH_OC_PROT_MODE) {
+ DescriptorA.OverCurrentProtMode = Value;
+ }
+ if(Field & RH_NOC_PROT) {
+ DescriptorA.NoOverCurrentProtMode = Value;
+ }
+ if(Field & RH_NO_POTPGT) {
+ DescriptorA.PowerOnToPowerGoodTime = Value;
+ }
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_DESC_A, &DescriptorA);
+
+ return Status;
+}
+
+
+/**
+
+ Get Root Hub Descriptor reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubDescriptor (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcRH_DESC_A DescriptorA;
+ HcRH_DESC_B DescriptorB;
+
+
+ *(UINT32 *) &DescriptorA = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_A);
+ *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_B);
+
+ switch (Field){
+ case RH_DEV_REMOVABLE:
+ return DescriptorB.DeviceRemovable;
+ break;
+
+ case RH_PORT_PWR_CTRL_MASK:
+ return DescriptorB.PortPowerControlMask;
+ break;
+
+ case RH_NUM_DS_PORTS:
+ return DescriptorA.NumDownStrmPorts;
+ break;
+
+ case RH_NO_PSWITCH:
+ return DescriptorA.NoPowerSwitch;
+ break;
+
+ case RH_PSWITCH_MODE:
+ return DescriptorA.PowerSwitchMode;
+ break;
+
+ case RH_DEVICE_TYPE:
+ return DescriptorA.DeviceType;
+ break;
+
+ case RH_OC_PROT_MODE:
+ return DescriptorA.OverCurrentProtMode;
+ break;
+
+ case RH_NOC_PROT:
+ return DescriptorA.NoOverCurrentProtMode;
+ break;
+
+ case RH_NO_POTPGT:
+ return DescriptorA.PowerOnToPowerGoodTime;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+
+/**
+
+ Set Root Hub Status reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ EFI_STATUS Status;
+ HcRH_STATUS RootHubStatus;
+
+
+ ZeroMem (&RootHubStatus, sizeof(HcRH_STATUS));
+
+ if(Field & RH_LOCAL_PSTAT){
+ RootHubStatus.LocalPowerStat = 1;
+ }
+ if(Field & RH_OC_ID){
+ RootHubStatus.OverCurrentIndicator = 1;
+ }
+ if(Field & RH_REMOTE_WK_ENABLE){
+ RootHubStatus.DevRemoteWakeupEnable = 1;
+ }
+ if(Field & RH_LOCAL_PSTAT_CHANGE){
+ RootHubStatus.LocalPowerStatChange = 1;
+ }
+ if(Field & RH_OC_ID_CHANGE){
+ RootHubStatus.OverCurrentIndicatorChange = 1;
+ }
+ if(Field & RH_CLR_RMT_WK_ENABLE){
+ RootHubStatus.ClearRemoteWakeupEnable = 1;
+ }
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_STATUS, &RootHubStatus);
+
+ return Status;
+}
+
+
+/**
+
+ Get Root Hub Status reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcRH_STATUS RootHubStatus;
+
+
+ *(UINT32 *) &RootHubStatus = OhciGetOperationalReg (Ohc->PciIo, HC_RH_STATUS);
+
+ switch (Field) {
+ case RH_LOCAL_PSTAT:
+ return RootHubStatus.LocalPowerStat;
+ break;
+ case RH_OC_ID:
+ return RootHubStatus.OverCurrentIndicator;
+ break;
+ case RH_REMOTE_WK_ENABLE:
+ return RootHubStatus.DevRemoteWakeupEnable;
+ break;
+ case RH_LOCAL_PSTAT_CHANGE:
+ return RootHubStatus.LocalPowerStatChange;
+ break;
+ case RH_OC_ID_CHANGE:
+ return RootHubStatus.OverCurrentIndicatorChange;
+ break;
+ case RH_CLR_RMT_WK_ENABLE:
+ return RootHubStatus.ClearRemoteWakeupEnable;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+
+/**
+
+ Set Root Hub Port Status reg value
+
+ @param Ohc UHC private data
+ @param Index Index of the port
+ @param Field Field to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubPortStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Index,
+ IN UINTN Field
+ )
+{
+ EFI_STATUS Status;
+ HcRHPORT_STATUS PortStatus;
+
+
+ ZeroMem (&PortStatus, sizeof(HcRHPORT_STATUS));
+
+ if (Field & RH_CLEAR_PORT_ENABLE) {
+ PortStatus.CurrentConnectStat = 1;
+ }
+ if (Field & RH_SET_PORT_ENABLE) {
+ PortStatus.EnableStat = 1;
+ }
+ if (Field & RH_SET_PORT_SUSPEND) {
+ PortStatus.SuspendStat = 1;
+ }
+ if (Field & RH_CLEAR_SUSPEND_STATUS) {
+ PortStatus.OCIndicator = 1;
+ }
+ if (Field & RH_SET_PORT_RESET) {
+ PortStatus.ResetStat = 1;
+ }
+ if (Field & RH_SET_PORT_POWER) {
+ PortStatus.PowerStat = 1;
+ }
+ if (Field & RH_CLEAR_PORT_POWER) {
+ PortStatus.LsDeviceAttached = 1;
+ }
+ if (Field & RH_CONNECT_STATUS_CHANGE) {
+ PortStatus.ConnectStatChange = 1;
+ }
+ if (Field & RH_PORT_ENABLE_STAT_CHANGE) {
+ PortStatus.EnableStatChange = 1;
+ }
+ if (Field & RH_PORT_SUSPEND_STAT_CHANGE) {
+ PortStatus.SuspendStatChange = 1;
+ }
+ if (Field & RH_OC_INDICATOR_CHANGE) {
+ PortStatus.OCIndicatorChange = 1;
+ }
+ if (Field & RH_PORT_RESET_STAT_CHANGE ) {
+ PortStatus.ResetStatChange = 1;
+ }
+
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_PORT_STATUS + (Index * 4), &PortStatus);
+
+ return Status;
+}
+
+
+/**
+
+ Get Root Hub Port Status reg value
+
+ @param Ohc UHC private data
+ @param Index Index of the port
+ @param Field Field to get
+
+ @retval Value of the field and index
+
+**/
+
+UINT32
+OhciReadRootHubPortStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Index,
+ IN UINTN Field
+ )
+{
+ HcRHPORT_STATUS PortStatus;
+
+ *(UINT32 *) &PortStatus = OhciGetOperationalReg (
+ Ohc->PciIo,
+ HC_RH_PORT_STATUS + (Index * 4)
+ );
+
+ switch (Field){
+ case RH_CURR_CONNECT_STAT:
+ return PortStatus.CurrentConnectStat;
+ break;
+ case RH_PORT_ENABLE_STAT:
+ return PortStatus.EnableStat;
+ break;
+ case RH_PORT_SUSPEND_STAT:
+ return PortStatus.SuspendStat;
+ break;
+ case RH_PORT_OC_INDICATOR:
+ return PortStatus.OCIndicator;
+ break;
+ case RH_PORT_RESET_STAT:
+ return PortStatus.ResetStat;
+ break;
+ case RH_PORT_POWER_STAT:
+ return PortStatus.PowerStat;
+ break;
+ case RH_LSDEVICE_ATTACHED:
+ return PortStatus.LsDeviceAttached;
+ break;
+ case RH_CONNECT_STATUS_CHANGE:
+ return PortStatus.ConnectStatChange;
+ break;
+ case RH_PORT_ENABLE_STAT_CHANGE:
+ return PortStatus.EnableStatChange;
+ break;
+ case RH_PORT_SUSPEND_STAT_CHANGE:
+ return PortStatus.SuspendStatChange;
+ break;
+ case RH_OC_INDICATOR_CHANGE:
+ return PortStatus.OCIndicatorChange;
+ break;
+ case RH_PORT_RESET_STAT_CHANGE:
+ return PortStatus.ResetStatChange;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h
new file mode 100644
index 0000000000..4896badd09
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h
@@ -0,0 +1,926 @@
+/** @file
+This file contains the definination for host controller
+register operation 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 _OHCI_REG_H
+#define _OHCI_REG_H
+
+#define HC_STATE_RESET 0x0
+#define HC_STATE_RESUME 0x1
+#define HC_STATE_OPERATIONAL 0x2
+#define HC_STATE_SUSPEND 0x3
+
+#define PERIODIC_ENABLE 0x01
+#define ISOCHRONOUS_ENABLE 0x02
+#define CONTROL_ENABLE 0x04
+#define BULK_ENABLE 0x08
+#define CONTROL_BULK_RATIO 0x10
+
+#define HC_FUNCTIONAL_STATE 0x20
+#define INTERRUPT_ROUTING 0x40
+
+#define HC_RESET 0x01
+#define CONTROL_LIST_FILLED 0x02
+#define BULK_LIST_FILLED 0x04
+#define CHANGE_OWNER_REQUEST 0x08
+
+#define SCHEDULE_OVERRUN_COUNT 0x10
+
+#define SCHEDULE_OVERRUN 0x00001
+#define WRITEBACK_DONE_HEAD 0x00002
+#define START_OF_FRAME 0x00004
+#define RESUME_DETECT 0x00008
+#define UNRECOVERABLE_ERROR 0x00010
+#define FRAME_NUMBER_OVERFLOW 0x00020
+#define ROOTHUB_STATUS_CHANGE 0x00040
+#define OWNERSHIP_CHANGE 0x00080
+
+#define MASTER_INTERRUPT 0x00400
+
+#define CONTROL_HEAD 0x001
+#define BULK_HEAD 0x002
+#define DONE_HEAD 0x004
+
+#define Hc_HCCA 0x001
+#define Hc_PERIODIC_CURRENT 0x002
+#define Hc_CONTOL_HEAD 0x004
+#define Hc_CONTROL_CURRENT_PTR 0x008
+#define Hc_BULK_HEAD 0x010
+#define Hc_BULK_CURRENT_PTR 0x020
+#define Hc_DONE_HEAD 0x040
+
+#define FRAME_INTERVAL 0x008
+#define FS_LARGEST_DATA_PACKET 0x010
+#define FRMINT_TOGGLE 0x020
+#define FRAME_REMAINING 0x040
+#define FRAME_REMAIN_TOGGLE 0x080
+
+#define RH_DESC_A 0x00001
+#define RH_DESC_B 0x00002
+#define RH_NUM_DS_PORTS 0x00004
+#define RH_NO_PSWITCH 0x00008
+#define RH_PSWITCH_MODE 0x00010
+#define RH_DEVICE_TYPE 0x00020
+#define RH_OC_PROT_MODE 0x00040
+#define RH_NOC_PROT 0x00080
+#define RH_POTPGT 0x00100
+#define RH_NO_POTPGT 0x00200
+#define RH_DEV_REMOVABLE 0x00400
+#define RH_PORT_PWR_CTRL_MASK 0x00800
+
+#define RH_LOCAL_PSTAT 0x00001
+#define RH_OC_ID 0x00002
+#define RH_REMOTE_WK_ENABLE 0x00004
+#define RH_LOCAL_PSTAT_CHANGE 0x00008
+#define RH_OC_ID_CHANGE 0x00010
+#define RH_CLR_RMT_WK_ENABLE 0x00020
+
+#define RH_CLEAR_PORT_ENABLE 0x0001
+#define RH_SET_PORT_ENABLE 0x0002
+#define RH_SET_PORT_SUSPEND 0x0004
+#define RH_CLEAR_SUSPEND_STATUS 0x0008
+#define RH_SET_PORT_RESET 0x0010
+#define RH_SET_PORT_POWER 0x0020
+#define RH_CLEAR_PORT_POWER 0x0040
+#define RH_CONNECT_STATUS_CHANGE 0x10000
+#define RH_PORT_ENABLE_STAT_CHANGE 0x20000
+#define RH_PORT_SUSPEND_STAT_CHANGE 0x40000
+#define RH_OC_INDICATOR_CHANGE 0x80000
+#define RH_PORT_RESET_STAT_CHANGE 0x100000
+
+#define RH_CURR_CONNECT_STAT 0x0001
+#define RH_PORT_ENABLE_STAT 0x0002
+#define RH_PORT_SUSPEND_STAT 0x0004
+#define RH_PORT_OC_INDICATOR 0x0008
+#define RH_PORT_RESET_STAT 0x0010
+#define RH_PORT_POWER_STAT 0x0020
+#define RH_LSDEVICE_ATTACHED 0x0040
+
+#define RESET_SYSTEM_BUS (1 << 0)
+#define RESET_HOST_CONTROLLER (1 << 1)
+#define RESET_CLOCK_GENERATION (1 << 2)
+#define RESET_SSE_GLOBAL (1 << 5)
+#define RESET_PSPL (1 << 6)
+#define RESET_PCPL (1 << 7)
+#define RESET_SSEP1 (1 << 9)
+#define RESET_SSEP2 (1 << 10)
+#define RESET_SSEP3 (1 << 11)
+
+#define ONE_SECOND 1000000
+#define ONE_MILLI_SEC 1000
+#define MAX_BYTES_PER_TD 0x1000
+#define MAX_RETRY_TIMES 100
+#define PORT_NUMBER_ON_MAINSTONE2 1
+
+
+//
+// Operational Register Offsets
+//
+
+//
+// Command & Status Registers Offsets
+//
+#define HC_REVISION 0x00
+#define HC_CONTROL 0x04
+#define HC_COMMAND_STATUS 0x08
+#define HC_INTERRUPT_STATUS 0x0C
+#define HC_INTERRUPT_ENABLE 0x10
+#define HC_INTERRUPT_DISABLE 0x14
+
+//
+// Memory Pointer Offsets
+//
+#define HC_HCCA 0x18
+#define HC_PERIODIC_CURRENT 0x1C
+#define HC_CONTROL_HEAD 0x20
+#define HC_CONTROL_CURRENT_PTR 0x24
+#define HC_BULK_HEAD 0x28
+#define HC_BULK_CURRENT_PTR 0x2C
+#define HC_DONE_HEAD 0x30
+
+//
+// Frame Register Offsets
+//
+#define HC_FRM_INTERVAL 0x34
+#define HC_FRM_REMAINING 0x38
+#define HC_FRM_NUMBER 0x3C
+#define HC_PERIODIC_START 0x40
+#define HC_LS_THREASHOLD 0x44
+
+//
+// Root Hub Register Offsets
+//
+#define HC_RH_DESC_A 0x48
+#define HC_RH_DESC_B 0x4C
+#define HC_RH_STATUS 0x50
+#define HC_RH_PORT_STATUS 0x54
+
+#define USBHOST_OFFSET_UHCHR 0x64 // Usb Host reset register
+
+#define OHC_BAR_INDEX 0
+
+//
+// Usb Host controller register offset
+//
+#define USBHOST_OFFSET_UHCREV 0x0 // Usb Host revision register
+#define USBHOST_OFFSET_UHCHCON 0x4 // Usb Host control register
+#define USBHOST_OFFSET_UHCCOMS 0x8 // Usb Host Command Status register
+#define USBHOST_OFFSET_UHCINTS 0xC // Usb Host Interrupt Status register
+#define USBHOST_OFFSET_UHCINTE 0x10 // Usb Host Interrupt Enable register
+#define USBHOST_OFFSET_UHCINTD 0x14 // Usb Host Interrupt Disable register
+#define USBHOST_OFFSET_UHCHCCA 0x18 // Usb Host Controller Communication Area
+#define USBHOST_OFFSET_UHCPCED 0x1C // Usb Host Period Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCCHED 0x20 // Usb Host Control Head Endpoint Descriptor
+#define USBHOST_OFFSET_UHCCCED 0x24 // Usb Host Control Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCBHED 0x28 // Usb Host Bulk Head Endpoint Descriptor
+#define USBHOST_OFFSET_UHCBCED 0x2C // Usb Host Bulk Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCDHEAD 0x30 // Usb Host Done Head register
+#define USBHOST_OFFSET_UHCFMI 0x34 // Usb Host Frame Interval register
+#define USBHOST_OFFSET_UHCFMR 0x38 // Usb Host Frame Remaining register
+#define USBHOST_OFFSET_UHCFMN 0x3C // Usb Host Frame Number register
+#define USBHOST_OFFSET_UHCPERS 0x40 // Usb Host Periodic Start register
+#define USBHOST_OFFSET_UHCLST 0x44 // Usb Host Low-Speed Threshold register
+#define USBHOST_OFFSET_UHCRHDA 0x48 // Usb Host Root Hub Descriptor A register
+#define USBHOST_OFFSET_UHCRHDB 0x4C // Usb Host Root Hub Descriptor B register
+#define USBHOST_OFFSET_UHCRHS 0x50 // Usb Host Root Hub Status register
+#define USBHOST_OFFSET_UHCRHPS1 0x54 // Usb Host Root Hub Port Status 1 register
+
+//
+// Usb Host controller register bit fields
+//
+#pragma pack(1)
+
+typedef struct {
+ UINT8 ProgInterface;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+} USB_CLASSC;
+
+typedef struct {
+ UINT32 Revision:8;
+ UINT32 Rsvd:24;
+} HcREVISION;
+
+typedef struct {
+ UINT32 ControlBulkRatio:2;
+ UINT32 PeriodicEnable:1;
+ UINT32 IsochronousEnable:1;
+ UINT32 ControlEnable:1;
+ UINT32 BulkEnable:1;
+ UINT32 FunctionalState:2;
+ UINT32 InterruptRouting:1;
+ UINT32 RemoteWakeup:1;
+ UINT32 RemoteWakeupEnable:1;
+ UINT32 Reserved:21;
+} HcCONTROL;
+
+typedef struct {
+ UINT32 HcReset:1;
+ UINT32 ControlListFilled:1;
+ UINT32 BulkListFilled:1;
+ UINT32 ChangeOwnerRequest:1;
+ UINT32 Reserved1:12;
+ UINT32 ScheduleOverrunCount:2;
+ UINT32 Reserved:14;
+} HcCOMMAND_STATUS;
+
+typedef struct {
+ UINT32 SchedulingOverrun:1;
+ UINT32 WriteBackDone:1;
+ UINT32 Sof:1;
+ UINT32 ResumeDetected:1;
+ UINT32 UnrecoverableError:1;
+ UINT32 FrameNumOverflow:1;
+ UINT32 RHStatusChange:1;
+ UINT32 Reserved1:23;
+ UINT32 OwnerChange:1;
+ UINT32 Reserved2:1;
+} HcINTERRUPT_STATUS;
+
+typedef struct {
+ UINT32 SchedulingOverrunInt:1;
+ UINT32 WriteBackDoneInt:1;
+ UINT32 SofInt:1;
+ UINT32 ResumeDetectedInt:1;
+ UINT32 UnrecoverableErrorInt:1;
+ UINT32 FrameNumOverflowInt:1;
+ UINT32 RHStatusChangeInt:1;
+ UINT32 Reserved:23;
+ UINT32 OwnerChangedInt:1;
+ UINT32 MasterInterruptEnable:1;
+} HcINTERRUPT_CONTROL;
+
+typedef struct {
+ UINT32 Rerserved:8;
+ UINT32 Hcca:24;
+} HcHCCA;
+
+typedef struct {
+ UINT32 Reserved:4;
+ UINT32 MemoryPtr:28;
+} HcMEMORY_PTR;
+
+typedef struct {
+ UINT32 FrameInterval:14;
+ UINT32 Reserved:2;
+ UINT32 FSMaxDataPacket:15;
+ UINT32 FrmIntervalToggle:1;
+} HcFRM_INTERVAL;
+
+typedef struct {
+ UINT32 FrameRemaining:14;
+ UINT32 Reserved:17;
+ UINT32 FrameRemainingToggle:1;
+} HcFRAME_REMAINING;
+
+typedef struct {
+ UINT32 FrameNumber:16;
+ UINT32 Reserved:16;
+} HcFRAME_NUMBER;
+
+typedef struct {
+ UINT32 PeriodicStart:14;
+ UINT32 Reserved:18;
+} HcPERIODIC_START;
+
+typedef struct {
+ UINT32 LsThreshold:12;
+ UINT32 Reserved:20;
+} HcLS_THRESHOLD;
+
+typedef struct {
+ UINT32 NumDownStrmPorts:8;
+ UINT32 PowerSwitchMode:1;
+ UINT32 NoPowerSwitch:1;
+ UINT32 DeviceType:1;
+ UINT32 OverCurrentProtMode:1;
+ UINT32 NoOverCurrentProtMode:1;
+ UINT32 Reserved:11;
+ UINT32 PowerOnToPowerGoodTime:8;
+} HcRH_DESC_A;
+
+typedef struct {
+ UINT32 DeviceRemovable:16;
+ UINT32 PortPowerControlMask:16;
+} HcRH_DESC_B;
+
+typedef struct {
+ UINT32 LocalPowerStat:1;
+ UINT32 OverCurrentIndicator:1;
+ UINT32 Reserved1:13;
+ UINT32 DevRemoteWakeupEnable:1;
+ UINT32 LocalPowerStatChange:1;
+ UINT32 OverCurrentIndicatorChange:1;
+ UINT32 Reserved2:13;
+ UINT32 ClearRemoteWakeupEnable:1;
+} HcRH_STATUS;
+
+typedef struct {
+ UINT32 CurrentConnectStat:1;
+ UINT32 EnableStat:1;
+ UINT32 SuspendStat:1;
+ UINT32 OCIndicator:1;
+ UINT32 ResetStat:1;
+ UINT32 Reserved1:3;
+ UINT32 PowerStat:1;
+ UINT32 LsDeviceAttached:1;
+ UINT32 Reserved2:6;
+ UINT32 ConnectStatChange:1;
+ UINT32 EnableStatChange:1;
+ UINT32 SuspendStatChange:1;
+ UINT32 OCIndicatorChange:1;
+ UINT32 ResetStatChange:1;
+ UINT32 Reserved3:11;
+} HcRHPORT_STATUS;
+
+typedef struct {
+ UINT32 FSBIR:1;
+ UINT32 FHR:1;
+ UINT32 CGR:1;
+ UINT32 SSDC:1;
+ UINT32 UIT:1;
+ UINT32 SSE:1;
+ UINT32 PSPL:1;
+ UINT32 PCPL:1;
+ UINT32 Reserved0:1;
+ UINT32 SSEP1:1;
+ UINT32 SSEP2:1;
+ UINT32 SSEP3:1;
+ UINT32 Reserved1:20;
+} HcRESET;
+
+
+#pragma pack()
+
+//
+// Func List
+//
+
+
+/**
+
+ Get OHCI operational reg value
+
+ @param PciIo PciIo protocol instance
+ @param Offset Offset of the operational reg
+
+ @retval Value of the register
+
+**/
+UINT32
+OhciGetOperationalReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset
+ );
+
+/**
+
+ Set OHCI operational reg value
+
+ @param PciIo PCI Bus Io protocol instance
+ @param Offset Offset of the operational reg
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set to the reg
+
+**/
+
+
+EFI_STATUS
+OhciSetOperationalReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN VOID *Value
+ );
+
+
+/**
+
+ Get HcRevision reg value
+
+ @param PciIo PCI Bus Io protocol instance
+
+ @retval Value of the register
+
+**/
+
+
+UINT32
+OhciGetHcRevision (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ );
+
+/**
+
+ Set HcReset reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcReset (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Field,
+ IN UINT32 Value
+ );
+/**
+
+ Get specific field of HcReset reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcReset (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Field
+ );
+/**
+
+ Set HcControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+
+
+/**
+
+ Get specific field of HcControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+
+UINT32
+OhciGetHcControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+
+/**
+
+ Set HcCommand reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcCommandStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+
+/**
+
+ Get specific field of HcCommand reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcCommandStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+/**
+
+ Clear specific fields of Interrupt Status
+
+ @param Ohc UHC private data
+ @param Field Field to clear
+
+ @retval EFI_SUCCESS Fields cleared
+
+**/
+
+EFI_STATUS
+OhciClearInterruptStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+/**
+
+ Get fields of HcInterrupt reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+/**
+
+ Set Interrupt Control reg value
+
+ @param Ohc UHC private data
+ @param StatEnable Enable or Disable
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetInterruptControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN BOOLEAN StatEnable,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+
+/**
+
+ Get field of HcInterruptControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+
+/**
+
+ Set memory pointer of specific type
+
+ @param Ohc UHC private data
+ @param PointerType Type of the pointer to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Memory pointer set
+
+**/
+
+EFI_STATUS
+OhciSetMemoryPointer(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 PointerType,
+ IN VOID *Value
+ );
+
+/**
+
+ Get memory pointer of specific type
+
+ @param Ohc UHC private data
+ @param PointerType Type of pointer
+
+ @retval Memory pointer of the specific type
+
+**/
+
+VOID *
+OhciGetMemoryPointer (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 PointerType
+ );
+
+/**
+
+ Set Frame Interval value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameInterval (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+
+
+/**
+
+ Get field of frame interval reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetFrameInterval (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+
+/**
+
+ Set Frame Remaining reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameRemaining (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ );
+
+/**
+
+ Get value of frame remaining reg
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of frame remaining reg
+
+**/
+UINT32
+OhciGetFrameRemaining (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+/**
+
+ Set frame number reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameNumber(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ );
+
+/**
+
+ Get frame number reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of frame number reg
+
+**/
+
+UINT32
+OhciGetFrameNumber (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+
+
+/**
+
+ Set period start reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetPeriodicStart (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ );
+
+
+/**
+
+ Get periodic start reg value
+
+ @param Ohc UHC private data
+
+ @param Value of periodic start reg
+
+**/
+
+UINT32
+OhciGetPeriodicStart (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+
+
+/**
+
+ Set Ls Threshold reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetLsThreshold (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ );
+
+/**
+
+ Get Ls Threshold reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of Ls Threshold reg
+
+**/
+
+UINT32
+OhciGetLsThreshold (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+
+/**
+
+ Set Root Hub Descriptor reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetRootHubDescriptor (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+
+
+/**
+
+ Get Root Hub Descriptor reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubDescriptor (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+/**
+
+ Set Root Hub Status reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+
+/**
+
+ Get Root Hub Status reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+
+
+/**
+
+ Set Root Hub Port Status reg value
+
+ @param Ohc UHC private data
+ @param Index Index of the port
+ @param Field Field to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubPortStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Index,
+ IN UINTN Field
+ );
+
+
+/**
+
+ Get Root Hub Port Status reg value
+
+ @param Ohc UHC private data
+ @param Index Index of the port
+ @param Field Field to get
+
+ @retval Value of the field and index
+
+**/
+
+UINT32
+OhciReadRootHubPortStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Index,
+ IN UINTN Field
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c
new file mode 100644
index 0000000000..22aa26fb86
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c
@@ -0,0 +1,534 @@
+/** @file
+OHCI transfer scheduling 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.
+
+**/
+
+
+#include "Ohci.h"
+
+/**
+
+ Add an item of interrupt context
+
+ @param Ohc UHC private data
+ @param NewEntry New entry to add
+
+ @retval EFI_SUCCESS Item successfully added
+
+**/
+EFI_STATUS
+OhciAddInterruptContextEntry (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN INTERRUPT_CONTEXT_ENTRY *NewEntry
+ )
+{
+ INTERRUPT_CONTEXT_ENTRY *Entry;
+ EFI_TPL OriginalTPL;
+
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+ if (Ohc->InterruptContextList == NULL) {
+ Ohc->InterruptContextList = NewEntry;
+ } else {
+ Entry = Ohc->InterruptContextList;
+ while (Entry->NextEntry != NULL) {
+ Entry = Entry->NextEntry;
+ }
+ Entry->NextEntry = NewEntry;
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Free a interrupt context entry
+
+ @param Ohc UHC private data
+ @param Entry Pointer to an interrupt context entry
+
+ @retval EFI_SUCCESS Entry freed
+ @retval EFI_INVALID_PARAMETER Entry is NULL
+
+**/
+EFI_STATUS
+OhciFreeInterruptContextEntry (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN INTERRUPT_CONTEXT_ENTRY *Entry
+ )
+{
+ TD_DESCRIPTOR *Td;
+ if (Entry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Entry->UCBufferMapping != NULL) {
+ Ohc->PciIo->Unmap(Ohc->PciIo, Entry->UCBufferMapping);
+ }
+ if (Entry->UCBuffer != NULL) {
+ FreePool(Entry->UCBuffer);
+ }
+ while (Entry->DataTd) {
+ Td = Entry->DataTd;
+ Entry->DataTd = (TD_DESCRIPTOR *)(UINTN)(Entry->DataTd->NextTDPointer);
+ UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));
+ }
+ FreePool(Entry);
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Free entries match the device address and endpoint address
+
+ @Param Ohc UHC private date
+ @Param DeviceAddress Item to free must match this device address
+ @Param EndPointAddress Item to free must match this end point address
+ @Param DataToggle DataToggle for output
+
+ @retval EFI_SUCCESS Items match the requirement removed
+
+**/
+EFI_STATUS
+OhciFreeInterruptContext(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ OUT UINT8 *DataToggle
+ )
+{
+ INTERRUPT_CONTEXT_ENTRY *Entry;
+ INTERRUPT_CONTEXT_ENTRY *TempEntry;
+ EFI_TPL OriginalTPL;
+
+
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+ while (Ohc->InterruptContextList != NULL &&
+ Ohc->InterruptContextList->DeviceAddress == DeviceAddress &&
+ Ohc->InterruptContextList->EndPointAddress == EndPointAddress) {
+ TempEntry = Ohc->InterruptContextList;
+ Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry;
+ if (DataToggle != NULL) {
+ *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1);
+ }
+ OhciFreeInterruptContextEntry (Ohc, TempEntry);
+ }
+
+ Entry = Ohc->InterruptContextList;
+ if (Entry == NULL) {
+ gBS->RestoreTPL (OriginalTPL);
+ return EFI_SUCCESS;
+ }
+ while (Entry->NextEntry != NULL) {
+ if (Entry->NextEntry->DeviceAddress == DeviceAddress &&
+ Entry->NextEntry->EndPointAddress == EndPointAddress) {
+ TempEntry = Entry->NextEntry;
+ Entry->NextEntry = Entry->NextEntry->NextEntry;
+ if (DataToggle != NULL) {
+ *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1);
+ }
+ OhciFreeInterruptContextEntry (Ohc, TempEntry);
+ } else {
+ Entry = Entry->NextEntry;
+ }
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Convert Error code from OHCI format to EFI format
+
+ @Param ErrorCode ErrorCode in OHCI format
+
+ @retval ErrorCode in EFI format
+
+**/
+UINT32
+ConvertErrorCode (
+ IN UINT32 ErrorCode
+ )
+{
+ UINT32 TransferResult;
+
+ switch (ErrorCode) {
+ case TD_NO_ERROR:
+ TransferResult = EFI_USB_NOERROR;
+ break;
+
+ case TD_TOBE_PROCESSED:
+ case TD_TOBE_PROCESSED_2:
+ TransferResult = EFI_USB_ERR_NOTEXECUTE;
+ break;
+
+ case TD_DEVICE_STALL:
+ TransferResult = EFI_USB_ERR_STALL;
+ break;
+
+ case TD_BUFFER_OVERRUN:
+ case TD_BUFFER_UNDERRUN:
+ TransferResult = EFI_USB_ERR_BUFFER;
+ break;
+
+ case TD_CRC_ERROR:
+ TransferResult = EFI_USB_ERR_CRC;
+ break;
+
+ case TD_NO_RESPONSE:
+ TransferResult = EFI_USB_ERR_TIMEOUT;
+ break;
+
+ case TD_BITSTUFFING_ERROR:
+ TransferResult = EFI_USB_ERR_BITSTUFF;
+ break;
+
+ default:
+ TransferResult = EFI_USB_ERR_SYSTEM;
+ }
+
+ return TransferResult;
+}
+
+
+/**
+
+ Check TDs Results
+
+ @Param Ohc UHC private data
+ @Param Td TD_DESCRIPTOR
+ @Param Result Result to return
+
+ @retval TRUE means OK
+ @retval FLASE means Error or Short packet
+
+**/
+BOOLEAN
+OhciCheckTDsResults (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN TD_DESCRIPTOR *Td,
+ OUT UINT32 *Result
+ )
+{
+ UINT32 TdCompletionCode;
+
+ *Result = EFI_USB_NOERROR;
+
+ while (Td) {
+ TdCompletionCode = Td->Word0.ConditionCode;
+
+ *Result |= ConvertErrorCode(TdCompletionCode);
+ //
+ // if any error encountered, stop processing the left TDs.
+ //
+ if (*Result) {
+ return FALSE;
+ }
+
+ Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer);
+ }
+ return TRUE;
+
+}
+
+
+/**
+
+ Check the task status on an ED
+
+ @Param Ed Pointer to the ED task that TD hooked on
+ @Param HeadTd TD header for current transaction
+
+ @retval Task Status Code
+
+**/
+
+UINT32
+CheckEDStatus (
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd,
+ OUT OHCI_ED_RESULT *EdResult
+ )
+{
+ while(HeadTd != NULL) {
+ if (HeadTd->NextTDPointer == 0) {
+ return TD_NO_ERROR;
+ }
+ if (HeadTd->Word0.ConditionCode != 0) {
+ return HeadTd->Word0.ConditionCode;
+ }
+ EdResult->NextToggle = ((UINT8)(HeadTd->Word0.DataToggle) & BIT0) ^ BIT0;
+ HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);
+ }
+ if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) {
+ return TD_TOBE_PROCESSED;
+ }
+ return TD_NO_ERROR;
+}
+
+/**
+
+ Check the task status
+
+ @Param Ohc UHC private data
+ @Param ListType Pipe type
+ @Param Ed Pointer to the ED task hooked on
+ @Param HeadTd Head of TD corresponding to the task
+ @Param ErrorCode return the ErrorCode
+
+ @retval EFI_SUCCESS Task done
+ @retval EFI_NOT_READY Task on processing
+ @retval EFI_DEVICE_ERROR Some error occured
+
+**/
+EFI_STATUS
+CheckIfDone (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN DESCRIPTOR_LIST_TYPE ListType,
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd,
+ OUT OHCI_ED_RESULT *EdResult
+ )
+{
+ EdResult->ErrorCode = TD_TOBE_PROCESSED;
+
+ switch (ListType) {
+ case CONTROL_LIST:
+ if (OhciGetHcCommandStatus (Ohc, CONTROL_LIST_FILLED) != 0) {
+ return EFI_NOT_READY;
+ }
+ break;
+ case BULK_LIST:
+ if (OhciGetHcCommandStatus (Ohc, BULK_LIST_FILLED) != 0) {
+ return EFI_NOT_READY;
+ }
+ break;
+ default:
+ break;
+ }
+
+ EdResult->ErrorCode = CheckEDStatus (Ed, HeadTd, EdResult);
+
+ if (EdResult->ErrorCode == TD_NO_ERROR) {
+ return EFI_SUCCESS;
+ } else if (EdResult->ErrorCode == TD_TOBE_PROCESSED) {
+ return EFI_NOT_READY;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+
+/**
+
+ Convert TD condition code to Efi Status
+
+ @Param ConditionCode Condition code to convert
+
+ @retval EFI_SUCCESS No error occured
+ @retval EFI_NOT_READY TD still on processing
+ @retval EFI_DEVICE_ERROR Error occured in processing TD
+
+**/
+
+EFI_STATUS
+OhciTDConditionCodeToStatus (
+ IN UINT32 ConditionCode
+ )
+{
+ if (ConditionCode == TD_NO_ERROR) {
+ return EFI_SUCCESS;
+ }
+
+ if (ConditionCode == TD_TOBE_PROCESSED) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+
+ Invoke callbacks hooked on done TDs
+
+ @Param Entry Interrupt transfer transaction information data structure
+ @Param Context Ohc private data
+
+**/
+
+VOID
+OhciInvokeInterruptCallBack(
+ IN INTERRUPT_CONTEXT_ENTRY *Entry,
+ IN UINT32 Result
+)
+{
+ //Generally speaking, Keyboard driver should not
+ //check the Keyboard buffer if an error happens, it will be robust
+ //if we NULLed the buffer once error happens
+ if (Result) {
+ Entry->CallBackFunction (
+ NULL,
+ 0,
+ Entry->Context,
+ Result
+ );
+ }else{
+ Entry->CallBackFunction (
+ (VOID *)(UINTN)(Entry->DataTd->DataBuffer),
+ Entry->DataTd->ActualSendLength,
+ Entry->Context,
+ Result
+ );
+ }
+}
+
+
+/**
+
+ Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs
+
+ @param Event Event handle
+ @param Context Device private data
+
+**/
+
+VOID
+EFIAPI
+OhciHouseKeeper (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+
+ USB_OHCI_HC_DEV *Ohc;
+ INTERRUPT_CONTEXT_ENTRY *Entry;
+ INTERRUPT_CONTEXT_ENTRY *PreEntry;
+ ED_DESCRIPTOR *Ed;
+ TD_DESCRIPTOR *DataTd;
+ TD_DESCRIPTOR *HeadTd;
+
+ UINT8 Toggle;
+ EFI_TPL OriginalTPL;
+ UINT32 Result;
+
+ Ohc = (USB_OHCI_HC_DEV *) Context;
+ OriginalTPL = gBS->RaiseTPL(TPL_NOTIFY);
+
+ Entry = Ohc->InterruptContextList;
+ PreEntry = NULL;
+
+ while(Entry != NULL) {
+
+ OhciCheckTDsResults(Ohc, Entry->DataTd, &Result );
+ if (((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) ||
+ ((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)) {
+ PreEntry = Entry;
+ Entry = Entry->NextEntry;
+ continue;
+ }
+
+ if (Entry->CallBackFunction != NULL) {
+ OhciInvokeInterruptCallBack (Entry, Result);
+ if (Ohc->InterruptContextList == NULL) {
+ gBS->RestoreTPL (OriginalTPL);
+ return;
+ }
+ }
+ if (Entry->IsPeriodic) {
+
+ Ed = Entry->Ed;
+ HeadTd = Entry->DataTd;
+ DataTd = HeadTd;
+ Toggle = 0;
+ if (Result == EFI_USB_NOERROR) {
+ //
+ // Update toggle if there is no error, and re-submit the interrupt Ed&Tds
+ //
+ if ((Ed != NULL) && (DataTd != NULL)) {
+ Ed->Word0.Skip = 1;
+ }
+ //
+ // From hcir1_0a.pdf 4.2.2
+ // ToggleCarry:This bit is the data toggle carry bit,
+ // Whenever a TD is retired, this bit is written to
+ // contain the last data toggle value(LSb of data Toggel
+ // file) from the retired TD.
+ // This field is not used for Isochronous Endpoints
+ //
+ if (Ed == NULL) {
+ return;
+ }
+ Toggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);
+ while(DataTd != NULL) {
+ if (DataTd->NextTDPointer == 0) {
+ DataTd->Word0.DataToggle = 0;
+ break;
+ } else {
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, Toggle);
+ }
+ DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer);
+ Toggle ^= 1;
+ }
+ //
+ // HC will only update DataToggle, ErrorCount, ConditionCode
+ // CurrentBufferPointer & NextTD, so we only need to update
+ // them once we want to active them again
+ //
+ DataTd = HeadTd;
+ while (DataTd != NULL) {
+ if (DataTd->NextTDPointer == 0) {
+ OhciSetTDField (DataTd, TD_ERROR_CNT | TD_COND_CODE | TD_CURR_BUFFER_PTR | TD_NEXT_PTR, 0);
+ break;
+ }
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ DataTd->NextTD = DataTd->NextTDPointer;
+ DataTd->CurrBufferPointer = DataTd->DataBuffer;
+ DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer);
+ }
+ //
+ // Active current Ed,Td
+ //
+ // HC will only update Halted, ToggleCarry & TDQueueHeadPointer,
+ // So we only need to update them once we want to active them again.
+ //
+ if ((Ed != NULL) && (DataTd != NULL)) {
+ Ed->Word2.TdHeadPointer = (UINT32)((UINTN)HeadTd>>4);
+ OhciSetEDField (Ed, ED_HALTED | ED_DTTOGGLE, 0);
+ Ed->Word0.Skip = 0;
+ }
+ }
+ } else {
+ if (PreEntry == NULL) {
+ Ohc->InterruptContextList = Entry->NextEntry;
+ } else {
+ PreEntry = Entry;
+ PreEntry->NextEntry = Entry->NextEntry;
+ }
+ OhciFreeInterruptContextEntry (Ohc, PreEntry);
+ gBS->RestoreTPL (OriginalTPL);
+ return;
+ }
+ PreEntry = Entry;
+ Entry = Entry->NextEntry;
+ }
+ gBS->RestoreTPL (OriginalTPL);
+}
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h
new file mode 100644
index 0000000000..8a8638257f
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h
@@ -0,0 +1,231 @@
+/** @file
+This file contains the definination for host controller schedule 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 _OHCI_SCHED_H
+#define _OHCI_SCHED_H
+
+#include "Descriptor.h"
+
+#define HCCA_MEM_SIZE 256
+#define GRID_SIZE 16
+#define GRID_SHIFT 4
+
+typedef struct _INTERRUPT_CONTEXT_ENTRY INTERRUPT_CONTEXT_ENTRY;
+
+struct _INTERRUPT_CONTEXT_ENTRY{
+ UINT8 DeviceAddress;
+ UINT8 EndPointAddress;
+ ED_DESCRIPTOR *Ed;
+ TD_DESCRIPTOR *DataTd;
+ BOOLEAN IsSlowDevice;
+ UINT8 MaxPacketLength;
+ UINTN PollingInterval;
+ EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction;
+ VOID *Context;
+ BOOLEAN IsPeriodic;
+ VOID *Buffer;
+ UINTN DataLength;
+ VOID *UCBuffer;
+ VOID *UCBufferMapping;
+ UINT8 *Toggle;
+ INTERRUPT_CONTEXT_ENTRY *NextEntry;
+};
+
+
+typedef struct {
+ UINT32 ErrorCode;
+ UINT8 NextToggle;
+} OHCI_ED_RESULT;
+
+/**
+
+ Add an item of interrupt context
+
+ @param Ohc UHC private data
+ @param NewEntry New entry to add
+
+ @retval EFI_SUCCESS Item successfully added
+
+**/
+EFI_STATUS
+OhciAddInterruptContextEntry (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN INTERRUPT_CONTEXT_ENTRY *NewEntry
+ );
+
+/**
+
+ Free a interrupt context entry
+
+ @param Ohc UHC private data
+ @param Entry Pointer to an interrupt context entry
+
+ @retval EFI_SUCCESS Entry freed
+ @retval EFI_INVALID_PARAMETER Entry is NULL
+
+**/
+EFI_STATUS
+OhciFreeInterruptContextEntry (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN INTERRUPT_CONTEXT_ENTRY *Entry
+ );
+
+/**
+
+ Free entries match the device address and endpoint address
+
+ @Param Ohc UHC private date
+ @Param DeviceAddress Item to free must match this device address
+ @Param EndPointAddress Item to free must match this end point address
+ @Param DataToggle DataToggle for output
+
+ @retval EFI_SUCCESS Items match the requirement removed
+
+**/
+EFI_STATUS
+OhciFreeInterruptContext(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ OUT UINT8 *DataToggle
+ );
+
+
+/**
+
+ Convert Error code from OHCI format to EFI format
+
+ @Param ErrorCode ErrorCode in OHCI format
+
+ @retval ErrorCode in EFI format
+
+**/
+UINT32
+ConvertErrorCode (
+ IN UINT32 ErrorCode
+ );
+
+
+/**
+
+ Check TDs Results
+
+ @Param Ohc UHC private data
+ @Param Td TD_DESCRIPTOR
+ @Param Result Result to return
+
+ @retval TRUE means OK
+ @retval FLASE means Error or Short packet
+
+**/
+BOOLEAN
+OhciCheckTDsResults (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN TD_DESCRIPTOR *Td,
+ OUT UINT32 *Result
+ );
+/**
+
+ Check the task status on an ED
+
+ @Param Ed Pointer to the ED task that TD hooked on
+ @Param HeadTd TD header for current transaction
+
+ @retval Task Status Code
+
+**/
+
+UINT32
+CheckEDStatus (
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd,
+ OUT OHCI_ED_RESULT *EdResult
+ );
+/**
+
+ Check the task status
+
+ @Param Ohc UHC private data
+ @Param ListType Pipe type
+ @Param Ed Pointer to the ED task hooked on
+ @Param HeadTd Head of TD corresponding to the task
+ @Param ErrorCode return the ErrorCode
+
+ @retval EFI_SUCCESS Task done
+ @retval EFI_NOT_READY Task on processing
+ @retval EFI_DEVICE_ERROR Some error occured
+
+**/
+EFI_STATUS
+CheckIfDone (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN DESCRIPTOR_LIST_TYPE ListType,
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd,
+ OUT OHCI_ED_RESULT *EdResult
+ );
+
+/**
+
+ Convert TD condition code to Efi Status
+
+ @Param ConditionCode Condition code to convert
+
+ @retval EFI_SUCCESS No error occured
+ @retval EFI_NOT_READY TD still on processing
+ @retval EFI_DEVICE_ERROR Error occured in processing TD
+
+**/
+
+EFI_STATUS
+OhciTDConditionCodeToStatus (
+ IN UINT32 ConditionCode
+ );
+
+/**
+
+ Invoke callbacks hooked on done TDs
+
+ @Param Entry Interrupt transfer transaction information data structure
+ @Param Context Ohc private data
+
+**/
+
+VOID
+OhciInvokeInterruptCallBack(
+ IN INTERRUPT_CONTEXT_ENTRY *Entry,
+ IN UINT32 Result
+);
+
+
+/**
+
+ Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs
+
+ @param Event Event handle
+ @param Context Device private data
+
+**/
+
+VOID
+EFIAPI
+OhciHouseKeeper (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c
new file mode 100644
index 0000000000..736bab9041
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c
@@ -0,0 +1,895 @@
+/** @file
+This file contains URB request, each request is warpped in a
+URB (Usb Request Block).
+
+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 "Ohci.h"
+
+
+/**
+
+ Create a TD
+
+ @Param Ohc UHC private data
+
+ @retval TD structure pointer
+
+**/
+TD_DESCRIPTOR *
+OhciCreateTD (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ TD_DESCRIPTOR *Td;
+
+ Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR));
+ if (Td == NULL) {
+ DEBUG ((EFI_D_INFO, "STV allocate TD fail !\r\n"));
+ return NULL;
+ }
+ Td->CurrBufferPointer = 0;
+ Td->NextTD = 0;
+ Td->BufferEndPointer = 0;
+ Td->NextTDPointer = 0;
+
+ return Td;
+}
+
+
+/**
+
+ Free a TD
+
+ @Param Ohc UHC private data
+ @Param Td Pointer to a TD to free
+
+ @retval EFI_SUCCESS TD freed
+
+**/
+EFI_STATUS
+OhciFreeTD (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN TD_DESCRIPTOR *Td
+ )
+{
+ if (Td == NULL) {
+ return EFI_SUCCESS;
+ }
+ UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Create a ED
+
+ @Param Ohc Device private data
+
+ @retval ED descriptor pointer
+
+**/
+ED_DESCRIPTOR *
+OhciCreateED (
+ USB_OHCI_HC_DEV *Ohc
+ )
+{
+ ED_DESCRIPTOR *Ed;
+ Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR));
+ if (Ed == NULL) {
+ DEBUG ((EFI_D_INFO, "STV allocate ED fail !\r\n"));
+ return NULL;
+ }
+ Ed->Word0.Skip = 1;
+ Ed->TdTailPointer = 0;
+ Ed->Word2.TdHeadPointer = 0;
+ Ed->NextED = 0;
+
+ return Ed;
+}
+
+/**
+
+ Free a ED
+
+ @Param Ohc UHC private data
+ @Param Ed Pointer to a ED to free
+
+ @retval EFI_SUCCESS ED freed
+
+**/
+
+EFI_STATUS
+OhciFreeED (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *Ed
+ )
+{
+ if (Ed == NULL) {
+ return EFI_SUCCESS;
+ }
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Free ED
+
+ @Param Ohc Device private data
+ @Param Ed Pointer to a ED to free
+
+ @retval EFI_SUCCESS ED freed
+
+**/
+EFI_STATUS
+OhciFreeAllTDFromED (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *Ed
+ )
+{
+ TD_DESCRIPTOR *HeadTd;
+ TD_DESCRIPTOR *TailTd;
+ TD_DESCRIPTOR *Td;
+ TD_DESCRIPTOR *TempTd;
+
+ if (Ed == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ HeadTd = TD_PTR (Ed->Word2.TdHeadPointer);
+ TailTd = (TD_DESCRIPTOR *)(UINTN)(Ed->TdTailPointer);
+
+ Td = HeadTd;
+ while (Td != TailTd) {
+ TempTd = Td;
+ Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer);
+ OhciFreeTD (Ohc, TempTd);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Find a working ED match the requirement
+
+ @Param EdHead Head of the ED list
+ @Param DeviceAddress Device address to search
+ @Param EndPointNum End point num to search
+ @Param EdDir ED Direction to search
+
+ @retval ED descriptor searched
+
+**/
+
+ED_DESCRIPTOR *
+OhciFindWorkingEd (
+ IN ED_DESCRIPTOR *EdHead,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointNum,
+ IN UINT8 EdDir
+ )
+{
+ ED_DESCRIPTOR *Ed;
+
+ for (Ed = EdHead; Ed != NULL; Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED)) {
+ if (Ed->Word2.Halted == 0 && Ed->Word0.Skip == 0 &&
+ Ed->Word0.FunctionAddress == DeviceAddress && Ed->Word0.EndPointNum == EndPointNum &&
+ Ed->Word0.Direction == EdDir) {
+ break;
+ }
+ }
+
+ return Ed;
+}
+
+
+/**
+
+ Initialize interrupt list.
+
+ @Param Ohc Device private data
+
+ @retval EFI_SUCCESS Initialization done
+
+**/
+EFI_STATUS
+OhciInitializeInterruptList (
+ USB_OHCI_HC_DEV *Ohc
+ )
+{
+ static UINT32 Leaf[32] = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17,
+ 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31};
+ UINT32 *HccaInterruptTable;
+ UINTN Index;
+ UINTN Level;
+ UINTN Count;
+ ED_DESCRIPTOR *NewEd;
+
+ HccaInterruptTable = Ohc->HccaMemoryBlock->HccaInterruptTable;
+
+ for (Index = 0; Index < 32; Index++) {
+ NewEd = OhciCreateED (Ohc);
+ if (NewEd == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ HccaInterruptTable[Index] = (UINT32)(UINTN)NewEd;
+ }
+
+ for (Index = 0; Index < 32; Index++) {
+ Ohc->IntervalList[0][Index] = (ED_DESCRIPTOR *)(UINTN)HccaInterruptTable[Leaf[Index]];
+ }
+
+ Count = 32;
+ for (Level = 1; Level <= 5; Level++) {
+ Count = Count >> 1;
+
+ for (Index = 0; Index < Count; Index++) {
+ Ohc->IntervalList[Level][Index] = OhciCreateED (Ohc);
+ if (HccaInterruptTable[Index] == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Ohc->IntervalList[Level - 1][Index * 2 ]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index];
+ Ohc->IntervalList[Level - 1][Index * 2 + 1]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index];
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Attach an ED
+
+ @Param Ed Ed to be attached
+ @Param NewEd Ed to attach
+
+ @retval EFI_SUCCESS NewEd attached to Ed
+ @retval EFI_INVALID_PARAMETER Ed is NULL
+
+**/
+EFI_STATUS
+OhciAttachED (
+ IN ED_DESCRIPTOR *Ed,
+ IN ED_DESCRIPTOR *NewEd
+ )
+{
+ ED_DESCRIPTOR *Temp;
+
+ if (Ed == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Ed->NextED == 0){
+ Ed->NextED = (UINT32)(UINTN)NewEd;
+ } else {
+ Temp = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+ Ed->NextED = (UINT32)(UINTN)NewEd;
+ NewEd->NextED = (UINT32)(UINTN)Temp;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Count ED number on a ED chain
+
+ @Param Ed Head of the ED chain
+
+ @retval ED number on the chain
+
+**/
+
+UINTN
+CountEdNum (
+ IN ED_DESCRIPTOR *Ed
+ )
+{
+ UINTN Count;
+
+ Count = 0;
+
+ while (Ed) {
+ Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+ Count++;
+ }
+
+ return Count;
+}
+
+/**
+
+ Find the minimal burn ED list on a specific depth level
+
+ @Param Ohc Device private data
+ @Param Depth Depth level
+
+ @retval ED list found
+
+**/
+
+ED_DESCRIPTOR *
+OhciFindMinInterruptEDList (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Depth
+ )
+{
+ UINTN EdNum;
+ UINTN MinEdNum;
+ ED_DESCRIPTOR *TempEd;
+ ED_DESCRIPTOR *HeadEd;
+ UINTN Index;
+
+ if (Depth > 5) {
+ return NULL;
+ }
+
+ MinEdNum = 0xFFFFFFFF;
+ TempEd = NULL;
+ for (Index = 0; Index < (UINTN)(32 >> Depth); Index++) {
+ HeadEd = Ohc->IntervalList[Depth][Index];
+ EdNum = CountEdNum (HeadEd);
+ if (EdNum < MinEdNum) {
+ MinEdNum = EdNum;
+ TempEd = HeadEd;
+ }
+ }
+
+ ASSERT (TempEd != NULL);
+
+ return TempEd;
+}
+
+
+/**
+
+ Attach an ED to an ED list
+
+ @Param OHC UHC private data
+ @Param ListType Type of the ED list
+ @Param Ed ED to attach
+ @Param EdList ED list to be attached
+
+ @retval EFI_SUCCESS ED attached to ED list
+
+**/
+ED_DESCRIPTOR *
+OhciAttachEDToList (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN DESCRIPTOR_LIST_TYPE ListType,
+ IN ED_DESCRIPTOR *Ed,
+ IN ED_DESCRIPTOR *EdList
+ )
+{
+ ED_DESCRIPTOR *HeadEd;
+
+ HeadEd = NULL;
+ switch(ListType) {
+ case CONTROL_LIST:
+ HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD);
+ if (HeadEd == NULL) {
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed);
+ HeadEd = Ed;
+ } else {
+ OhciAttachED (HeadEd, Ed);
+ }
+ break;
+
+ case BULK_LIST:
+ HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD);
+ if (HeadEd == NULL) {
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed);
+ HeadEd = Ed;
+ } else {
+ OhciAttachED (HeadEd, Ed);
+ }
+ break;
+
+ case INTERRUPT_LIST:
+ OhciAttachED (EdList, Ed);
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return HeadEd;
+}
+
+/**
+
+ Remove interrupt EDs that match requirement
+
+ @Param Ohc UHC private data
+ @Param IntEd The address of Interrupt endpoint
+
+ @retval EFI_SUCCESS EDs match requirement removed
+
+**/
+
+EFI_STATUS
+OhciFreeInterruptEdByEd (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *IntEd
+ )
+{
+ ED_DESCRIPTOR *Ed;
+ ED_DESCRIPTOR *TempEd;
+ UINTN Index;
+
+ if (IntEd == NULL)
+ return EFI_SUCCESS;
+
+ for (Index = 0; Index < 32; Index++) {
+ Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index];
+ if (Ed == NULL) {
+ continue;
+ }
+ while (Ed->NextED != 0) {
+ if (Ed->NextED == (UINT32)(UINTN)IntEd ) {
+ TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+ Ed->NextED = TempEd->NextED;
+ OhciFreeED (Ohc, TempEd);
+ } else {
+ Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Remove interrupt EDs that match requirement
+
+ @Param Ohc UHC private data
+ @Param FunctionAddress Requirement on function address
+ @Param EndPointNum Requirement on end point number
+
+ @retval EFI_SUCCESS EDs match requirement removed
+
+**/
+EFI_STATUS
+OhciFreeInterruptEdByAddr (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT8 FunctionAddress,
+ IN UINT8 EndPointNum
+ )
+{
+ ED_DESCRIPTOR *Ed;
+ ED_DESCRIPTOR *TempEd;
+ UINTN Index;
+
+ for (Index = 0; Index < 32; Index++) {
+ Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index];
+ if (Ed == NULL) {
+ continue;
+ }
+
+ while (Ed->NextED != 0) {
+ TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+ if (TempEd->Word0.FunctionAddress == FunctionAddress &&
+ TempEd->Word0.EndPointNum == EndPointNum ) {
+ Ed->NextED = TempEd->NextED;
+ OhciFreeED (Ohc, TempEd);
+ } else {
+ Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Link Td2 to the end of Td1
+
+ @Param Td1 TD to be linked
+ @Param Td2 TD to link
+
+ @retval EFI_SUCCESS TD successfully linked
+ @retval EFI_INVALID_PARAMETER Td1 is NULL
+
+**/
+EFI_STATUS
+OhciLinkTD (
+ IN TD_DESCRIPTOR *Td1,
+ IN TD_DESCRIPTOR *Td2
+ )
+{
+ TD_DESCRIPTOR *TempTd;
+
+ if (Td1 == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Td1 == Td2) {
+ return EFI_SUCCESS;
+ }
+
+ TempTd = Td1;
+ while (TempTd->NextTD != 0) {
+ TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD);
+ }
+
+ TempTd->NextTD = (UINT32)(UINTN)Td2;
+ TempTd->NextTDPointer = (UINT32)(UINTN)Td2;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Attach TD list to ED
+
+ @Param Ed ED which TD list attach on
+ @Param HeadTd Head of the TD list to attach
+
+ @retval EFI_SUCCESS TD list attached on the ED
+
+**/
+EFI_STATUS
+OhciAttachTDListToED (
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd
+ )
+{
+ TD_DESCRIPTOR *TempTd;
+
+ TempTd = TD_PTR (Ed->Word2.TdHeadPointer);
+
+ if (TempTd != NULL) {
+ while (TempTd->NextTD != 0) {
+ TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD);
+ }
+ TempTd->NextTD = (UINT32)(UINTN)HeadTd;
+ TempTd->NextTDPointer = (UINT32)(UINTN)HeadTd;
+ } else {
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32)(UINTN)HeadTd);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Set value to ED specific field
+
+ @Param Ed ED to be set
+ @Param Field Field to be set
+ @Param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetEDField (
+ IN ED_DESCRIPTOR *Ed,
+ IN UINT32 Field,
+ IN UINT32 Value
+ )
+{
+ if (Field & ED_FUNC_ADD) {
+ Ed->Word0.FunctionAddress = Value;
+ }
+ if (Field & ED_ENDPT_NUM) {
+ Ed->Word0.EndPointNum = Value;
+ }
+ if (Field & ED_DIR) {
+ Ed->Word0.Direction = Value;
+ }
+ if (Field & ED_SPEED) {
+ Ed->Word0.Speed = Value;
+ }
+ if (Field & ED_SKIP) {
+ Ed->Word0.Skip = Value;
+ }
+ if (Field & ED_FORMAT) {
+ Ed->Word0.Format = Value;
+ }
+ if (Field & ED_MAX_PACKET) {
+ Ed->Word0.MaxPacketSize = Value;
+ }
+ if (Field & ED_PDATA) {
+ Ed->Word0.FreeSpace = Value;
+ }
+ if (Field & ED_ZERO) {
+ Ed->Word2.Zero = Value;
+ }
+ if (Field & ED_TDTAIL_PTR) {
+ Ed->TdTailPointer = Value;
+ }
+
+ if (Field & ED_HALTED) {
+ Ed->Word2.Halted = Value;
+ }
+ if (Field & ED_DTTOGGLE) {
+ Ed->Word2.ToggleCarry = Value;
+ }
+ if (Field & ED_TDHEAD_PTR) {
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value);
+ }
+
+ if (Field & ED_NEXT_EDPTR) {
+ Ed->NextED = Value;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get value from an ED's specific field
+
+ @Param Ed ED pointer
+ @Param Field Field to get value from
+
+ @retval Value of the field
+
+**/
+UINT32
+OhciGetEDField (
+ IN ED_DESCRIPTOR *Ed,
+ IN UINT32 Field
+ )
+{
+ switch (Field) {
+ case ED_FUNC_ADD:
+ return Ed->Word0.FunctionAddress;
+ break;
+ case ED_ENDPT_NUM:
+ return Ed->Word0.EndPointNum;
+ break;
+ case ED_DIR:
+ return Ed->Word0.Direction;
+ break;
+ case ED_SPEED:
+ return Ed->Word0.Speed;
+ break;
+ case ED_SKIP:
+ return Ed->Word0.Skip;
+ break;
+ case ED_FORMAT:
+ return Ed->Word0.Format;
+ break;
+ case ED_MAX_PACKET:
+ return Ed->Word0.MaxPacketSize;
+ break;
+
+ case ED_TDTAIL_PTR:
+ return Ed->TdTailPointer;
+ break;
+
+ case ED_HALTED:
+ return Ed->Word2.Halted;
+ break;
+
+ case ED_DTTOGGLE:
+ return Ed->Word2.ToggleCarry;
+ break;
+
+ case ED_TDHEAD_PTR:
+ return Ed->Word2.TdHeadPointer << 4;
+ break;
+
+ case ED_NEXT_EDPTR:
+ return Ed->NextED;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+
+/**
+
+ Set value to TD specific field
+
+ @Param Td TD to be set
+ @Param Field Field to be set
+ @Param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetTDField (
+ IN TD_DESCRIPTOR *Td,
+ IN UINT32 Field,
+ IN UINT32 Value
+ )
+{
+ if (Field & TD_PDATA) {
+ Td->Word0.Reserved = Value;
+ }
+ if (Field & TD_BUFFER_ROUND) {
+ Td->Word0.BufferRounding = Value;
+ }
+ if (Field & TD_DIR_PID) {
+ Td->Word0.DirPID = Value;
+ }
+ if (Field & TD_DELAY_INT) {
+ Td->Word0.DelayInterrupt = Value;
+ }
+ if (Field & TD_DT_TOGGLE) {
+ Td->Word0.DataToggle = Value | 0x2;
+ }
+ if (Field & TD_ERROR_CNT) {
+ Td->Word0.ErrorCount = Value;
+ }
+ if (Field & TD_COND_CODE) {
+ Td->Word0.ConditionCode = Value;
+ }
+
+ if (Field & TD_CURR_BUFFER_PTR) {
+ Td->CurrBufferPointer = Value;
+ }
+
+
+ if (Field & TD_NEXT_PTR) {
+ Td->NextTD = Value;
+ }
+
+ if (Field & TD_BUFFER_END_PTR) {
+ Td->BufferEndPointer = Value;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Get value from ED specific field
+
+ @Param Td TD pointer
+ @Param Field Field to get value from
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetTDField (
+ IN TD_DESCRIPTOR *Td,
+ IN UINT32 Field
+ )
+{
+ switch (Field){
+ case TD_BUFFER_ROUND:
+ return Td->Word0.BufferRounding;
+ break;
+ case TD_DIR_PID:
+ return Td->Word0.DirPID;
+ break;
+ case TD_DELAY_INT:
+ return Td->Word0.DelayInterrupt;
+ break;
+ case TD_DT_TOGGLE:
+ return Td->Word0.DataToggle;
+ break;
+ case TD_ERROR_CNT:
+ return Td->Word0.ErrorCount;
+ break;
+ case TD_COND_CODE:
+ return Td->Word0.ConditionCode;
+ break;
+ case TD_CURR_BUFFER_PTR:
+ return Td->CurrBufferPointer;
+ break;
+
+ case TD_NEXT_PTR:
+ return Td->NextTD;
+ break;
+
+ case TD_BUFFER_END_PTR:
+ return Td->BufferEndPointer;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Free the Ed,Td,buffer that were created during transferring
+
+ @Param Ohc Device private data
+**/
+
+VOID
+OhciFreeDynamicIntMemory(
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ INTERRUPT_CONTEXT_ENTRY *Entry;
+ if (Ohc != NULL) {
+ while (Ohc->InterruptContextList != NULL) {
+ Entry = Ohc->InterruptContextList;
+ Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry;
+ OhciFreeInterruptEdByEd (Ohc, Entry->Ed);
+ OhciFreeInterruptContextEntry (Ohc, Entry);
+ }
+ }
+}
+/**
+
+ Free the Ed that were initilized during driver was starting,
+ those memory were used as interrupt ED head
+
+ @Param Ohc Device private data
+
+
+**/
+VOID
+OhciFreeFixedIntMemory (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ static UINT32 Leaf[] = {32,16,8,4,2,1};
+ UINTN Index;
+ UINTN Level;
+
+ for (Level = 0; Level < 6; Level++) {
+ for (Index = 0; Index < Leaf[Level]; Index++) {
+ if (Ohc->IntervalList[Level][Index] != NULL) {
+ UsbHcFreeMem(Ohc->MemPool, Ohc->IntervalList[Level][Index], sizeof(ED_DESCRIPTOR));
+ }
+ }
+ }
+}
+/**
+
+ Release all OHCI used memory when OHCI going to quit
+
+ @Param Ohc Device private data
+
+ @retval EFI_SUCCESS Memory released
+
+**/
+
+EFI_STATUS
+OhciFreeIntTransferMemory (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ //
+ // Free the Ed,Td,buffer that were created during transferring
+ //
+ OhciFreeDynamicIntMemory (Ohc);
+ //
+ // Free the Ed that were initilized during driver was starting
+ //
+ OhciFreeFixedIntMemory (Ohc);
+ return EFI_SUCCESS;
+}
+
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h
new file mode 100644
index 0000000000..47851fd43c
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h
@@ -0,0 +1,393 @@
+/** @file
+Provides some data struct used by OHCI controller 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 _OHCI_URB_H
+#define _OHCI_URB_H
+
+#include "Descriptor.h"
+
+
+//
+// Func List
+//
+
+
+/**
+
+ Create a TD
+
+ @Param Ohc UHC private data
+
+ @retval TD structure pointer
+
+**/
+TD_DESCRIPTOR *
+OhciCreateTD (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+
+/**
+
+ Free a TD
+
+ @Param Ohc UHC private data
+ @Param Td Pointer to a TD to free
+
+ @retval EFI_SUCCESS TD freed
+
+**/
+EFI_STATUS
+OhciFreeTD (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN TD_DESCRIPTOR *Td
+ );
+
+/**
+
+ Create a ED
+
+ @Param Ohc Device private data
+
+ @retval ED descriptor pointer
+
+**/
+ED_DESCRIPTOR *
+OhciCreateED (
+ USB_OHCI_HC_DEV *Ohc
+ );
+
+
+/**
+
+ Free a ED
+
+ @Param Ohc UHC private data
+ @Param Ed Pointer to a ED to free
+
+ @retval EFI_SUCCESS ED freed
+
+**/
+
+EFI_STATUS
+OhciFreeED (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *Ed
+ );
+
+/**
+
+ Free ED
+
+ @Param Ohc Device private data
+ @Param Ed Pointer to a ED to free
+
+ @retval EFI_SUCCESS ED freed
+
+**/
+EFI_STATUS
+OhciFreeAllTDFromED (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *Ed
+ );
+
+/**
+
+ Find a working ED match the requirement
+
+ @Param EdHead Head of the ED list
+ @Param DeviceAddress Device address to search
+ @Param EndPointNum End point num to search
+ @Param EdDir ED Direction to search
+
+ @retval ED descriptor searched
+
+**/
+
+ED_DESCRIPTOR *
+OhciFindWorkingEd (
+ IN ED_DESCRIPTOR *EdHead,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointNum,
+ IN UINT8 EdDir
+ );
+
+
+/**
+
+ Initialize interrupt list.
+
+ @Param Ohc Device private data
+
+ @retval EFI_SUCCESS Initialization done
+
+**/
+EFI_STATUS
+OhciInitializeInterruptList (
+ USB_OHCI_HC_DEV *Ohc
+ );
+
+/**
+
+ Attach an ED
+
+ @Param Ed Ed to be attached
+ @Param NewEd Ed to attach
+
+ @retval EFI_SUCCESS NewEd attached to Ed
+ @retval EFI_INVALID_PARAMETER Ed is NULL
+
+**/
+EFI_STATUS
+OhciAttachED (
+ IN ED_DESCRIPTOR *Ed,
+ IN ED_DESCRIPTOR *NewEd
+ );
+
+/**
+
+ Count ED number on a ED chain
+
+ @Param Ed Head of the ED chain
+
+ @retval ED number on the chain
+
+**/
+
+UINTN
+CountEdNum (
+ IN ED_DESCRIPTOR *Ed
+ );
+
+/**
+
+ Find the minimal burn ED list on a specific depth level
+
+ @Param Ohc Device private data
+ @Param Depth Depth level
+
+ @retval ED list found
+
+**/
+
+ED_DESCRIPTOR *
+OhciFindMinInterruptEDList (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Depth
+ );
+
+/**
+
+ Attach an ED to an ED list
+
+ @Param OHC UHC private data
+ @Param ListType Type of the ED list
+ @Param Ed ED to attach
+ @Param EdList ED list to be attached
+
+ @retval EFI_SUCCESS ED attached to ED list
+
+**/
+ED_DESCRIPTOR *
+OhciAttachEDToList (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN DESCRIPTOR_LIST_TYPE ListType,
+ IN ED_DESCRIPTOR *Ed,
+ IN ED_DESCRIPTOR *EdList
+ );
+
+/**
+
+ Remove interrupt EDs that match requirement
+
+ @Param Ohc UHC private data
+ @Param IntEd The address of Interrupt endpoint
+
+ @retval EFI_SUCCESS EDs match requirement removed
+
+**/
+
+EFI_STATUS
+OhciFreeInterruptEdByEd (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *IntEd
+ );
+
+/**
+
+ Remove interrupt EDs that match requirement
+
+ @Param Ohc UHC private data
+ @Param FunctionAddress Requirement on function address
+ @Param EndPointNum Requirement on end point number
+
+ @retval EFI_SUCCESS EDs match requirement removed
+
+**/
+EFI_STATUS
+OhciFreeInterruptEdByAddr (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT8 FunctionAddress,
+ IN UINT8 EndPointNum
+ );
+
+
+/**
+
+ Link Td2 to the end of Td1
+
+ @Param Td1 TD to be linked
+ @Param Td2 TD to link
+
+ @retval EFI_SUCCESS TD successfully linked
+ @retval EFI_INVALID_PARAMETER Td1 is NULL
+
+**/
+EFI_STATUS
+OhciLinkTD (
+ IN TD_DESCRIPTOR *Td1,
+ IN TD_DESCRIPTOR *Td2
+ );
+
+
+/**
+
+ Attach TD list to ED
+
+ @Param Ed ED which TD list attach on
+ @Param HeadTd Head of the TD list to attach
+
+ @retval EFI_SUCCESS TD list attached on the ED
+
+**/
+EFI_STATUS
+OhciAttachTDListToED (
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd
+ );
+
+
+/**
+
+ Set value to ED specific field
+
+ @Param Ed ED to be set
+ @Param Field Field to be set
+ @Param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetEDField (
+ IN ED_DESCRIPTOR *Ed,
+ IN UINT32 Field,
+ IN UINT32 Value
+ );
+
+
+/**
+
+ Get value from an ED's specific field
+
+ @Param Ed ED pointer
+ @Param Field Field to get value from
+
+ @retval Value of the field
+
+**/
+UINT32
+OhciGetEDField (
+ IN ED_DESCRIPTOR *Ed,
+ IN UINT32 Field
+ );
+
+
+/**
+
+ Set value to TD specific field
+
+ @Param Td TD to be set
+ @Param Field Field to be set
+ @Param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetTDField (
+ IN TD_DESCRIPTOR *Td,
+ IN UINT32 Field,
+ IN UINT32 Value
+ );
+
+
+/**
+
+ Get value from ED specific field
+
+ @Param Td TD pointer
+ @Param Field Field to get value from
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetTDField (
+ IN TD_DESCRIPTOR *Td,
+ IN UINT32 Field
+ );
+/**
+
+ Free the Ed,Td,buffer that were created during transferring
+
+ @Param Ohc Device private data
+**/
+
+VOID
+OhciFreeDynamicIntMemory(
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+
+/**
+
+ Free the Ed that were initilized during driver was starting,
+ those memory were used as interrupt ED head
+
+ @Param Ohc Device private data
+
+
+**/
+VOID
+OhciFreeFixedIntMemory (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+/**
+
+ Release all OHCI used memory when OHCI going to quit
+
+ @Param Ohc Device private data
+
+ @retval EFI_SUCCESS Memory released
+
+**/
+
+EFI_STATUS
+OhciFreeIntTransferMemory (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c
new file mode 100644
index 0000000000..dd42938dfd
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c
@@ -0,0 +1,566 @@
+/** @file
+Routine procedures for memory allocate/free.
+
+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 "Ohci.h"
+
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ @param Pool The buffer pool to allocate memory for.
+ @param Pages How many pages to allocate.
+
+ @return The allocated memory block or NULL if failed.
+
+**/
+USBHC_MEM_BLOCK *
+UsbHcAllocMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Pages
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ UINTN Bytes;
+ EFI_STATUS Status;
+
+ PciIo = Pool->PciIo;
+
+ Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));
+ if (Block == NULL) {
+ return NULL;
+ }
+
+ //
+ // each bit in the bit array represents USBHC_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
+ Block->Bits = AllocateZeroPool (Block->BitsLen);
+
+ if (Block->Bits == NULL) {
+ gBS->FreePool (Block);
+ return NULL;
+ }
+
+ //
+ // Allocate the number of Pages of memory, then map it for
+ // bus master read and write.
+ //
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Pages,
+ &BufHost,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_BITARRAY;
+ }
+
+ Bytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ BufHost,
+ &Bytes,
+ &MappedAddr,
+ &Mapping
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
+ goto FREE_BUFFER;
+ }
+
+ //
+ // Check whether the data structure used by the host controller
+ // should be restricted into the same 4G
+ //
+ if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
+ PciIo->Unmap (PciIo, Mapping);
+ goto FREE_BUFFER;
+ }
+
+ Block->BufHost = BufHost;
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);
+ Block->Mapping = Mapping;
+
+ return Block;
+
+FREE_BUFFER:
+ PciIo->FreeBuffer (PciIo, Pages, BufHost);
+
+FREE_BITARRAY:
+ gBS->FreePool (Block->Bits);
+ gBS->FreePool (Block);
+ return NULL;
+}
+
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+UsbHcFreeMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ ASSERT ((Pool != NULL) && (Block != NULL));
+
+ PciIo = Pool->PciIo;
+
+ //
+ // Unmap the common buffer then free the structures
+ //
+ PciIo->Unmap (PciIo, Block->Mapping);
+ PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);
+
+ gBS->FreePool (Block->Bits);
+ gBS->FreePool (Block);
+}
+
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+ the return value is NULL.
+
+**/
+VOID *
+UsbHcAllocMemFromBlock (
+ IN USBHC_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consective number of zero bit.
+ //
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ NEXT_BIT (Byte, Bit);
+
+ } else {
+ NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
+}
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINTN AllocSize;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ UINTN Offset;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+
+ if (Mem == NULL) {
+ return 0;
+ }
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the allocated memory.
+ //
+ if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ break;
+ }
+ }
+
+ ASSERT ((Block != NULL));
+ //
+ // calculate the pci memory address for host memory address.
+ //
+ Offset = (UINT8 *)Mem - Block->BufHost;
+ PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);
+ return PhyAddr;
+}
+
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+UsbHcInsertMemBlockToPool (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @retval TRUE The memory block is empty.
+ @retval FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+UsbHcIsMemBlockEmpty (
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Unlink the memory block from the pool's list.
+
+ @param Head The block list head of the memory's pool.
+ @param BlockToUnlink The memory block to unlink.
+
+**/
+VOID
+UsbHcUnlinkMemBlock (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *BlockToUnlink
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ if (Block->Next == BlockToUnlink) {
+ Block->Next = BlockToUnlink->Next;
+ BlockToUnlink->Next = NULL;
+ break;
+ }
+ }
+}
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Check4G Whether the host controller requires allocated memory
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ )
+{
+ USBHC_MEM_POOL *Pool;
+
+ Pool = AllocatePool (sizeof (USBHC_MEM_POOL));
+
+ if (Pool == NULL) {
+ return Pool;
+ }
+
+ Pool->PciIo = PciIo;
+ Pool->Check4G = Check4G;
+ Pool->Which4G = Which4G;
+ Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ gBS->FreePool (Pool);
+ Pool = NULL;
+ }
+
+ return Pool;
+}
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_SUCCESS The memory pool is freed.
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the
+ // first block.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+ UsbHcUnlinkMemBlock (Pool->Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ UsbHcFreeMemBlock (Pool, Pool->Head);
+ gBS->FreePool (Pool);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ USBHC_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+ } else {
+ Pages = USBHC_MEM_DEFAULT_PAGES;
+ }
+
+ NewBlock = UsbHcAllocMemBlock (Pool, Pages);
+
+ if (NewBlock == NULL) {
+ DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ UsbHcInsertMemBlockToPool (Head, NewBlock);
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit arry
+ //
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory point
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
+ UsbHcUnlinkMemBlock (Head, Block);
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ return ;
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h
new file mode 100644
index 0000000000..e16425e34c
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h
@@ -0,0 +1,158 @@
+/** @file
+This file contains the definination for host controller memory
+management 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 _USB_HC_MEM_H_
+#define _USB_HC_MEM_H_
+
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))
+
+#define USB_HC_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
+
+#define USB_HC_HIGH_32BIT(Addr64) \
+ ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
+struct _USBHC_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ USBHC_MEM_BLOCK *Next;
+};
+
+//
+// USBHC_MEM_POOL is used to manage the memory used by USB
+// host controller. EHCI requires the control memory and transfer
+// data to be on the same 4G memory.
+//
+typedef struct _USBHC_MEM_POOL {
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ BOOLEAN Check4G;
+ UINT32 Which4G;
+ USBHC_MEM_BLOCK *Head;
+} USBHC_MEM_POOL;
+
+//
+// Memory allocation unit, must be 2^n, n>4
+//
+#define USBHC_MEM_UNIT 64
+
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)
+#define USBHC_MEM_DEFAULT_PAGES 16
+
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Check4G Whether the host controller requires allocated memory
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ );
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_SUCCESS The memory pool is freed.
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ );
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ );
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+/**
+ Calculate the corresponding pci bus address according to the Mem parameter.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The pointer to host memory.
+ @param Size The size of the memory region.
+
+ @return the pci memory address
+**/
+EFI_PHYSICAL_ADDRESS
+UsbHcGetPciAddressForHostMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h
new file mode 100644
index 0000000000..e7cc319fe1
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h
@@ -0,0 +1,137 @@
+/** @file
+This file contains the descriptor definination of OHCI spec
+
+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 _DESCRIPTOR_H
+#define _DESCRIPTOR_H
+
+#define ED_FUNC_ADD 0x0001
+#define ED_ENDPT_NUM 0x0002
+#define ED_DIR 0x0004
+#define ED_SPEED 0x0008
+#define ED_SKIP 0x0010
+#define ED_FORMAT 0x0020
+#define ED_MAX_PACKET 0x0040
+#define ED_TDTAIL_PTR 0x0080
+#define ED_HALTED 0x0100
+#define ED_DTTOGGLE 0x0200
+#define ED_TDHEAD_PTR 0x0400
+#define ED_NEXT_EDPTR 0x0800
+#define ED_PDATA 0x1000
+#define ED_ZERO 0x2000
+
+#define TD_BUFFER_ROUND 0x0001
+#define TD_DIR_PID 0x0002
+#define TD_DELAY_INT 0x0004
+#define TD_DT_TOGGLE 0x0008
+#define TD_ERROR_CNT 0x0010
+#define TD_COND_CODE 0x0020
+#define TD_CURR_BUFFER_PTR 0x0040
+#define TD_NEXT_PTR 0x0080
+#define TD_BUFFER_END_PTR 0x0100
+#define TD_PDATA 0x0200
+
+#define ED_FROM_TD_DIR 0x0
+#define ED_OUT_DIR 0x1
+#define ED_IN_DIR 0x2
+#define ED_FROM_TD_ALSO_DIR 0x3
+
+#define TD_SETUP_PID 0x00
+#define TD_OUT_PID 0x01
+#define TD_IN_PID 0x02
+#define TD_NODATA_PID 0x03
+
+#define HI_SPEED 0
+#define LO_SPEED 1
+
+#define TD_NO_ERROR 0x00
+#define TD_CRC_ERROR 0x01
+#define TD_BITSTUFFING_ERROR 0x02
+#define TD_TOGGLE_ERROR 0x03
+#define TD_DEVICE_STALL 0x04
+#define TD_NO_RESPONSE 0x05
+#define TD_PIDCHK_FAIL 0x06
+#define TD_PID_UNEXPECTED 0x07
+#define TD_DATA_OVERRUN 0x08
+#define TD_DATA_UNDERRUN 0x09
+#define TD_BUFFER_OVERRUN 0x0C
+#define TD_BUFFER_UNDERRUN 0x0D
+#define TD_TOBE_PROCESSED 0x0E
+#define TD_TOBE_PROCESSED_2 0x0F
+
+#define TD_NO_DELAY 0x7
+
+#define TD_INT 0x1
+#define TD_CTL 0x2
+#define TD_BLK 0x3
+
+typedef struct {
+ UINT32 Reserved:18;
+ UINT32 BufferRounding:1;
+ UINT32 DirPID:2;
+ UINT32 DelayInterrupt:3;
+ UINT32 DataToggle:2;
+ UINT32 ErrorCount:2;
+ UINT32 ConditionCode:4;
+} TD_DESCRIPTOR_WORD0;
+
+typedef struct _TD_DESCRIPTOR {
+ TD_DESCRIPTOR_WORD0 Word0;
+ VOID *CurrBufferPointer;
+ struct _TD_DESCRIPTOR *NextTD;
+ VOID *BufferEndPointer;
+ struct _TD_DESCRIPTOR *NextTDPointer;
+ UINT8 *DataBuffer;
+ UINT32 ActualSendLength;
+} TD_DESCRIPTOR;
+
+typedef struct {
+ UINT32 FunctionAddress:7;
+ UINT32 EndPointNum:4;
+ UINT32 Direction:2;
+ UINT32 Speed:1;
+ UINT32 Skip:1;
+ UINT32 Format:1;
+ UINT32 MaxPacketSize:11;
+ UINT32 FreeSpace:5;
+} ED_DESCRIPTOR_WORD0;
+
+typedef struct {
+ UINT32 Halted:1;
+ UINT32 ToggleCarry:1;
+ UINT32 Zero:2;
+ UINT32 TdHeadPointer:28;
+} ED_DESCRIPTOR_WORD2;
+
+typedef struct _ED_DESCRIPTOR {
+ ED_DESCRIPTOR_WORD0 Word0;
+ TD_DESCRIPTOR *TdTailPointer;
+ ED_DESCRIPTOR_WORD2 Word2;
+ struct _ED_DESCRIPTOR *NextED;
+} ED_DESCRIPTOR;
+
+#define TD_PTR(p) ((TD_DESCRIPTOR *)((p) << 4))
+#define ED_PTR(p) ((ED_DESCRIPTOR *)((p) << 4))
+#define RIGHT_SHIFT_4(p) ((UINT32)(p) >> 4)
+
+typedef enum {
+ CONTROL_LIST,
+ BULK_LIST,
+ INTERRUPT_LIST,
+ ISOCHRONOUS_LIST
+} DESCRIPTOR_LIST_TYPE;
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c
new file mode 100644
index 0000000000..c38d4969d8
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c
@@ -0,0 +1,1402 @@
+/** @file
+This file contains the implementation of Usb Hc 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 "OhcPeim.h"
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage.
+ @param Data Data buffer to be transmitted or received from USB device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param TimeOut Indicates the maximum timeout, in millisecond.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 MaxPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ ED_DESCRIPTOR *Ed;
+ TD_DESCRIPTOR *HeadTd;
+ TD_DESCRIPTOR *SetupTd;
+ TD_DESCRIPTOR *DataTd;
+ TD_DESCRIPTOR *StatusTd;
+ TD_DESCRIPTOR *EmptyTd;
+ EFI_STATUS Status;
+ UINT32 DataPidDir;
+ UINT32 StatusPidDir;
+ UINTN TimeCount;
+ UINT32 ErrorCode;
+
+ UINTN ActualSendLength;
+ UINTN LeftLength;
+ UINT8 DataToggle;
+
+ UINTN ReqMapLength = 0;
+ EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0;
+
+ UINTN DataMapLength = 0;
+ EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0;
+
+ HeadTd = NULL;
+ DataTd = NULL;
+
+ if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn &&
+ TransferDirection != EfiUsbNoData) ||
+ Request == NULL || DataLength == NULL || TransferResult == NULL ||
+ (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) ||
+ (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) ||
+ (DeviceSpeed != EFI_USB_SPEED_LOW && DeviceSpeed != EFI_USB_SPEED_FULL) ||
+ (MaxPacketLength != 8 && MaxPacketLength != 16 &&
+ MaxPacketLength != 32 && MaxPacketLength != 64)) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: EFI_INVALID_PARAMETER\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*DataLength > MAX_BYTES_PER_TD) {
+ DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS(This);
+
+ if (TransferDirection == EfiUsbDataIn) {
+ DataPidDir = TD_IN_PID;
+ StatusPidDir = TD_OUT_PID;
+ } else {
+ DataPidDir = TD_OUT_PID;
+ StatusPidDir = TD_IN_PID;
+ }
+
+ OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to disable CONTROL transfer\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+ Ed = OhciCreateED (Ohc);
+ if (Ed == NULL) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ OhciSetEDField (Ed, ED_SKIP, 1);
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+ OhciSetEDField (Ed, ED_ENDPT_NUM, 0);
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+ OhciSetEDField (Ed, ED_SPEED, DeviceSpeed);
+ OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+ OhciSetEDField (Ed, ED_PDATA, 0);
+ OhciSetEDField (Ed, ED_ZERO, 0);
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL);
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL);
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL);
+ OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL);
+ //
+ // Setup Stage
+ //
+ if(Request != NULL) {
+ ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST);
+ ReqMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Request;
+ }
+ SetupTd = OhciCreateTD (Ohc);
+ if (SetupTd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\n"));
+ goto FREE_ED_BUFF;
+ }
+ HeadTd = SetupTd;
+ OhciSetTDField (SetupTd, TD_PDATA, 0);
+ OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1);
+ OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID);
+ OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY);
+ OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2);
+ OhciSetTDField (SetupTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINTN)ReqMapPhyAddr);
+ OhciSetTDField (SetupTd, TD_NEXT_PTR, (UINT32) NULL);
+ OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINTN)ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1);
+ SetupTd->ActualSendLength = 0;
+ SetupTd->DataBuffer = NULL;
+ SetupTd->NextTDPointer = NULL;
+
+ DataMapLength = *DataLength;
+ if ((Data != NULL) && (DataMapLength != 0)) {
+ DataMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data;
+ }
+ //
+ //Data Stage
+ //
+ LeftLength = DataMapLength;
+ ActualSendLength = DataMapLength;
+ DataToggle = 1;
+ while (LeftLength > 0) {
+ ActualSendLength = LeftLength;
+ if (LeftLength > MaxPacketLength) {
+ ActualSendLength = MaxPacketLength;
+ }
+ DataTd = OhciCreateTD (Ohc);
+ if (DataTd == NULL) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Data TD buffer\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FREE_TD_BUFF;
+ }
+ OhciSetTDField (DataTd, TD_PDATA, 0);
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle);
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr);
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) DataMapPhyAddr + ActualSendLength - 1);
+ OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL);
+ DataTd->ActualSendLength = ActualSendLength;
+ DataTd->DataBuffer = (UINT8 *)(UINTN)DataMapPhyAddr;
+ DataTd->NextTDPointer = 0;
+ OhciLinkTD (HeadTd, DataTd);
+ DataToggle ^= 1;
+ DataMapPhyAddr += ActualSendLength;
+ LeftLength -= ActualSendLength;
+ }
+ //
+ // Status Stage
+ //
+ StatusTd = OhciCreateTD (Ohc);
+ if (StatusTd == NULL) {
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Status TD buffer\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FREE_TD_BUFF;
+ }
+ OhciSetTDField (StatusTd, TD_PDATA, 0);
+ OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1);
+ OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir);
+ OhciSetTDField (StatusTd, TD_DELAY_INT, 7);
+ OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3);
+ OhciSetTDField (StatusTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, (UINT32) NULL);
+ OhciSetTDField (StatusTd, TD_NEXT_PTR, (UINT32) NULL);
+ OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, (UINT32) NULL);
+ StatusTd->ActualSendLength = 0;
+ StatusTd->DataBuffer = NULL;
+ StatusTd->NextTDPointer = NULL;
+ OhciLinkTD (HeadTd, StatusTd);
+ //
+ // Empty Stage
+ //
+ EmptyTd = OhciCreateTD (Ohc);
+ if (EmptyTd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Empty TD buffer\n"));
+ goto FREE_TD_BUFF;
+ }
+ OhciSetTDField (EmptyTd, TD_PDATA, 0);
+ OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);
+ OhciSetTDField (EmptyTd, TD_DIR_PID, 0);
+ OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);
+ //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
+ EmptyTd->Word0.DataToggle = 0;
+ OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (EmptyTd, TD_COND_CODE, 0);
+ OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);
+ OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);
+ OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);
+ EmptyTd->ActualSendLength = 0;
+ EmptyTd->DataBuffer = NULL;
+ EmptyTd->NextTDPointer = NULL;
+ OhciLinkTD (HeadTd, EmptyTd);
+ Ed->TdTailPointer = EmptyTd;
+ OhciAttachTDListToED (Ed, HeadTd);
+ //
+ OhciSetEDField (Ed, ED_SKIP, 0);
+ MicroSecondDelay (20 * HC_1_MILLISECOND);
+ OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1);
+ OhciSetHcControl (Ohc, CONTROL_ENABLE, 1);
+ MicroSecondDelay (20 * HC_1_MILLISECOND);
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) {
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable CONTROL transfer\n"));
+ goto FREE_TD_BUFF;
+ }
+ }
+
+ TimeCount = 0;
+ Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode);
+
+ while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ TimeCount++;
+ Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode);
+ }
+ //
+ *TransferResult = ConvertErrorCode (ErrorCode);
+
+ if (ErrorCode != TD_NO_ERROR) {
+ if (ErrorCode == TD_TOBE_PROCESSED) {
+ DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut));
+ } else {
+ DEBUG ((EFI_D_INFO, "Control pipe broken\r\n"));
+ }
+
+ *DataLength = 0;
+ }
+
+ OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Cannot disable CONTROL_ENABLE transfer\n"));
+ goto FREE_TD_BUFF;
+ }
+ }
+
+FREE_TD_BUFF:
+ while (HeadTd) {
+ DataTd = HeadTd;
+ HeadTd = HeadTd->NextTDPointer;
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+ }
+
+FREE_ED_BUFF:
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+ return Status;
+}
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param MaxiPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param Data A pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to use of
+ the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaxPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ ED_DESCRIPTOR *Ed;
+ UINT8 EdDir;
+ UINT32 DataPidDir;
+ TD_DESCRIPTOR *HeadTd;
+ TD_DESCRIPTOR *DataTd;
+ TD_DESCRIPTOR *EmptyTd;
+ EFI_STATUS Status;
+ EFI_USB_DATA_DIRECTION TransferDirection;
+ UINT8 EndPointNum;
+ UINTN TimeCount;
+ UINT32 ErrorCode;
+
+ UINT8 CurrentToggle;
+ VOID *Mapping;
+ UINTN MapLength;
+ EFI_PHYSICAL_ADDRESS MapPyhAddr;
+ UINTN LeftLength;
+ UINTN ActualSendLength;
+ BOOLEAN FirstTD;
+
+ Mapping = NULL;
+ MapLength = 0;
+ MapPyhAddr = 0;
+ LeftLength = 0;
+ Status = EFI_SUCCESS;
+
+ if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||
+ *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||
+ (MaxPacketLength != 8 && MaxPacketLength != 16 &&
+ MaxPacketLength != 32 && MaxPacketLength != 64)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+
+ if ((EndPointAddress & 0x80) != 0) {
+ TransferDirection = EfiUsbDataIn;
+ EdDir = ED_IN_DIR;
+ DataPidDir = TD_IN_PID;
+ } else {
+ TransferDirection = EfiUsbDataOut;
+ EdDir = ED_OUT_DIR;
+ DataPidDir = TD_OUT_PID;
+ }
+
+ EndPointNum = (EndPointAddress & 0xF);
+
+ OhciSetHcControl (Ohc, BULK_ENABLE, 0);
+ if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) {
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+
+ Ed = OhciCreateED (Ohc);
+ if (Ed == NULL) {
+ DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate ED buffer\r\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ OhciSetEDField (Ed, ED_SKIP, 1);
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);
+ OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);
+ OhciSetEDField (Ed, ED_SPEED, HI_SPEED);
+ OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);
+ OhciSetEDField (Ed, ED_PDATA, 0);
+ OhciSetEDField (Ed, ED_ZERO, 0);
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL);
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL);
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL);
+ OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);
+
+ if(Data != NULL) {
+ MapLength = *DataLength;
+ MapPyhAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data;
+ }
+ //
+ //Data Stage
+ //
+ LeftLength = MapLength;
+ ActualSendLength = MapLength;
+ CurrentToggle = *DataToggle;
+ HeadTd = NULL;
+ FirstTD = TRUE;
+ while (LeftLength > 0) {
+ ActualSendLength = LeftLength;
+ if (LeftLength > MaxPacketLength) {
+ ActualSendLength = MaxPacketLength;
+ }
+ DataTd = OhciCreateTD (Ohc);
+ if (DataTd == NULL) {
+ DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Data TD buffer\r\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FREE_TD_BUFF;
+ }
+ OhciSetTDField (DataTd, TD_PDATA, 0);
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, CurrentToggle);
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) MapPyhAddr + ActualSendLength - 1);
+ OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL);
+ DataTd->ActualSendLength = ActualSendLength;
+ DataTd->DataBuffer = (UINT8 *)(UINTN)MapPyhAddr;
+ DataTd->NextTDPointer = 0;
+ if (FirstTD) {
+ HeadTd = DataTd;
+ FirstTD = FALSE;
+ } else {
+ OhciLinkTD (HeadTd, DataTd);
+ }
+ CurrentToggle ^= 1;
+ MapPyhAddr += ActualSendLength;
+ LeftLength -= ActualSendLength;
+ }
+ //
+ // Empty Stage
+ //
+ EmptyTd = OhciCreateTD (Ohc);
+ if (EmptyTd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Empty TD buffer\r\n"));
+ goto FREE_TD_BUFF;
+ }
+ OhciSetTDField (EmptyTd, TD_PDATA, 0);
+ OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);
+ OhciSetTDField (EmptyTd, TD_DIR_PID, 0);
+ OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);
+ //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
+ EmptyTd->Word0.DataToggle = 0;
+ OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);
+ OhciSetTDField (EmptyTd, TD_COND_CODE, 0);
+ OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);
+ OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);
+ OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);
+ EmptyTd->ActualSendLength = 0;
+ EmptyTd->DataBuffer = NULL;
+ EmptyTd->NextTDPointer = NULL;
+ OhciLinkTD (HeadTd, EmptyTd);
+ Ed->TdTailPointer = EmptyTd;
+ OhciAttachTDListToED (Ed, HeadTd);
+
+ OhciSetEDField (Ed, ED_SKIP, 0);
+ OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);
+ OhciSetHcControl (Ohc, BULK_ENABLE, 1);
+ if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) {
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ goto FREE_TD_BUFF;
+ }
+ }
+
+ TimeCount = 0;
+ Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode);
+
+ while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ TimeCount++;
+ Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode);
+ }
+
+ *TransferResult = ConvertErrorCode (ErrorCode);
+
+ if (ErrorCode != TD_NO_ERROR) {
+ if (ErrorCode == TD_TOBE_PROCESSED) {
+ DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));
+ } else {
+ DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));
+ }
+ *DataLength = 0;
+ }
+ *DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);
+
+FREE_TD_BUFF:
+ while (HeadTd) {
+ DataTd = HeadTd;
+ HeadTd = HeadTd->NextTDPointer;
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
+ }
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+ return Status;
+}
+/**
+ Retrieves the number of root hub ports.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[out] NumOfPorts The pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubNumOfPorts (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *NumOfPorts
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ if (NumOfPorts == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+ *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);
+
+ return EFI_SUCCESS;
+}
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param PortNumber The root hub port to retrieve the state from.
+ @param PortStatus Variable to receive the port state.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified.
+ by PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ UINT8 NumOfPorts;
+
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+
+ OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);
+ if (PortNumber >= NumOfPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_POWER;
+ }
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;
+ }
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Sets a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI
+ @param PortNumber Root hub port to set.
+ @param PortFeature Feature to set.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciSetRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ EFI_STATUS Status;
+ UINT8 NumOfPorts;
+ UINTN RetryTimes;
+
+ OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);
+ if (PortNumber >= NumOfPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+
+ Status = EFI_SUCCESS;
+
+
+ switch (PortFeature) {
+ case EfiUsbPortPower:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortReset:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||
+ OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);
+ break;
+
+ case EfiUsbPortEnable:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);;
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+
+ case EfiUsbPortSuspend:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);;
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Clears a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciClearRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+{
+ USB_OHCI_HC_DEV *Ohc;
+ EFI_STATUS Status;
+ UINT8 NumOfPorts;
+ UINTN RetryTimes;
+
+
+ OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);
+ if (PortNumber >= NumOfPorts) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);
+
+ Status = EFI_SUCCESS;
+
+ switch (PortFeature) {
+ case EfiUsbPortEnable:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortSuspend:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortReset:
+ break;
+
+ case EfiUsbPortPower:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortConnectChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortResetChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+
+ case EfiUsbPortEnableChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortSuspendChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbPortOverCurrentChange:
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);
+
+ //
+ // Verify the state
+ //
+ RetryTimes = 0;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ RetryTimes++;
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&
+ RetryTimes < MAX_RETRY_TIMES);
+
+ if (RetryTimes >= MAX_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+/**
+ Provides software reset for the USB host controller.
+
+ @param This This EFI_USB_HC_PROTOCOL instance.
+ @param Attributes A bit mask of the reset operation to perform.
+
+ @retval EFI_SUCCESS The reset operation succeeded.
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
+ not currently supported by the host controller.
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+InitializeUsbHC (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT16 Attributes
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT8 NumOfPorts;
+ UINT32 PowerOnGoodTime;
+ UINT32 Data32;
+ BOOLEAN Flag = FALSE;
+
+ if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = EFI_SUCCESS;
+
+ if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {
+ MicroSecondDelay (50 * HC_1_MILLISECOND);
+ Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ MicroSecondDelay (50 * HC_1_MILLISECOND);
+ //
+ // Wait for host controller reset.
+ //
+ PowerOnGoodTime = 50;
+ do {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ Data32 = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS );
+ if ((Data32 & HC_RESET) == 0) {
+ Flag = TRUE;
+ break;
+ }
+ }while(PowerOnGoodTime--);
+ if (!Flag){
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);
+ if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) {
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ MicroSecondDelay (50 * HC_1_MILLISECOND);
+ }
+ //
+ // Initialize host controller operational registers
+ //
+ OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778);
+ OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);
+ OhciSetPeriodicStart (Ohc, 0x2a2f);
+ OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x0);
+ OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0);
+ OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0);
+ OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1);
+ //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);
+ //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);
+
+ OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0);
+ OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff);
+ OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE);
+ OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER);
+ OhciGetRootHubNumOfPorts (PeiServices, &Ohc->UsbHostControllerPpi, &NumOfPorts);
+ for (Index = 0; Index < NumOfPorts; Index++) {
+ if (!EFI_ERROR (OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset))) {
+ MicroSecondDelay (200 * HC_1_MILLISECOND);
+ OhciClearRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset);
+ MicroSecondDelay (HC_1_MILLISECOND);
+ OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortEnable);
+ MicroSecondDelay (HC_1_MILLISECOND);
+ }
+ }
+
+ Ohc->MemPool = UsbHcInitMemPool(TRUE, 0);
+ if(Ohc->MemPool == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);
+ OhciSetHcControl (Ohc, CONTROL_ENABLE | BULK_ENABLE, 1);
+ OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);
+ MicroSecondDelay (50 * HC_1_MILLISECOND);
+ //
+ // Wait till first SOF occurs, and then clear it
+ //
+ while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0);
+ OhciClearInterruptStatus (Ohc, START_OF_FRAME);
+ MicroSecondDelay (HC_1_MILLISECOND);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Submits control transfer to a target USB device.
+
+ Calls underlying OhciControlTransfer to do work. This wrapper routine required
+ on Quark so that USB DMA transfers do not cause an IMR violation.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage.
+ @param Data Data buffer to be transmitted or received from USB device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param TimeOut Indicates the maximum timeout, in millisecond.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+RedirectOhciControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 MaxPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_REQUEST *NewRequest;
+ VOID *NewData;
+ UINT8 *Alloc;
+
+ //
+ // Allocate memory external to IMR protected region for transfer data.
+ //
+ Status = PeiServicesAllocatePool (
+ sizeof(EFI_USB_DEVICE_REQUEST) + *DataLength,
+ (VOID **) &Alloc
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Setup pointers to transfer buffers.
+ //
+ NewRequest = (EFI_USB_DEVICE_REQUEST *) Alloc;
+ Alloc += sizeof(EFI_USB_DEVICE_REQUEST);
+ NewData = (VOID *) Alloc;
+
+ //
+ // Copy callers request packet into transfer request packet.
+ //
+ if (Request != NULL) {
+ CopyMem (NewRequest,Request,sizeof(EFI_USB_DEVICE_REQUEST));
+ } else {
+ NewRequest = NULL;
+ }
+ //
+ // Copy callers data into transfer data buffer.
+ //
+ if (Data != NULL) {
+ if (DataLength > 0) {
+ CopyMem (NewData,Data,*DataLength);
+ }
+ } else {
+ NewData = NULL;
+ }
+
+ //
+ // Call underlying OhciControlTransfer to do work.
+ //
+ Status = OhciControlTransfer (
+ PeiServices,
+ This,
+ DeviceAddress,
+ DeviceSpeed,
+ MaxPacketLength,
+ NewRequest,
+ TransferDirection,
+ NewData,
+ DataLength,
+ TimeOut,
+ TransferResult
+ );
+
+ //
+ // Copy transfer buffer back into callers buffer.
+ //
+ if (Data != NULL && *DataLength > 0) {
+ CopyMem (Data, NewData, *DataLength);
+ }
+
+ return Status;
+}
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ Calls underlying OhciBulkTransfer to do work. This wrapper routine required
+ on Quark so that USB DMA transfers do not cause an IMR violation.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param MaxiPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param Data A pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to use of
+ the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+RedirectOhciBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaxPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *NewData;
+
+ //
+ // Allocate memory external to IMR protected region for transfer data.
+ //
+ Status = PeiServicesAllocatePool (
+ *DataLength,
+ (VOID **) &NewData
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Copy callers data into transfer buffer.
+ //
+ if (Data != NULL) {
+ if (DataLength > 0) {
+ CopyMem (NewData,Data,*DataLength);
+ }
+ } else {
+ NewData = NULL;
+ }
+
+ //
+ // Call underlying OhciBulkTransfer to do work.
+ //
+ Status = OhciBulkTransfer (
+ PeiServices,
+ This,
+ DeviceAddress,
+ EndPointAddress,
+ MaxPacketLength,
+ NewData,
+ DataLength,
+ DataToggle,
+ TimeOut,
+ TransferResult
+ );
+
+ //
+ // Copy transfer buffer back into callers buffer.
+ //
+ if (Data != NULL && *DataLength > 0) {
+ CopyMem (Data, NewData, *DataLength);
+ }
+
+ return Status;
+}
+
+/**
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS PPI successfully installed.
+
+**/
+EFI_STATUS
+OhcPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+
+ PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINTN ControllerType;
+ UINTN BaseAddress;
+ UINTN MemPages;
+ USB_OHCI_HC_DEV *Ohc;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+
+
+ //
+ // Shadow this PEIM to run from memory
+ //
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+ Status = PeiServicesLocatePpi (
+ &gPeiUsbControllerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &ChipSetUsbControllerPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Index = 0;
+ while (TRUE) {
+ Status = ChipSetUsbControllerPpi->GetUsbController (
+ (EFI_PEI_SERVICES **) PeiServices,
+ ChipSetUsbControllerPpi,
+ Index,
+ &ControllerType,
+ &BaseAddress
+ );
+ //
+ // When status is error, meant no controller is found
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // This PEIM is for OHC type controller.
+ //
+ if (ControllerType != PEI_OHCI_CONTROLLER) {
+ Index++;
+ continue;
+ }
+
+ MemPages = sizeof (USB_OHCI_HC_DEV) / PAGESIZE + 1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ MemPages,
+ &TempPtr
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to allocate buffer for the %dth OHCI ControllerPpi\n", Index));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);
+ Ohc = (USB_OHCI_HC_DEV *) ((UINTN) TempPtr);
+
+ Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE;
+
+ Ohc->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
+
+ //
+ // Initialize Uhc's hardware
+ //
+ Status = InitializeUsbHC (
+ (EFI_PEI_SERVICES **)PeiServices,
+ Ohc,
+ EFI_USB_HC_RESET_GLOBAL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to init %dth OHCI ControllerPpi\n", Index));
+ return Status;
+ }
+ //
+ // Control & Bulk transfer services are accessed via their Redirect
+ // routine versions on Quark so that USB DMA transfers do not cause an
+ // IMR violation.
+ //
+ Ohc->UsbHostControllerPpi.ControlTransfer = RedirectOhciControlTransfer;
+ Ohc->UsbHostControllerPpi.BulkTransfer = RedirectOhciBulkTransfer;
+ Ohc->UsbHostControllerPpi.GetRootHubPortNumber = OhciGetRootHubNumOfPorts;
+ Ohc->UsbHostControllerPpi.GetRootHubPortStatus = OhciGetRootHubPortStatus;
+ Ohc->UsbHostControllerPpi.SetRootHubPortFeature = OhciSetRootHubPortFeature;
+ Ohc->UsbHostControllerPpi.ClearRootHubPortFeature = OhciClearRootHubPortFeature;
+
+ Ohc->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ Ohc->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid;
+ Ohc->PpiDescriptor.Ppi = &Ohc->UsbHostControllerPpi;
+
+ Status = PeiServicesInstallPpi (&Ohc->PpiDescriptor);
+ if (EFI_ERROR (Status)) {
+ Index++;
+ continue;
+ }
+ Index++;
+ }
+ return EFI_SUCCESS;
+}
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h
new file mode 100644
index 0000000000..0fd5302c67
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h
@@ -0,0 +1,258 @@
+/** @file
+Provides the definition of Usb Hc Protocol and OHCI controller
+private data structure.
+
+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 _OHCI_PEIM_H
+#define _OHCI_PEIM_H
+
+#include <PiPei.h>
+
+#include <Ppi/UsbController.h>
+#include <Ppi/UsbHostController.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/IoLib.h>
+
+typedef struct _USB_OHCI_HC_DEV USB_OHCI_HC_DEV;
+
+#include "UsbHcMem.h"
+#include "OhciReg.h"
+#include "OhciSched.h"
+#include "OhciUrb.h"
+#include "Descriptor.h"
+
+#define EFI_USB_SPEED_FULL 0x0000
+#define EFI_USB_SPEED_LOW 0x0001
+#define EFI_USB_SPEED_HIGH 0x0002
+
+#define PAGESIZE 4096
+
+#define HC_1_MICROSECOND 1
+#define HC_1_MILLISECOND (1000 * HC_1_MICROSECOND)
+#define HC_1_SECOND (1000 * HC_1_MILLISECOND)
+
+
+#define USB_OHCI_HC_DEV_SIGNATURE SIGNATURE_32('o','h','c','i')
+
+struct _USB_OHCI_HC_DEV {
+ UINTN Signature;
+ PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
+ UINT32 UsbHostControllerBaseAddress;
+ VOID *MemPool;
+};
+
+#define PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS(a) CR (a, USB_OHCI_HC_DEV, UsbHostControllerPpi, USB_OHCI_HC_DEV_SIGNATURE)
+
+//
+// Func List
+//
+
+/**
+ Provides software reset for the USB host controller.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param Attributes A bit mask of the reset operation to perform.
+
+ @retval EFI_SUCCESS The reset operation succeeded.
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
+ not currently supported by the host controller.
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
+
+**/
+EFI_STATUS
+InitializeUsbHC (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT16 Attributes
+ );
+
+/**
+ Submits control transfer to a target USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress The target device address.
+ @param DeviceSpeed Target device speed.
+ @param MaximumPacketLength Maximum packet size the default control transfer
+ endpoint is capable of sending or receiving.
+ @param Request USB device request to send.
+ @param TransferDirection Specifies the data direction for the data stage.
+ @param Data Data buffer to be transmitted or received from USB device.
+ @param DataLength The size (in bytes) of the data buffer.
+ @param TimeOut Indicates the maximum timeout, in millisecond.
+ @param TransferResult Return the result of this control transfer.
+
+ @retval EFI_SUCCESS Transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT Transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 DeviceSpeed,
+ IN UINT8 MaxPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param DeviceAddress Target device address.
+ @param EndPointAddress Endpoint number and its direction in bit 7.
+ @param MaxiPacketLength Maximum packet size the endpoint is capable of
+ sending or receiving.
+ @param Data A pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param DataToggle On input, the initial data toggle for the transfer;
+ On output, it is updated to to next data toggle to use of
+ the subsequent bulk transfer.
+ @param TimeOut Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+ @param TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+OhciBulkTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaxPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+/**
+ Retrieves the number of root hub ports.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] This The pointer to this instance of the
+ PEI_USB_HOST_CONTROLLER_PPI.
+ @param[out] NumOfPorts The pointer to the number of the root hub ports.
+
+ @retval EFI_SUCCESS The port number was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubNumOfPorts (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *NumOfPorts
+ );
+/**
+ Retrieves the current status of a USB root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param PortNumber The root hub port to retrieve the state from.
+ @param PortStatus Variable to receive the port state.
+
+ @retval EFI_SUCCESS The status of the USB root hub port specified.
+ by PortNumber was returned in PortStatus.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciGetRootHubPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ );
+/**
+
+ Sets a feature for the specified root hub port.
+
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be set.
+ @param PortFeature Indicates the feature selector associated
+ with the feature set request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for the
+ USB root hub port specified by PortNumber.
+ @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+**/
+EFI_STATUS
+EFIAPI
+OhciSetRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+/**
+ Clears a feature for the specified root hub port.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
+ @param PortNumber Specifies the root hub port whose feature
+ is requested to be cleared.
+ @param PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared
+ for the USB root hub port specified by PortNumber.
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
+
+**/
+
+EFI_STATUS
+EFIAPI
+OhciClearRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf
new file mode 100644
index 0000000000..d919b1873c
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf
@@ -0,0 +1,62 @@
+## @file
+# OHCI USB Host Controller PEIM
+#
+# 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 = OhciPei
+ FILE_GUID = 332A0926-429B-4624-9211-A36B23DF0389
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = OhcPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ Descriptor.h
+ OhcPeim.c
+ OhcPeim.h
+ OhciSched.c
+ OhciSched.h
+ OhciReg.c
+ OhciReg.h
+ OhciUrb.c
+ OhciUrb.h
+ UsbHcMem.c
+ UsbHcMem.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ IoLib
+ TimerLib
+ BaseMemoryLib
+ PeimEntryPoint
+ PeiServicesLib
+
+[Ppis]
+ gPeiUsbHostControllerPpiGuid # PPI ALWAYS_PRODUCED
+ gPeiUsbControllerPpiGuid # PPI ALWAYS_CONSUMED
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c
new file mode 100644
index 0000000000..b181c3df62
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c
@@ -0,0 +1,1394 @@
+/** @file
+The OHCI register operation 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.
+
+**/
+
+
+#include "OhcPeim.h"
+
+/**
+
+ Get OHCI operational reg value
+
+ @param Ohc UHC private data
+ @param Offset Offset of the operational reg
+
+ @retval Value of the register
+
+**/
+UINT32
+OhciGetOperationalReg (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Offset
+ )
+{
+
+ return MmioRead32 (Ohc->UsbHostControllerBaseAddress + Offset);
+
+}
+/**
+
+ Set OHCI operational reg value
+
+ @param Ohc UHC private data
+ @param Offset Offset of the operational reg
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set to the reg
+
+**/
+
+
+EFI_STATUS
+OhciSetOperationalReg (
+ USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Offset,
+ IN UINT32 *Value
+ )
+{
+ MmioWrite32(Ohc->UsbHostControllerBaseAddress + Offset, *Value);
+ return EFI_SUCCESS;
+}
+/**
+
+ Get HcRevision reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of the register
+
+**/
+
+
+UINT32
+OhciGetHcRevision (
+ USB_OHCI_HC_DEV *Ohc
+ )
+{
+ return OhciGetOperationalReg (Ohc, HC_REVISION);
+}
+/**
+
+ Set HcReset reg value
+
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcReset (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcRESET Reset;
+
+ Status = EFI_SUCCESS;
+ *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR);
+
+ if (Field & RESET_SYSTEM_BUS) {
+ Reset.FSBIR = Value;
+ }
+
+ if (Field & RESET_HOST_CONTROLLER) {
+ Reset.FHR = Value;
+ }
+
+ if (Field & RESET_CLOCK_GENERATION) {
+ Reset.CGR = Value;
+ }
+
+ if (Field & RESET_SSE_GLOBAL) {
+ Reset.SSE = Value;
+ }
+
+ if (Field & RESET_PSPL) {
+ Reset.PSPL = Value;
+ }
+
+ if (Field & RESET_PCPL) {
+ Reset.PCPL = Value;
+ }
+
+ if (Field & RESET_SSEP1) {
+ Reset.SSEP1 = Value;
+ }
+
+ if (Field & RESET_SSEP2) {
+ Reset.SSEP2 = Value;
+ }
+
+ if (Field & RESET_SSEP3) {
+ Reset.SSEP3 = Value;
+ }
+
+ OhciSetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR, (UINT32*)&Reset);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get specific field of HcReset reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcReset (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Field
+ )
+{
+ HcRESET Reset;
+ UINT32 Value;
+
+
+ *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR);
+ Value = 0;
+
+ switch (Field) {
+ case RESET_SYSTEM_BUS:
+ Value = Reset.FSBIR;
+ break;
+
+ case RESET_HOST_CONTROLLER:
+ Value = Reset.FHR;
+ break;
+
+ case RESET_CLOCK_GENERATION:
+ Value = Reset.CGR;
+ break;
+
+ case RESET_SSE_GLOBAL:
+ Value = Reset.SSE;
+ break;
+
+ case RESET_PSPL:
+ Value = Reset.PSPL;
+ break;
+
+ case RESET_PCPL:
+ Value = Reset.PCPL;
+ break;
+
+ case RESET_SSEP1:
+ Value = Reset.SSEP1;
+ break;
+
+ case RESET_SSEP2:
+ Value = Reset.SSEP2;
+ break;
+
+ case RESET_SSEP3:
+ Value = Reset.SSEP3;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+
+ return Value;
+}
+
+/**
+
+ Set HcControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcCONTROL Control;
+
+
+
+ *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL);
+
+ if (Field & CONTROL_BULK_RATIO) {
+ Control.ControlBulkRatio = Value;
+ }
+
+ if (Field & HC_FUNCTIONAL_STATE) {
+ Control.FunctionalState = Value;
+ }
+
+ if (Field & PERIODIC_ENABLE) {
+ Control.PeriodicEnable = Value;
+ }
+
+ if (Field & CONTROL_ENABLE) {
+ Control.ControlEnable = Value;
+ }
+
+ if (Field & ISOCHRONOUS_ENABLE) {
+ Control.IsochronousEnable = Value;
+ }
+
+ if (Field & BULK_ENABLE) {
+ Control.BulkEnable = Value;
+ }
+
+ if (Field & INTERRUPT_ROUTING) {
+ Control.InterruptRouting = Value;
+ }
+
+ Status = OhciSetOperationalReg (Ohc, HC_CONTROL, (UINT32*)&Control);
+
+ return Status;
+}
+
+
+/**
+
+ Get specific field of HcControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+
+UINT32
+OhciGetHcControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcCONTROL Control;
+
+ *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL);
+
+ switch (Field) {
+ case CONTROL_BULK_RATIO:
+ return Control.ControlBulkRatio;
+ break;
+ case PERIODIC_ENABLE:
+ return Control.PeriodicEnable;
+ break;
+ case CONTROL_ENABLE:
+ return Control.ControlEnable;
+ break;
+ case BULK_ENABLE:
+ return Control.BulkEnable;
+ break;
+ case ISOCHRONOUS_ENABLE:
+ return Control.IsochronousEnable;
+ break;
+ case HC_FUNCTIONAL_STATE:
+ return Control.FunctionalState;
+ break;
+ case INTERRUPT_ROUTING:
+ return Control.InterruptRouting;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set HcCommand reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcCommandStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcCOMMAND_STATUS CommandStatus;
+
+ ZeroMem (&CommandStatus, sizeof (HcCOMMAND_STATUS));
+
+ if(Field & HC_RESET){
+ CommandStatus.HcReset = Value;
+ }
+
+ if(Field & CONTROL_LIST_FILLED){
+ CommandStatus.ControlListFilled = Value;
+ }
+
+ if(Field & BULK_LIST_FILLED){
+ CommandStatus.BulkListFilled = Value;
+ }
+
+ if(Field & CHANGE_OWNER_REQUEST){
+ CommandStatus.ChangeOwnerRequest = Value;
+ }
+
+ if(Field & SCHEDULE_OVERRUN_COUNT){
+ CommandStatus.ScheduleOverrunCount = Value;
+ }
+
+ Status = OhciSetOperationalReg (Ohc, HC_COMMAND_STATUS, (UINT32*)&CommandStatus);
+
+ return Status;
+}
+
+/**
+
+ Get specific field of HcCommand reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcCommandStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcCOMMAND_STATUS CommandStatus;
+
+ *(UINT32 *) &CommandStatus = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS);
+
+ switch (Field){
+ case HC_RESET:
+ return CommandStatus.HcReset;
+ break;
+ case CONTROL_LIST_FILLED:
+ return CommandStatus.ControlListFilled;
+ break;
+ case BULK_LIST_FILLED:
+ return CommandStatus.BulkListFilled;
+ break;
+ case CHANGE_OWNER_REQUEST:
+ return CommandStatus.ChangeOwnerRequest;
+ break;
+ case SCHEDULE_OVERRUN_COUNT:
+ return CommandStatus.ScheduleOverrunCount;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Clear specific fields of Interrupt Status
+
+ @param Ohc UHC private data
+ @param Field Field to clear
+
+ @retval EFI_SUCCESS Fields cleared
+
+**/
+
+EFI_STATUS
+OhciClearInterruptStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ EFI_STATUS Status;
+ HcINTERRUPT_STATUS InterruptStatus;
+
+ ZeroMem (&InterruptStatus, sizeof (HcINTERRUPT_STATUS));
+
+ if(Field & SCHEDULE_OVERRUN){
+ InterruptStatus.SchedulingOverrun = 1;
+ }
+
+ if(Field & WRITEBACK_DONE_HEAD){
+ InterruptStatus.WriteBackDone = 1;
+ }
+ if(Field & START_OF_FRAME){
+ InterruptStatus.Sof = 1;
+ }
+
+ if(Field & RESUME_DETECT){
+ InterruptStatus.ResumeDetected = 1;
+ }
+
+ if(Field & UNRECOVERABLE_ERROR){
+ InterruptStatus.UnrecoverableError = 1;
+ }
+
+ if(Field & FRAME_NUMBER_OVERFLOW){
+ InterruptStatus.FrameNumOverflow = 1;
+ }
+
+ if(Field & ROOTHUB_STATUS_CHANGE){
+ InterruptStatus.RHStatusChange = 1;
+ }
+
+ if(Field & OWNERSHIP_CHANGE){
+ InterruptStatus.OwnerChange = 1;
+ }
+
+ Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_STATUS, (UINT32*)&InterruptStatus);
+
+ return Status;
+}
+
+/**
+
+ Get fields of HcInterrupt reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcINTERRUPT_STATUS InterruptStatus;
+
+ *(UINT32 *) &InterruptStatus = OhciGetOperationalReg (Ohc, HC_INTERRUPT_STATUS);
+
+ switch (Field){
+ case SCHEDULE_OVERRUN:
+ return InterruptStatus.SchedulingOverrun;
+ break;
+
+ case WRITEBACK_DONE_HEAD:
+ return InterruptStatus.WriteBackDone;
+ break;
+
+ case START_OF_FRAME:
+ return InterruptStatus.Sof;
+ break;
+
+ case RESUME_DETECT:
+ return InterruptStatus.ResumeDetected;
+ break;
+
+ case UNRECOVERABLE_ERROR:
+ return InterruptStatus.UnrecoverableError;
+ break;
+
+ case FRAME_NUMBER_OVERFLOW:
+ return InterruptStatus.FrameNumOverflow;
+ break;
+
+ case ROOTHUB_STATUS_CHANGE:
+ return InterruptStatus.RHStatusChange;
+ break;
+
+ case OWNERSHIP_CHANGE:
+ return InterruptStatus.OwnerChange;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set Interrupt Control reg value
+
+ @param Ohc UHC private data
+ @param StatEnable Enable or Disable
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetInterruptControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN BOOLEAN StatEnable,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcINTERRUPT_CONTROL InterruptState;
+
+
+ ZeroMem (&InterruptState, sizeof (HcINTERRUPT_CONTROL));
+
+ if(Field & SCHEDULE_OVERRUN) {
+ InterruptState.SchedulingOverrunInt = Value;
+ }
+
+ if(Field & WRITEBACK_DONE_HEAD) {
+ InterruptState.WriteBackDoneInt = Value;
+ }
+ if(Field & START_OF_FRAME) {
+ InterruptState.SofInt = Value;
+ }
+
+ if(Field & RESUME_DETECT) {
+ InterruptState.ResumeDetectedInt = Value;
+ }
+
+ if(Field & UNRECOVERABLE_ERROR) {
+ InterruptState.UnrecoverableErrorInt = Value;
+ }
+
+ if(Field & FRAME_NUMBER_OVERFLOW) {
+ InterruptState.FrameNumOverflowInt = Value;
+ }
+
+ if(Field & ROOTHUB_STATUS_CHANGE) {
+ InterruptState.RHStatusChangeInt = Value;
+ }
+
+ if(Field & OWNERSHIP_CHANGE) {
+ InterruptState.OwnerChangedInt = Value;
+ }
+
+ if(Field & MASTER_INTERRUPT) {
+ InterruptState.MasterInterruptEnable = Value;
+ }
+
+ if (StatEnable) {
+ Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_ENABLE, (UINT32*)&InterruptState);
+ } else {
+ Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_DISABLE, (UINT32*)&InterruptState);
+ }
+
+ return Status;
+}
+
+/**
+
+ Get field of HcInterruptControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcINTERRUPT_CONTROL InterruptState;
+
+ *(UINT32 *) &InterruptState = OhciGetOperationalReg (Ohc, HC_INTERRUPT_ENABLE);
+
+ switch (Field){
+ case SCHEDULE_OVERRUN:
+ return InterruptState.SchedulingOverrunInt;
+ break;
+
+ case WRITEBACK_DONE_HEAD:
+ return InterruptState.WriteBackDoneInt;
+ break;
+
+ case START_OF_FRAME:
+ return InterruptState.SofInt;
+ break;
+
+ case RESUME_DETECT:
+ return InterruptState.ResumeDetectedInt;
+ break;
+
+ case UNRECOVERABLE_ERROR:
+ return InterruptState.UnrecoverableErrorInt;
+ break;
+
+ case FRAME_NUMBER_OVERFLOW:
+ return InterruptState.FrameNumOverflowInt;
+ break;
+
+ case ROOTHUB_STATUS_CHANGE:
+ return InterruptState.RHStatusChangeInt;
+ break;
+
+ case OWNERSHIP_CHANGE:
+ return InterruptState.OwnerChangedInt;
+ break;
+
+ case MASTER_INTERRUPT:
+ return InterruptState.MasterInterruptEnable;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set memory pointer of specific type
+
+ @param Ohc UHC private data
+ @param PointerType Type of the pointer to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Memory pointer set
+
+**/
+
+EFI_STATUS
+OhciSetMemoryPointer(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN PointerType,
+ IN VOID *Value
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Verify;
+
+ Status = OhciSetOperationalReg (Ohc, PointerType, (UINT32*)&Value);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Verify = OhciGetOperationalReg (Ohc, PointerType);
+
+ while (Verify != (UINT32) Value) {
+ MicroSecondDelay (HC_1_MILLISECOND);
+ Verify = OhciGetOperationalReg (Ohc, PointerType);
+ };
+
+
+ return Status;
+}
+
+/**
+
+ Get memory pointer of specific type
+
+ @param Ohc UHC private data
+ @param PointerType Type of pointer
+
+ @retval Memory pointer of the specific type
+
+**/
+
+VOID *
+OhciGetMemoryPointer (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN PointerType
+ )
+{
+
+ return (VOID *) OhciGetOperationalReg (Ohc, PointerType);
+}
+
+
+/**
+
+ Set Frame Interval value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameInterval (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcFRM_INTERVAL FrameInterval;
+
+
+ *(UINT32 *) &FrameInterval = OhciGetOperationalReg(Ohc, HC_FRM_INTERVAL);
+
+ if (Field & FRAME_INTERVAL) {
+ FrameInterval.FrmIntervalToggle = !FrameInterval.FrmIntervalToggle;
+ FrameInterval.FrameInterval = Value;
+ }
+
+ if (Field & FS_LARGEST_DATA_PACKET) {
+ FrameInterval.FSMaxDataPacket = Value;
+ }
+
+ if (Field & FRMINT_TOGGLE) {
+ FrameInterval.FrmIntervalToggle = Value;
+ }
+
+ Status = OhciSetOperationalReg (
+ Ohc,
+ HC_FRM_INTERVAL,
+ (UINT32*)&FrameInterval
+ );
+
+ return Status;
+}
+
+
+/**
+
+ Get field of frame interval reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetFrameInterval (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcFRM_INTERVAL FrameInterval;
+
+ *(UINT32 *) &FrameInterval = OhciGetOperationalReg (Ohc, HC_FRM_INTERVAL);
+
+ switch (Field){
+ case FRAME_INTERVAL:
+ return FrameInterval.FrameInterval;
+ break;
+
+ case FS_LARGEST_DATA_PACKET:
+ return FrameInterval.FSMaxDataPacket;
+ break;
+
+ case FRMINT_TOGGLE:
+ return FrameInterval.FrmIntervalToggle;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set Frame Remaining reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameRemaining (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcFRAME_REMAINING FrameRemaining;
+
+
+ *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING);
+
+ FrameRemaining.FrameRemaining = Value;
+ FrameRemaining.FrameRemainingToggle = !FrameRemaining.FrameRemainingToggle;
+
+ Status = OhciSetOperationalReg (Ohc, HC_FRM_REMAINING, (UINT32*)&FrameRemaining);
+
+ return Status;
+}
+/**
+
+ Get value of frame remaining reg
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of frame remaining reg
+
+**/
+UINT32
+OhciGetFrameRemaining (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+
+{
+ HcFRAME_REMAINING FrameRemaining;
+
+
+ *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING);
+
+ switch (Field){
+ case FRAME_REMAINING:
+ return FrameRemaining.FrameRemaining;
+ break;
+
+ case FRAME_REMAIN_TOGGLE:
+ return FrameRemaining.FrameRemainingToggle;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+/**
+
+ Set frame number reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameNumber(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+ Status = OhciSetOperationalReg (Ohc, HC_FRM_NUMBER, &Value);
+
+ return Status;
+}
+
+/**
+
+ Get frame number reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of frame number reg
+
+**/
+
+UINT32
+OhciGetFrameNumber (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ return OhciGetOperationalReg(Ohc, HC_FRM_NUMBER);
+}
+
+/**
+
+ Set period start reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetPeriodicStart (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+
+ Status = OhciSetOperationalReg (Ohc, HC_PERIODIC_START, &Value);
+
+ return Status;
+}
+
+
+/**
+
+ Get periodic start reg value
+
+ @param Ohc UHC private data
+
+ @param Value of periodic start reg
+
+**/
+
+UINT32
+OhciGetPeriodicStart (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ return OhciGetOperationalReg(Ohc, HC_PERIODIC_START);
+}
+
+
+/**
+
+ Set Ls Threshold reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetLsThreshold (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+
+ Status = OhciSetOperationalReg (Ohc, HC_LS_THREASHOLD, &Value);
+
+ return Status;
+}
+
+
+/**
+
+ Get Ls Threshold reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of Ls Threshold reg
+
+**/
+
+UINT32
+OhciGetLsThreshold (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ return OhciGetOperationalReg(Ohc, HC_LS_THREASHOLD);
+}
+
+/**
+
+ Set Root Hub Descriptor reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetRootHubDescriptor (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+ HcRH_DESC_A DescriptorA;
+ HcRH_DESC_B DescriptorB;
+
+
+ if (Field & (RH_DEV_REMOVABLE || RH_PORT_PWR_CTRL_MASK)) {
+ *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B);
+
+ if(Field & RH_DEV_REMOVABLE) {
+ DescriptorB.DeviceRemovable = Value;
+ }
+ if(Field & RH_PORT_PWR_CTRL_MASK) {
+ DescriptorB.PortPowerControlMask = Value;
+ }
+
+ Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_B, (UINT32*)&DescriptorB);
+
+ return Status;
+ }
+
+ *(UINT32 *)&DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A);
+
+ if(Field & RH_NUM_DS_PORTS) {
+ DescriptorA.NumDownStrmPorts = Value;
+ }
+ if(Field & RH_NO_PSWITCH) {
+ DescriptorA.NoPowerSwitch = Value;
+ }
+ if(Field & RH_PSWITCH_MODE) {
+ DescriptorA.PowerSwitchMode = Value;
+ }
+ if(Field & RH_DEVICE_TYPE) {
+ DescriptorA.DeviceType = Value;
+ }
+ if(Field & RH_OC_PROT_MODE) {
+ DescriptorA.OverCurrentProtMode = Value;
+ }
+ if(Field & RH_NOC_PROT) {
+ DescriptorA.NoOverCurrentProtMode = Value;
+ }
+ if(Field & RH_NO_POTPGT) {
+ DescriptorA.PowerOnToPowerGoodTime = Value;
+ }
+
+ Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_A, (UINT32*)&DescriptorA);
+
+ return Status;
+}
+
+
+/**
+
+ Get Root Hub Descriptor reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubDescriptor (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcRH_DESC_A DescriptorA;
+ HcRH_DESC_B DescriptorB;
+
+
+ *(UINT32 *) &DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A);
+ *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B);
+
+ switch (Field){
+ case RH_DEV_REMOVABLE:
+ return DescriptorB.DeviceRemovable;
+ break;
+
+ case RH_PORT_PWR_CTRL_MASK:
+ return DescriptorB.PortPowerControlMask;
+ break;
+
+ case RH_NUM_DS_PORTS:
+ return DescriptorA.NumDownStrmPorts;
+ break;
+
+ case RH_NO_PSWITCH:
+ return DescriptorA.NoPowerSwitch;
+ break;
+
+ case RH_PSWITCH_MODE:
+ return DescriptorA.PowerSwitchMode;
+ break;
+
+ case RH_DEVICE_TYPE:
+ return DescriptorA.DeviceType;
+ break;
+
+ case RH_OC_PROT_MODE:
+ return DescriptorA.OverCurrentProtMode;
+ break;
+
+ case RH_NOC_PROT:
+ return DescriptorA.NoOverCurrentProtMode;
+ break;
+
+ case RH_NO_POTPGT:
+ return DescriptorA.PowerOnToPowerGoodTime;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+
+/**
+
+ Set Root Hub Status reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ EFI_STATUS Status;
+ HcRH_STATUS RootHubStatus;
+
+
+ ZeroMem (&RootHubStatus, sizeof(HcRH_STATUS));
+
+ if(Field & RH_LOCAL_PSTAT){
+ RootHubStatus.LocalPowerStat = 1;
+ }
+ if(Field & RH_OC_ID){
+ RootHubStatus.OverCurrentIndicator = 1;
+ }
+ if(Field & RH_REMOTE_WK_ENABLE){
+ RootHubStatus.DevRemoteWakeupEnable = 1;
+ }
+ if(Field & RH_LOCAL_PSTAT_CHANGE){
+ RootHubStatus.LocalPowerStatChange = 1;
+ }
+ if(Field & RH_OC_ID_CHANGE){
+ RootHubStatus.OverCurrentIndicatorChange = 1;
+ }
+ if(Field & RH_CLR_RMT_WK_ENABLE){
+ RootHubStatus.ClearRemoteWakeupEnable = 1;
+ }
+
+ Status = OhciSetOperationalReg (Ohc, HC_RH_STATUS, (UINT32*)&RootHubStatus);
+
+ return Status;
+}
+
+
+/**
+
+ Get Root Hub Status reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ )
+{
+ HcRH_STATUS RootHubStatus;
+
+
+ *(UINT32 *) &RootHubStatus = OhciGetOperationalReg (Ohc, HC_RH_STATUS);
+
+ switch (Field) {
+ case RH_LOCAL_PSTAT:
+ return RootHubStatus.LocalPowerStat;
+ break;
+ case RH_OC_ID:
+ return RootHubStatus.OverCurrentIndicator;
+ break;
+ case RH_REMOTE_WK_ENABLE:
+ return RootHubStatus.DevRemoteWakeupEnable;
+ break;
+ case RH_LOCAL_PSTAT_CHANGE:
+ return RootHubStatus.LocalPowerStatChange;
+ break;
+ case RH_OC_ID_CHANGE:
+ return RootHubStatus.OverCurrentIndicatorChange;
+ break;
+ case RH_CLR_RMT_WK_ENABLE:
+ return RootHubStatus.ClearRemoteWakeupEnable;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+
+/**
+
+ Set Root Hub Port Status reg value
+
+ @param Ohc UHC private data
+ @param Index Index of the port
+ @param Field Field to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubPortStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Index,
+ IN UINTN Field
+ )
+{
+ EFI_STATUS Status;
+ HcRHPORT_STATUS PortStatus;
+
+
+ ZeroMem (&PortStatus, sizeof(HcRHPORT_STATUS));
+
+ if (Field & RH_CLEAR_PORT_ENABLE) {
+ PortStatus.CurrentConnectStat = 1;
+ }
+ if (Field & RH_SET_PORT_ENABLE) {
+ PortStatus.EnableStat = 1;
+ }
+ if (Field & RH_SET_PORT_SUSPEND) {
+ PortStatus.SuspendStat = 1;
+ }
+ if (Field & RH_CLEAR_SUSPEND_STATUS) {
+ PortStatus.OCIndicator = 1;
+ }
+ if (Field & RH_SET_PORT_RESET) {
+ PortStatus.ResetStat = 1;
+ }
+ if (Field & RH_SET_PORT_POWER) {
+ PortStatus.PowerStat = 1;
+ }
+ if (Field & RH_CLEAR_PORT_POWER) {
+ PortStatus.LsDeviceAttached = 1;
+ }
+ if (Field & RH_CONNECT_STATUS_CHANGE) {
+ PortStatus.ConnectStatChange = 1;
+ }
+ if (Field & RH_PORT_ENABLE_STAT_CHANGE) {
+ PortStatus.EnableStatChange = 1;
+ }
+ if (Field & RH_PORT_SUSPEND_STAT_CHANGE) {
+ PortStatus.SuspendStatChange = 1;
+ }
+ if (Field & RH_OC_INDICATOR_CHANGE) {
+ PortStatus.OCIndicatorChange = 1;
+ }
+ if (Field & RH_PORT_RESET_STAT_CHANGE ) {
+ PortStatus.ResetStatChange = 1;
+ }
+
+ Status = OhciSetOperationalReg (Ohc, HC_RH_PORT_STATUS + (Index * 4), (UINT32*)&PortStatus);
+
+ return Status;
+}
+
+
+/**
+
+ Get Root Hub Port Status reg value
+
+ @param Ohc UHC private data
+ @param Index Index of the port
+ @param Field Field to get
+
+ @retval Value of the field and index
+
+**/
+
+UINT32
+OhciReadRootHubPortStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Index,
+ IN UINTN Field
+ )
+{
+ HcRHPORT_STATUS PortStatus;
+
+ *(UINT32 *) &PortStatus = OhciGetOperationalReg (
+ Ohc,
+ HC_RH_PORT_STATUS + (Index * 4)
+ );
+
+ switch (Field){
+ case RH_CURR_CONNECT_STAT:
+ return PortStatus.CurrentConnectStat;
+ break;
+ case RH_PORT_ENABLE_STAT:
+ return PortStatus.EnableStat;
+ break;
+ case RH_PORT_SUSPEND_STAT:
+ return PortStatus.SuspendStat;
+ break;
+ case RH_PORT_OC_INDICATOR:
+ return PortStatus.OCIndicator;
+ break;
+ case RH_PORT_RESET_STAT:
+ return PortStatus.ResetStat;
+ break;
+ case RH_PORT_POWER_STAT:
+ return PortStatus.PowerStat;
+ break;
+ case RH_LSDEVICE_ATTACHED:
+ return PortStatus.LsDeviceAttached;
+ break;
+ case RH_CONNECT_STATUS_CHANGE:
+ return PortStatus.ConnectStatChange;
+ break;
+ case RH_PORT_ENABLE_STAT_CHANGE:
+ return PortStatus.EnableStatChange;
+ break;
+ case RH_PORT_SUSPEND_STAT_CHANGE:
+ return PortStatus.SuspendStatChange;
+ break;
+ case RH_OC_INDICATOR_CHANGE:
+ return PortStatus.OCIndicatorChange;
+ break;
+ case RH_PORT_RESET_STAT_CHANGE:
+ return PortStatus.ResetStatChange;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h
new file mode 100644
index 0000000000..0f1d033d40
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h
@@ -0,0 +1,881 @@
+/** @file
+This file contains the definination for host controller
+register operation 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 _OHCI_REGS_H
+#define _OHCI_REGS_H
+
+#define HC_STATE_RESET 0x0
+#define HC_STATE_RESUME 0x1
+#define HC_STATE_OPERATIONAL 0x2
+#define HC_STATE_SUSPEND 0x3
+
+#define PERIODIC_ENABLE 0x01
+#define ISOCHRONOUS_ENABLE 0x02
+#define CONTROL_ENABLE 0x04
+#define BULK_ENABLE 0x08
+#define CONTROL_BULK_RATIO 0x10
+
+#define HC_FUNCTIONAL_STATE 0x20
+#define INTERRUPT_ROUTING 0x40
+
+#define HC_RESET 0x01
+#define CONTROL_LIST_FILLED 0x02
+#define BULK_LIST_FILLED 0x04
+#define CHANGE_OWNER_REQUEST 0x08
+
+#define SCHEDULE_OVERRUN_COUNT 0x10
+
+#define SCHEDULE_OVERRUN 0x00001
+#define WRITEBACK_DONE_HEAD 0x00002
+#define START_OF_FRAME 0x00004
+#define RESUME_DETECT 0x00008
+#define UNRECOVERABLE_ERROR 0x00010
+#define FRAME_NUMBER_OVERFLOW 0x00020
+#define ROOTHUB_STATUS_CHANGE 0x00040
+#define OWNERSHIP_CHANGE 0x00080
+
+#define MASTER_INTERRUPT 0x00400
+
+#define CONTROL_HEAD 0x001
+#define BULK_HEAD 0x002
+#define DONE_HEAD 0x004
+
+#define Hc_HCCA 0x001
+#define Hc_PERIODIC_CURRENT 0x002
+#define Hc_CONTOL_HEAD 0x004
+#define Hc_CONTROL_CURRENT_PTR 0x008
+#define Hc_BULK_HEAD 0x010
+#define Hc_BULK_CURRENT_PTR 0x020
+#define Hc_DONE_HEAD 0x040
+
+#define FRAME_INTERVAL 0x008
+#define FS_LARGEST_DATA_PACKET 0x010
+#define FRMINT_TOGGLE 0x020
+#define FRAME_REMAINING 0x040
+#define FRAME_REMAIN_TOGGLE 0x080
+
+#define RH_DESC_A 0x00001
+#define RH_DESC_B 0x00002
+#define RH_NUM_DS_PORTS 0x00004
+#define RH_NO_PSWITCH 0x00008
+#define RH_PSWITCH_MODE 0x00010
+#define RH_DEVICE_TYPE 0x00020
+#define RH_OC_PROT_MODE 0x00040
+#define RH_NOC_PROT 0x00080
+#define RH_POTPGT 0x00100
+#define RH_NO_POTPGT 0x00200
+#define RH_DEV_REMOVABLE 0x00400
+#define RH_PORT_PWR_CTRL_MASK 0x00800
+
+#define RH_LOCAL_PSTAT 0x00001
+#define RH_OC_ID 0x00002
+#define RH_REMOTE_WK_ENABLE 0x00004
+#define RH_LOCAL_PSTAT_CHANGE 0x00008
+#define RH_OC_ID_CHANGE 0x00010
+#define RH_CLR_RMT_WK_ENABLE 0x00020
+
+#define RH_CLEAR_PORT_ENABLE 0x0001
+#define RH_SET_PORT_ENABLE 0x0002
+#define RH_SET_PORT_SUSPEND 0x0004
+#define RH_CLEAR_SUSPEND_STATUS 0x0008
+#define RH_SET_PORT_RESET 0x0010
+#define RH_SET_PORT_POWER 0x0020
+#define RH_CLEAR_PORT_POWER 0x0040
+#define RH_CONNECT_STATUS_CHANGE 0x10000
+#define RH_PORT_ENABLE_STAT_CHANGE 0x20000
+#define RH_PORT_SUSPEND_STAT_CHANGE 0x40000
+#define RH_OC_INDICATOR_CHANGE 0x80000
+#define RH_PORT_RESET_STAT_CHANGE 0x100000
+
+#define RH_CURR_CONNECT_STAT 0x0001
+#define RH_PORT_ENABLE_STAT 0x0002
+#define RH_PORT_SUSPEND_STAT 0x0004
+#define RH_PORT_OC_INDICATOR 0x0008
+#define RH_PORT_RESET_STAT 0x0010
+#define RH_PORT_POWER_STAT 0x0020
+#define RH_LSDEVICE_ATTACHED 0x0040
+
+#define RESET_SYSTEM_BUS (1 << 0)
+#define RESET_HOST_CONTROLLER (1 << 1)
+#define RESET_CLOCK_GENERATION (1 << 2)
+#define RESET_SSE_GLOBAL (1 << 5)
+#define RESET_PSPL (1 << 6)
+#define RESET_PCPL (1 << 7)
+#define RESET_SSEP1 (1 << 9)
+#define RESET_SSEP2 (1 << 10)
+#define RESET_SSEP3 (1 << 11)
+
+#define ONE_SECOND 1000000
+#define ONE_MILLI_SEC 1000
+#define MAX_BYTES_PER_TD 0x1000
+#define MAX_RETRY_TIMES 100
+#define PORT_NUMBER_ON_MAINSTONE2 1
+
+
+//
+// Operational Register Offsets
+//
+
+//
+// Command & Status Registers Offsets
+//
+#define HC_REVISION 0x00
+#define HC_CONTROL 0x04
+#define HC_COMMAND_STATUS 0x08
+#define HC_INTERRUPT_STATUS 0x0C
+#define HC_INTERRUPT_ENABLE 0x10
+#define HC_INTERRUPT_DISABLE 0x14
+
+//
+// Memory Pointer Offsets
+//
+#define HC_HCCA 0x18
+#define HC_PERIODIC_CURRENT 0x1C
+#define HC_CONTROL_HEAD 0x20
+#define HC_CONTROL_CURRENT_PTR 0x24
+#define HC_BULK_HEAD 0x28
+#define HC_BULK_CURRENT_PTR 0x2C
+#define HC_DONE_HEAD 0x30
+
+//
+// Frame Register Offsets
+//
+#define HC_FRM_INTERVAL 0x34
+#define HC_FRM_REMAINING 0x38
+#define HC_FRM_NUMBER 0x3C
+#define HC_PERIODIC_START 0x40
+#define HC_LS_THREASHOLD 0x44
+
+//
+// Root Hub Register Offsets
+//
+#define HC_RH_DESC_A 0x48
+#define HC_RH_DESC_B 0x4C
+#define HC_RH_STATUS 0x50
+#define HC_RH_PORT_STATUS 0x54
+
+#define USBHOST_OFFSET_UHCHR 0x64 // Usb Host reset register
+
+#define OHC_BAR_INDEX 0
+
+//
+// Usb Host controller register offset
+//
+#define USBHOST_OFFSET_UHCREV 0x0 // Usb Host revision register
+#define USBHOST_OFFSET_UHCHCON 0x4 // Usb Host control register
+#define USBHOST_OFFSET_UHCCOMS 0x8 // Usb Host Command Status register
+#define USBHOST_OFFSET_UHCINTS 0xC // Usb Host Interrupt Status register
+#define USBHOST_OFFSET_UHCINTE 0x10 // Usb Host Interrupt Enable register
+#define USBHOST_OFFSET_UHCINTD 0x14 // Usb Host Interrupt Disable register
+#define USBHOST_OFFSET_UHCHCCA 0x18 // Usb Host Controller Communication Area
+#define USBHOST_OFFSET_UHCPCED 0x1C // Usb Host Period Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCCHED 0x20 // Usb Host Control Head Endpoint Descriptor
+#define USBHOST_OFFSET_UHCCCED 0x24 // Usb Host Control Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCBHED 0x28 // Usb Host Bulk Head Endpoint Descriptor
+#define USBHOST_OFFSET_UHCBCED 0x2C // Usb Host Bulk Current Endpoint Descriptor
+#define USBHOST_OFFSET_UHCDHEAD 0x30 // Usb Host Done Head register
+#define USBHOST_OFFSET_UHCFMI 0x34 // Usb Host Frame Interval register
+#define USBHOST_OFFSET_UHCFMR 0x38 // Usb Host Frame Remaining register
+#define USBHOST_OFFSET_UHCFMN 0x3C // Usb Host Frame Number register
+#define USBHOST_OFFSET_UHCPERS 0x40 // Usb Host Periodic Start register
+#define USBHOST_OFFSET_UHCLST 0x44 // Usb Host Low-Speed Threshold register
+#define USBHOST_OFFSET_UHCRHDA 0x48 // Usb Host Root Hub Descriptor A register
+#define USBHOST_OFFSET_UHCRHDB 0x4C // Usb Host Root Hub Descriptor B register
+#define USBHOST_OFFSET_UHCRHS 0x50 // Usb Host Root Hub Status register
+#define USBHOST_OFFSET_UHCRHPS1 0x54 // Usb Host Root Hub Port Status 1 register
+
+//
+// Usb Host controller register bit fields
+//
+#pragma pack(1)
+
+typedef struct {
+ UINT8 ProgInterface;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+} USB_CLASSC;
+
+typedef struct {
+ UINT32 Revision:8;
+ UINT32 Rsvd:24;
+} HcREVISION;
+
+typedef struct {
+ UINT32 ControlBulkRatio:2;
+ UINT32 PeriodicEnable:1;
+ UINT32 IsochronousEnable:1;
+ UINT32 ControlEnable:1;
+ UINT32 BulkEnable:1;
+ UINT32 FunctionalState:2;
+ UINT32 InterruptRouting:1;
+ UINT32 RemoteWakeup:1;
+ UINT32 RemoteWakeupEnable:1;
+ UINT32 Reserved:21;
+} HcCONTROL;
+
+typedef struct {
+ UINT32 HcReset:1;
+ UINT32 ControlListFilled:1;
+ UINT32 BulkListFilled:1;
+ UINT32 ChangeOwnerRequest:1;
+ UINT32 Reserved1:12;
+ UINT32 ScheduleOverrunCount:2;
+ UINT32 Reserved:14;
+} HcCOMMAND_STATUS;
+
+typedef struct {
+ UINT32 SchedulingOverrun:1;
+ UINT32 WriteBackDone:1;
+ UINT32 Sof:1;
+ UINT32 ResumeDetected:1;
+ UINT32 UnrecoverableError:1;
+ UINT32 FrameNumOverflow:1;
+ UINT32 RHStatusChange:1;
+ UINT32 Reserved1:23;
+ UINT32 OwnerChange:1;
+ UINT32 Reserved2:1;
+} HcINTERRUPT_STATUS;
+
+typedef struct {
+ UINT32 SchedulingOverrunInt:1;
+ UINT32 WriteBackDoneInt:1;
+ UINT32 SofInt:1;
+ UINT32 ResumeDetectedInt:1;
+ UINT32 UnrecoverableErrorInt:1;
+ UINT32 FrameNumOverflowInt:1;
+ UINT32 RHStatusChangeInt:1;
+ UINT32 Reserved:23;
+ UINT32 OwnerChangedInt:1;
+ UINT32 MasterInterruptEnable:1;
+} HcINTERRUPT_CONTROL;
+
+typedef struct {
+ UINT32 Rerserved:8;
+ UINT32 Hcca:24;
+} HcHCCA;
+
+typedef struct {
+ UINT32 Reserved:4;
+ UINT32 MemoryPtr:28;
+} HcMEMORY_PTR;
+
+typedef struct {
+ UINT32 FrameInterval:14;
+ UINT32 Reserved:2;
+ UINT32 FSMaxDataPacket:15;
+ UINT32 FrmIntervalToggle:1;
+} HcFRM_INTERVAL;
+
+typedef struct {
+ UINT32 FrameRemaining:14;
+ UINT32 Reserved:17;
+ UINT32 FrameRemainingToggle:1;
+} HcFRAME_REMAINING;
+
+typedef struct {
+ UINT32 FrameNumber:16;
+ UINT32 Reserved:16;
+} HcFRAME_NUMBER;
+
+typedef struct {
+ UINT32 PeriodicStart:14;
+ UINT32 Reserved:18;
+} HcPERIODIC_START;
+
+typedef struct {
+ UINT32 LsThreshold:12;
+ UINT32 Reserved:20;
+} HcLS_THRESHOLD;
+
+typedef struct {
+ UINT32 NumDownStrmPorts:8;
+ UINT32 PowerSwitchMode:1;
+ UINT32 NoPowerSwitch:1;
+ UINT32 DeviceType:1;
+ UINT32 OverCurrentProtMode:1;
+ UINT32 NoOverCurrentProtMode:1;
+ UINT32 Reserved:11;
+ UINT32 PowerOnToPowerGoodTime:8;
+} HcRH_DESC_A;
+
+typedef struct {
+ UINT32 DeviceRemovable:16;
+ UINT32 PortPowerControlMask:16;
+} HcRH_DESC_B;
+
+typedef struct {
+ UINT32 LocalPowerStat:1;
+ UINT32 OverCurrentIndicator:1;
+ UINT32 Reserved1:13;
+ UINT32 DevRemoteWakeupEnable:1;
+ UINT32 LocalPowerStatChange:1;
+ UINT32 OverCurrentIndicatorChange:1;
+ UINT32 Reserved2:13;
+ UINT32 ClearRemoteWakeupEnable:1;
+} HcRH_STATUS;
+
+typedef struct {
+ UINT32 CurrentConnectStat:1;
+ UINT32 EnableStat:1;
+ UINT32 SuspendStat:1;
+ UINT32 OCIndicator:1;
+ UINT32 ResetStat:1;
+ UINT32 Reserved1:3;
+ UINT32 PowerStat:1;
+ UINT32 LsDeviceAttached:1;
+ UINT32 Reserved2:6;
+ UINT32 ConnectStatChange:1;
+ UINT32 EnableStatChange:1;
+ UINT32 SuspendStatChange:1;
+ UINT32 OCIndicatorChange:1;
+ UINT32 ResetStatChange:1;
+ UINT32 Reserved3:11;
+} HcRHPORT_STATUS;
+
+typedef struct {
+ UINT32 FSBIR:1;
+ UINT32 FHR:1;
+ UINT32 CGR:1;
+ UINT32 SSDC:1;
+ UINT32 UIT:1;
+ UINT32 SSE:1;
+ UINT32 PSPL:1;
+ UINT32 PCPL:1;
+ UINT32 Reserved0:1;
+ UINT32 SSEP1:1;
+ UINT32 SSEP2:1;
+ UINT32 SSEP3:1;
+ UINT32 Reserved1:20;
+} HcRESET;
+
+#pragma pack()
+
+//
+// Func List
+//
+/**
+
+ Get OHCI operational reg value
+
+ @param Ohc UHC private data
+ @param Offset Offset of the operational reg
+
+ @retval Value of the register
+
+**/
+UINT32
+OhciGetOperationalReg (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Offset
+ );
+/**
+
+ Set OHCI operational reg value
+
+ @param Ohc UHC private data
+ @param Offset Offset of the operational reg
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set to the reg
+
+**/
+EFI_STATUS
+OhciSetOperationalReg (
+ USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Offset,
+ IN UINT32 *Value
+ );
+/**
+
+ Get HcRevision reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of the register
+
+**/
+
+
+UINT32
+OhciGetHcRevision (
+ USB_OHCI_HC_DEV *Ohc
+ );
+
+/**
+
+ Set HcReset reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcReset (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Field,
+ IN UINT32 Value
+ );
+/**
+
+ Get specific field of HcReset reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcReset (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Field
+ );
+/**
+
+ Set HcControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+/**
+
+ Get specific field of HcControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+
+UINT32
+OhciGetHcControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Set HcCommand reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetHcCommandStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+/**
+
+ Get specific field of HcCommand reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcCommandStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Clear specific fields of Interrupt Status
+
+ @param Ohc UHC private data
+ @param Field Field to clear
+
+ @retval EFI_SUCCESS Fields cleared
+
+**/
+
+EFI_STATUS
+OhciClearInterruptStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Get fields of HcInterrupt reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Set Interrupt Control reg value
+
+ @param Ohc UHC private data
+ @param StatEnable Enable or Disable
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetInterruptControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN BOOLEAN StatEnable,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+/**
+
+ Get field of HcInterruptControl reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetHcInterruptControl (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Set memory pointer of specific type
+
+ @param Ohc UHC private data
+ @param PointerType Type of the pointer to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Memory pointer set
+
+**/
+
+EFI_STATUS
+OhciSetMemoryPointer(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN PointerType,
+ IN VOID *Value
+ );
+/**
+
+ Get memory pointer of specific type
+
+ @param Ohc UHC private data
+ @param PointerType Type of pointer
+
+ @retval Memory pointer of the specific type
+
+**/
+
+VOID *
+OhciGetMemoryPointer (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN PointerType
+ );
+/**
+
+ Set Frame Interval value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameInterval (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+/**
+
+ Get field of frame interval reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetFrameInterval (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Set Frame Remaining reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameRemaining (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ );
+/**
+
+ Get value of frame remaining reg
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of frame remaining reg
+
+**/
+UINT32
+OhciGetFrameRemaining (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Set frame number reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetFrameNumber(
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ );
+/**
+
+ Get frame number reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of frame number reg
+
+**/
+
+UINT32
+OhciGetFrameNumber (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+/**
+
+ Set period start reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetPeriodicStart (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ );
+/**
+
+ Get periodic start reg value
+
+ @param Ohc UHC private data
+
+ @param Value of periodic start reg
+
+**/
+
+UINT32
+OhciGetPeriodicStart (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+/**
+
+ Set Ls Threshold reg value
+
+ @param Ohc UHC private data
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetLsThreshold (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Value
+ );
+/**
+
+ Get Ls Threshold reg value
+
+ @param Ohc UHC private data
+
+ @retval Value of Ls Threshold reg
+
+**/
+
+UINT32
+OhciGetLsThreshold (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+/**
+
+ Set Root Hub Descriptor reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+ @param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetRootHubDescriptor (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field,
+ IN UINT32 Value
+ );
+/**
+
+ Get Root Hub Descriptor reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubDescriptor (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Set Root Hub Status reg value
+
+ @param Ohc UHC private data
+ @param Field Field to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Get Root Hub Status reg value
+
+ @param Ohc UHC private data
+ @param Field Field to get
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetRootHubStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINTN Field
+ );
+/**
+
+ Set Root Hub Port Status reg value
+
+ @param Ohc UHC private data
+ @param Index Index of the port
+ @param Field Field to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+
+EFI_STATUS
+OhciSetRootHubPortStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Index,
+ IN UINTN Field
+ );
+/**
+
+ Get Root Hub Port Status reg value
+
+ @param Ohc UHC private data
+ @param Index Index of the port
+ @param Field Field to get
+
+ @retval Value of the field and index
+
+**/
+
+UINT32
+OhciReadRootHubPortStatus (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN UINT32 Index,
+ IN UINTN Field
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c
new file mode 100644
index 0000000000..49f13b66ba
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c
@@ -0,0 +1,229 @@
+/** @file
+OHCI transfer scheduling 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.
+
+**/
+
+
+#include "OhcPeim.h"
+
+/**
+
+ Convert Error code from OHCI format to EFI format
+
+ @Param ErrorCode ErrorCode in OHCI format
+
+ @retval ErrorCode in EFI format
+
+**/
+UINT32
+ConvertErrorCode (
+ IN UINT32 ErrorCode
+ )
+{
+ UINT32 TransferResult;
+
+ switch (ErrorCode) {
+ case TD_NO_ERROR:
+ TransferResult = EFI_USB_NOERROR;
+ break;
+
+ case TD_TOBE_PROCESSED:
+ case TD_TOBE_PROCESSED_2:
+ TransferResult = EFI_USB_ERR_NOTEXECUTE;
+ break;
+
+ case TD_DEVICE_STALL:
+ TransferResult = EFI_USB_ERR_STALL;
+ break;
+
+ case TD_BUFFER_OVERRUN:
+ case TD_BUFFER_UNDERRUN:
+ TransferResult = EFI_USB_ERR_BUFFER;
+ break;
+
+ case TD_CRC_ERROR:
+ TransferResult = EFI_USB_ERR_CRC;
+ break;
+
+ case TD_NO_RESPONSE:
+ TransferResult = EFI_USB_ERR_TIMEOUT;
+ break;
+
+ case TD_BITSTUFFING_ERROR:
+ TransferResult = EFI_USB_ERR_BITSTUFF;
+ break;
+
+ default:
+ TransferResult = EFI_USB_ERR_SYSTEM;
+ }
+
+ return TransferResult;
+}
+
+
+/**
+
+ Check TDs Results
+
+ @Param Ohc UHC private data
+ @Param Td TD_DESCRIPTOR
+ @Param Result Result to return
+
+ @retval TRUE means OK
+ @retval FLASE means Error or Short packet
+
+**/
+BOOLEAN
+OhciCheckTDsResults (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN TD_DESCRIPTOR *Td,
+ OUT UINT32 *Result
+ )
+{
+ UINT32 TdCompletionCode;
+
+ *Result = EFI_USB_NOERROR;
+
+ while (Td) {
+ TdCompletionCode = Td->Word0.ConditionCode;
+
+ *Result |= ConvertErrorCode(TdCompletionCode);
+ //
+ // if any error encountered, stop processing the left TDs.
+ //
+ if (*Result) {
+ return FALSE;
+ }
+
+ Td = Td->NextTDPointer;
+ }
+ return TRUE;
+
+}
+
+
+/**
+
+ Check the task status on an ED
+
+ @Param Ed Pointer to the ED task that TD hooked on
+ @Param HeadTd TD header for current transaction
+
+ @retval Task Status Code
+
+**/
+
+UINT32
+CheckEDStatus (
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd
+ )
+{
+ while(HeadTd != NULL) {
+ if (HeadTd->Word0.ConditionCode != 0) {
+ return HeadTd->Word0.ConditionCode;
+ }
+ HeadTd = HeadTd->NextTDPointer;
+ }
+
+ if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) {
+ return TD_TOBE_PROCESSED;
+ }
+
+ return TD_NO_ERROR;
+}
+
+/**
+
+ Check the task status
+
+ @Param Ohc UHC private data
+ @Param ListType Pipe type
+ @Param Ed Pointer to the ED task hooked on
+ @Param HeadTd Head of TD corresponding to the task
+ @Param ErrorCode return the ErrorCode
+
+ @retval EFI_SUCCESS Task done
+ @retval EFI_NOT_READY Task on processing
+ @retval EFI_DEVICE_ERROR Some error occured
+
+**/
+EFI_STATUS
+CheckIfDone (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN DESCRIPTOR_LIST_TYPE ListType,
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd,
+ OUT UINT32 *ErrorCode
+ )
+{
+ *ErrorCode = TD_TOBE_PROCESSED;
+
+ switch (ListType) {
+ case CONTROL_LIST:
+ if (OhciGetHcCommandStatus (Ohc, CONTROL_LIST_FILLED) != 0) {
+ return EFI_NOT_READY;
+ }
+ break;
+
+ case BULK_LIST:
+ if (OhciGetHcCommandStatus (Ohc, BULK_LIST_FILLED) != 0) {
+ return EFI_NOT_READY;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ *ErrorCode = CheckEDStatus (Ed, HeadTd);
+
+
+ if (*ErrorCode == TD_NO_ERROR) {
+ return EFI_SUCCESS;
+ } else if (*ErrorCode == TD_TOBE_PROCESSED) {
+ return EFI_NOT_READY;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+
+/**
+
+ Convert TD condition code to Efi Status
+
+ @Param ConditionCode Condition code to convert
+
+ @retval EFI_SUCCESS No error occured
+ @retval EFI_NOT_READY TD still on processing
+ @retval EFI_DEVICE_ERROR Error occured in processing TD
+
+**/
+
+EFI_STATUS
+OhciTDConditionCodeToStatus (
+ IN UINT32 ConditionCode
+ )
+{
+ if (ConditionCode == TD_NO_ERROR) {
+ return EFI_SUCCESS;
+ }
+
+ if (ConditionCode == TD_TOBE_PROCESSED) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h
new file mode 100644
index 0000000000..2fc35f6e62
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h
@@ -0,0 +1,114 @@
+/** @file
+This file contains the definination for host controller schedule 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 _OHCI_SCHED_H
+#define _OHCI_SCHED_H
+
+#include "Descriptor.h"
+
+#define HCCA_MEM_SIZE 256
+#define GRID_SIZE 16
+#define GRID_SHIFT 4
+
+/**
+
+ Convert Error code from OHCI format to EFI format
+
+ @Param ErrorCode ErrorCode in OHCI format
+
+ @retval ErrorCode in EFI format
+
+**/
+UINT32
+ConvertErrorCode (
+ IN UINT32 ErrorCode
+ );
+/**
+
+ Check TDs Results
+
+ @Param Ohc UHC private data
+ @Param Td TD_DESCRIPTOR
+ @Param Result Result to return
+
+ @retval TRUE means OK
+ @retval FLASE means Error or Short packet
+
+**/
+BOOLEAN
+OhciCheckTDsResults (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN TD_DESCRIPTOR *Td,
+ OUT UINT32 *Result
+ );
+/**
+
+ Check the task status on an ED
+
+ @Param Ed Pointer to the ED task that TD hooked on
+ @Param HeadTd TD header for current transaction
+
+ @retval Task Status Code
+
+**/
+
+UINT32
+CheckEDStatus (
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd
+ );
+/**
+
+ Check the task status
+
+ @Param Ohc UHC private data
+ @Param ListType Pipe type
+ @Param Ed Pointer to the ED task hooked on
+ @Param HeadTd Head of TD corresponding to the task
+ @Param ErrorCode return the ErrorCode
+
+ @retval EFI_SUCCESS Task done
+ @retval EFI_NOT_READY Task on processing
+ @retval EFI_DEVICE_ERROR Some error occured
+
+**/
+EFI_STATUS
+CheckIfDone (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN DESCRIPTOR_LIST_TYPE ListType,
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd,
+ OUT UINT32 *ErrorCode
+ );
+/**
+
+ Convert TD condition code to Efi Status
+
+ @Param ConditionCode Condition code to convert
+
+ @retval EFI_SUCCESS No error occured
+ @retval EFI_NOT_READY TD still on processing
+ @retval EFI_DEVICE_ERROR Error occured in processing TD
+
+**/
+
+EFI_STATUS
+OhciTDConditionCodeToStatus (
+ IN UINT32 ConditionCode
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c
new file mode 100644
index 0000000000..09ccb983ce
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c
@@ -0,0 +1,566 @@
+/** @file
+This file contains URB request, each request is warpped in a
+URB (Usb Request Block).
+
+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 "OhcPeim.h"
+
+
+/**
+
+ Create a TD
+
+ @Param Ohc UHC private data
+
+ @retval TD structure pointer
+
+**/
+TD_DESCRIPTOR *
+OhciCreateTD (
+ IN USB_OHCI_HC_DEV *Ohc
+ )
+{
+ TD_DESCRIPTOR *Td;
+
+ Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR));
+ if (Td == NULL) {
+ return NULL;
+ }
+ Td->CurrBufferPointer = NULL;
+ Td->NextTD = NULL;
+ Td->BufferEndPointer = NULL;
+ Td->NextTDPointer = NULL;
+
+ return Td;
+}
+
+
+/**
+
+ Free a TD
+
+ @Param Ohc UHC private data
+ @Param Td Pointer to a TD to free
+
+ @retval EFI_SUCCESS TD freed
+
+**/
+EFI_STATUS
+OhciFreeTD (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN TD_DESCRIPTOR *Td
+ )
+{
+ if (Td == NULL) {
+ return EFI_SUCCESS;
+ }
+ UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Create a ED
+
+ @Param Ohc Device private data
+
+ @retval ED descriptor pointer
+
+**/
+ED_DESCRIPTOR *
+OhciCreateED (
+ USB_OHCI_HC_DEV *Ohc
+ )
+{
+ ED_DESCRIPTOR *Ed;
+ Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR));
+ if (Ed == NULL) {
+ return NULL;
+ }
+ Ed->Word0.Skip = 1;
+ Ed->TdTailPointer = NULL;
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) NULL);
+ Ed->NextED = NULL;
+
+ return Ed;
+}
+
+/**
+
+ Free a ED
+
+ @Param Ohc UHC private data
+ @Param Ed Pointer to a ED to free
+
+ @retval EFI_SUCCESS ED freed
+
+**/
+
+EFI_STATUS
+OhciFreeED (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *Ed
+ )
+{
+ if (Ed == NULL) {
+ return EFI_SUCCESS;
+ }
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Free ED
+
+ @Param Ohc Device private data
+ @Param Ed Pointer to a ED to free
+
+ @retval EFI_SUCCESS ED freed
+
+**/
+EFI_STATUS
+OhciFreeAllTDFromED (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *Ed
+ )
+{
+ TD_DESCRIPTOR *HeadTd;
+ TD_DESCRIPTOR *TailTd;
+ TD_DESCRIPTOR *Td;
+ TD_DESCRIPTOR *TempTd;
+
+ if (Ed == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ HeadTd = TD_PTR (Ed->Word2.TdHeadPointer);
+ TailTd = Ed->TdTailPointer;
+
+ Td = HeadTd;
+ while (Td != TailTd) {
+ TempTd = Td;
+ Td = Td->NextTDPointer;
+ OhciFreeTD (Ohc, TempTd);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Attach an ED
+
+ @Param Ed Ed to be attached
+ @Param NewEd Ed to attach
+
+ @retval EFI_SUCCESS NewEd attached to Ed
+ @retval EFI_INVALID_PARAMETER Ed is NULL
+
+**/
+EFI_STATUS
+OhciAttachED (
+ IN ED_DESCRIPTOR *Ed,
+ IN ED_DESCRIPTOR *NewEd
+ )
+{
+ ED_DESCRIPTOR *Temp;
+
+ if (Ed == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Ed->NextED == NULL){
+ Ed->NextED = NewEd;
+ } else {
+ Temp = Ed->NextED;
+ Ed->NextED = NewEd;
+ NewEd->NextED = Temp;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+
+ Attach an ED to an ED list
+
+ @Param OHC UHC private data
+ @Param ListType Type of the ED list
+ @Param Ed ED to attach
+ @Param EdList ED list to be attached
+
+ @retval EFI_SUCCESS ED attached to ED list
+
+**/
+EFI_STATUS
+OhciAttachEDToList (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN DESCRIPTOR_LIST_TYPE ListType,
+ IN ED_DESCRIPTOR *Ed,
+ IN ED_DESCRIPTOR *EdList
+ )
+{
+ ED_DESCRIPTOR *HeadEd;
+
+ switch(ListType) {
+ case CONTROL_LIST:
+ HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD);
+ if (HeadEd == NULL) {
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed);
+ } else {
+ OhciAttachED (HeadEd, Ed);
+ }
+ break;
+
+ case BULK_LIST:
+ HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD);
+ if (HeadEd == NULL) {
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed);
+ } else {
+ OhciAttachED (HeadEd, Ed);
+ }
+ break;
+
+ case INTERRUPT_LIST:
+ OhciAttachED (EdList, Ed);
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+
+ Link Td2 to the end of Td1
+
+ @Param Td1 TD to be linked
+ @Param Td2 TD to link
+
+ @retval EFI_SUCCESS TD successfully linked
+ @retval EFI_INVALID_PARAMETER Td1 is NULL
+
+**/
+EFI_STATUS
+OhciLinkTD (
+ IN TD_DESCRIPTOR *Td1,
+ IN TD_DESCRIPTOR *Td2
+ )
+{
+ TD_DESCRIPTOR *TempTd;
+
+ if (Td1 == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Td1 == Td2) {
+ return EFI_SUCCESS;
+ }
+
+ TempTd = Td1;
+ while (TempTd->NextTD != NULL) {
+ TempTd = TempTd->NextTD;
+ }
+
+ TempTd->NextTD = Td2;
+ TempTd->NextTDPointer = Td2;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Attach TD list to ED
+
+ @Param Ed ED which TD list attach on
+ @Param HeadTd Head of the TD list to attach
+
+ @retval EFI_SUCCESS TD list attached on the ED
+
+**/
+EFI_STATUS
+OhciAttachTDListToED (
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd
+ )
+{
+ TD_DESCRIPTOR *TempTd;
+
+ TempTd = TD_PTR (Ed->Word2.TdHeadPointer);
+
+ if (TempTd != NULL) {
+ while (TempTd->NextTD != NULL) {
+ TempTd = TempTd->NextTD;
+ }
+ TempTd->NextTD = HeadTd;
+ TempTd->NextTDPointer = HeadTd;
+ } else {
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) HeadTd);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Set value to ED specific field
+
+ @Param Ed ED to be set
+ @Param Field Field to be set
+ @Param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetEDField (
+ IN ED_DESCRIPTOR *Ed,
+ IN UINT32 Field,
+ IN UINT32 Value
+ )
+{
+ if (Field & ED_FUNC_ADD) {
+ Ed->Word0.FunctionAddress = Value;
+ }
+ if (Field & ED_ENDPT_NUM) {
+ Ed->Word0.EndPointNum = Value;
+ }
+ if (Field & ED_DIR) {
+ Ed->Word0.Direction = Value;
+ }
+ if (Field & ED_SPEED) {
+ Ed->Word0.Speed = Value;
+ }
+ if (Field & ED_SKIP) {
+ Ed->Word0.Skip = Value;
+ }
+ if (Field & ED_FORMAT) {
+ Ed->Word0.Format = Value;
+ }
+ if (Field & ED_MAX_PACKET) {
+ Ed->Word0.MaxPacketSize = Value;
+ }
+ if (Field & ED_PDATA) {
+ Ed->Word0.FreeSpace = Value;
+ }
+ if (Field & ED_ZERO) {
+ Ed->Word2.Zero = Value;
+ }
+ if (Field & ED_TDTAIL_PTR) {
+ Ed->TdTailPointer = (VOID *) Value;
+ }
+
+ if (Field & ED_HALTED) {
+ Ed->Word2.Halted = Value;
+ }
+ if (Field & ED_DTTOGGLE) {
+ Ed->Word2.ToggleCarry = Value;
+ }
+ if (Field & ED_TDHEAD_PTR) {
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value);
+ }
+
+ if (Field & ED_NEXT_EDPTR) {
+ Ed->NextED = (VOID *) Value;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get value from an ED's specific field
+
+ @Param Ed ED pointer
+ @Param Field Field to get value from
+
+ @retval Value of the field
+
+**/
+UINT32
+OhciGetEDField (
+ IN ED_DESCRIPTOR *Ed,
+ IN UINT32 Field
+ )
+{
+ switch (Field) {
+ case ED_FUNC_ADD:
+ return Ed->Word0.FunctionAddress;
+ break;
+ case ED_ENDPT_NUM:
+ return Ed->Word0.EndPointNum;
+ break;
+ case ED_DIR:
+ return Ed->Word0.Direction;
+ break;
+ case ED_SPEED:
+ return Ed->Word0.Speed;
+ break;
+ case ED_SKIP:
+ return Ed->Word0.Skip;
+ break;
+ case ED_FORMAT:
+ return Ed->Word0.Format;
+ break;
+ case ED_MAX_PACKET:
+ return Ed->Word0.MaxPacketSize;
+ break;
+
+ case ED_TDTAIL_PTR:
+ return (UINT32) Ed->TdTailPointer;
+ break;
+
+ case ED_HALTED:
+ return Ed->Word2.Halted;
+ break;
+
+ case ED_DTTOGGLE:
+ return Ed->Word2.ToggleCarry;
+ break;
+
+ case ED_TDHEAD_PTR:
+ return Ed->Word2.TdHeadPointer << 4;
+ break;
+
+ case ED_NEXT_EDPTR:
+ return (UINT32) Ed->NextED;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
+
+
+/**
+
+ Set value to TD specific field
+
+ @Param Td TD to be set
+ @Param Field Field to be set
+ @Param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetTDField (
+ IN TD_DESCRIPTOR *Td,
+ IN UINT32 Field,
+ IN UINT32 Value
+ )
+{
+ if (Field & TD_PDATA) {
+ Td->Word0.Reserved = Value;
+ }
+ if (Field & TD_BUFFER_ROUND) {
+ Td->Word0.BufferRounding = Value;
+ }
+ if (Field & TD_DIR_PID) {
+ Td->Word0.DirPID = Value;
+ }
+ if (Field & TD_DELAY_INT) {
+ Td->Word0.DelayInterrupt = Value;
+ }
+ if (Field & TD_DT_TOGGLE) {
+ Td->Word0.DataToggle = Value | 0x2;
+ }
+ if (Field & TD_ERROR_CNT) {
+ Td->Word0.ErrorCount = Value;
+ }
+ if (Field & TD_COND_CODE) {
+ Td->Word0.ConditionCode = Value;
+ }
+
+ if (Field & TD_CURR_BUFFER_PTR) {
+ Td->CurrBufferPointer = (VOID *) Value;
+ }
+
+
+ if (Field & TD_NEXT_PTR) {
+ Td->NextTD = (VOID *) Value;
+ }
+
+ if (Field & TD_BUFFER_END_PTR) {
+ Td->BufferEndPointer = (VOID *) Value;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Get value from ED specific field
+
+ @Param Td TD pointer
+ @Param Field Field to get value from
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetTDField (
+ IN TD_DESCRIPTOR *Td,
+ IN UINT32 Field
+ )
+{
+ switch (Field){
+ case TD_BUFFER_ROUND:
+ return Td->Word0.BufferRounding;
+ break;
+ case TD_DIR_PID:
+ return Td->Word0.DirPID;
+ break;
+ case TD_DELAY_INT:
+ return Td->Word0.DelayInterrupt;
+ break;
+ case TD_DT_TOGGLE:
+ return Td->Word0.DataToggle;
+ break;
+ case TD_ERROR_CNT:
+ return Td->Word0.ErrorCount;
+ break;
+ case TD_COND_CODE:
+ return Td->Word0.ConditionCode;
+ break;
+ case TD_CURR_BUFFER_PTR:
+ return (UINT32) Td->CurrBufferPointer;
+ break;
+
+ case TD_NEXT_PTR:
+ return (UINT32) Td->NextTD;
+ break;
+
+ case TD_BUFFER_END_PTR:
+ return (UINT32) Td->BufferEndPointer;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return 0;
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h
new file mode 100644
index 0000000000..8376b0a848
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h
@@ -0,0 +1,237 @@
+/** @file
+Provides some data struct used by OHCI controller 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 _OHCI_URB_H
+#define _OHCI_URB_H
+
+#include "Descriptor.h"
+
+
+//
+// Func List
+//
+
+
+/**
+
+ Create a TD
+
+ @Param Ohc UHC private data
+
+ @retval TD structure pointer
+
+**/
+TD_DESCRIPTOR *
+OhciCreateTD (
+ IN USB_OHCI_HC_DEV *Ohc
+ );
+
+/**
+
+ Free a TD
+
+ @Param Ohc UHC private data
+ @Param Td Pointer to a TD to free
+
+ @retval EFI_SUCCESS TD freed
+
+**/
+EFI_STATUS
+OhciFreeTD (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN TD_DESCRIPTOR *Td
+ );
+
+/**
+
+ Create a ED
+
+ @Param Ohc Device private data
+
+ @retval ED descriptor pointer
+
+**/
+ED_DESCRIPTOR *
+OhciCreateED (
+ USB_OHCI_HC_DEV *Ohc
+ );
+
+
+/**
+
+ Free a ED
+
+ @Param Ohc UHC private data
+ @Param Ed Pointer to a ED to free
+
+ @retval EFI_SUCCESS ED freed
+
+**/
+
+EFI_STATUS
+OhciFreeED (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *Ed
+ );
+
+/**
+
+ Free ED
+
+ @Param Ohc Device private data
+ @Param Ed Pointer to a ED to free
+
+ @retval EFI_SUCCESS ED freed
+
+**/
+EFI_STATUS
+OhciFreeAllTDFromED (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN ED_DESCRIPTOR *Ed
+ );
+
+/**
+
+ Attach an ED
+
+ @Param Ed Ed to be attached
+ @Param NewEd Ed to attach
+
+ @retval EFI_SUCCESS NewEd attached to Ed
+ @retval EFI_INVALID_PARAMETER Ed is NULL
+
+**/
+EFI_STATUS
+OhciAttachED (
+ IN ED_DESCRIPTOR *Ed,
+ IN ED_DESCRIPTOR *NewEd
+ );
+/**
+
+ Attach an ED to an ED list
+
+ @Param OHC UHC private data
+ @Param ListType Type of the ED list
+ @Param Ed ED to attach
+ @Param EdList ED list to be attached
+
+ @retval EFI_SUCCESS ED attached to ED list
+
+**/
+EFI_STATUS
+OhciAttachEDToList (
+ IN USB_OHCI_HC_DEV *Ohc,
+ IN DESCRIPTOR_LIST_TYPE ListType,
+ IN ED_DESCRIPTOR *Ed,
+ IN ED_DESCRIPTOR *EdList
+ );
+EFI_STATUS
+OhciLinkTD (
+ IN TD_DESCRIPTOR *Td1,
+ IN TD_DESCRIPTOR *Td2
+ );
+
+
+/**
+
+ Attach TD list to ED
+
+ @Param Ed ED which TD list attach on
+ @Param HeadTd Head of the TD list to attach
+
+ @retval EFI_SUCCESS TD list attached on the ED
+
+**/
+EFI_STATUS
+OhciAttachTDListToED (
+ IN ED_DESCRIPTOR *Ed,
+ IN TD_DESCRIPTOR *HeadTd
+ );
+
+
+/**
+
+ Set value to ED specific field
+
+ @Param Ed ED to be set
+ @Param Field Field to be set
+ @Param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetEDField (
+ IN ED_DESCRIPTOR *Ed,
+ IN UINT32 Field,
+ IN UINT32 Value
+ );
+
+
+/**
+
+ Get value from an ED's specific field
+
+ @Param Ed ED pointer
+ @Param Field Field to get value from
+
+ @retval Value of the field
+
+**/
+UINT32
+OhciGetEDField (
+ IN ED_DESCRIPTOR *Ed,
+ IN UINT32 Field
+ );
+
+
+/**
+
+ Set value to TD specific field
+
+ @Param Td TD to be set
+ @Param Field Field to be set
+ @Param Value Value to set
+
+ @retval EFI_SUCCESS Value set
+
+**/
+EFI_STATUS
+OhciSetTDField (
+ IN TD_DESCRIPTOR *Td,
+ IN UINT32 Field,
+ IN UINT32 Value
+ );
+
+
+/**
+
+ Get value from ED specific field
+
+ @Param Td TD pointer
+ @Param Field Field to get value from
+
+ @retval Value of the field
+
+**/
+
+UINT32
+OhciGetTDField (
+ IN TD_DESCRIPTOR *Td,
+ IN UINT32 Field
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c
new file mode 100644
index 0000000000..10c2049d02
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c
@@ -0,0 +1,497 @@
+/** @file
+Routine procedures for memory allocate/free.
+
+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 "OhcPeim.h"
+
+
+/**
+ Allocate a block of memory to be used by the buffer pool.
+
+ Use Redirect memory services to allocate memmory so that USB DMA transfers do
+ not cause IMR violations on Quark.
+
+ @param Pool The buffer pool to allocate memory for.
+ @param Pages How many pages to allocate.
+
+ @return The allocated memory block or NULL if failed.
+
+**/
+USBHC_MEM_BLOCK *
+UsbHcAllocMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Pages
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
+ EFI_STATUS Status;
+ UINTN PageNumber;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+
+ Mapping = NULL;
+ PageNumber = sizeof(USBHC_MEM_BLOCK)/PAGESIZE +1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ PageNumber,
+ &TempPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
+
+ //
+ // each bit in the bit array represents USBHC_MEM_UNIT
+ // bytes of memory in the memory block.
+ //
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
+
+ Block = (USBHC_MEM_BLOCK*)(UINTN)TempPtr;
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
+
+ PageNumber = (Block->BitsLen)/PAGESIZE +1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ PageNumber,
+ &TempPtr
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
+
+ Block->Bits = (UINT8 *)(UINTN)TempPtr;
+
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ Pages,
+ &TempPtr
+ );
+ ZeroMem ((VOID *)(UINTN)TempPtr, Pages*EFI_PAGE_SIZE);
+
+ BufHost = (VOID *)(UINTN)TempPtr;
+ MappedAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) BufHost;
+ //
+ // Check whether the data structure used by the host controller
+ // should be restricted into the same 4G
+ //
+ if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
+ return NULL;
+ }
+
+ Block->BufHost = BufHost;
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);
+ Block->Mapping = Mapping;
+ Block->Next = NULL;
+
+ return Block;
+
+}
+
+
+/**
+ Free the memory block from the memory pool.
+
+ @param Pool The memory pool to free the block from.
+ @param Block The memory block to free.
+
+**/
+VOID
+UsbHcFreeMemBlock (
+ IN USBHC_MEM_POOL *Pool,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+
+ ASSERT ((Pool != NULL) && (Block != NULL));
+}
+
+
+/**
+ Alloc some memory from the block.
+
+ @param Block The memory block to allocate memory from.
+ @param Units Number of memory units to allocate.
+
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,
+ the return value is NULL.
+
+**/
+VOID *
+UsbHcAllocMemFromBlock (
+ IN USBHC_MEM_BLOCK *Block,
+ IN UINTN Units
+ )
+{
+ UINTN Byte;
+ UINT8 Bit;
+ UINTN StartByte;
+ UINT8 StartBit;
+ UINTN Available;
+ UINTN Count;
+
+ ASSERT ((Block != 0) && (Units != 0));
+
+ StartByte = 0;
+ StartBit = 0;
+ Available = 0;
+
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
+ //
+ // If current bit is zero, the corresponding memory unit is
+ // available, otherwise we need to restart our searching.
+ // Available counts the consective number of zero bit.
+ //
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
+ Available++;
+
+ if (Available >= Units) {
+ break;
+ }
+
+ NEXT_BIT (Byte, Bit);
+
+ } else {
+ NEXT_BIT (Byte, Bit);
+
+ Available = 0;
+ StartByte = Byte;
+ StartBit = Bit;
+ }
+ }
+
+ if (Available < Units) {
+ return NULL;
+ }
+
+ //
+ // Mark the memory as allocated
+ //
+ Byte = StartByte;
+ Bit = StartBit;
+
+ for (Count = 0; Count < Units; Count++) {
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
+}
+
+/**
+ Insert the memory block to the pool's list of the blocks.
+
+ @param Head The head of the memory pool's block list.
+ @param Block The memory block to insert.
+
+**/
+VOID
+UsbHcInsertMemBlockToPool (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ ASSERT ((Head != NULL) && (Block != NULL));
+ Block->Next = Head->Next;
+ Head->Next = Block;
+}
+
+
+/**
+ Is the memory block empty?
+
+ @param Block The memory block to check.
+
+ @retval TRUE The memory block is empty.
+ @retval FALSE The memory block isn't empty.
+
+**/
+BOOLEAN
+UsbHcIsMemBlockEmpty (
+ IN USBHC_MEM_BLOCK *Block
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Block->BitsLen; Index++) {
+ if (Block->Bits[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Unlink the memory block from the pool's list.
+
+ @param Head The block list head of the memory's pool.
+ @param BlockToUnlink The memory block to unlink.
+
+**/
+VOID
+UsbHcUnlinkMemBlock (
+ IN USBHC_MEM_BLOCK *Head,
+ IN USBHC_MEM_BLOCK *BlockToUnlink
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ if (Block->Next == BlockToUnlink) {
+ Block->Next = BlockToUnlink->Next;
+ BlockToUnlink->Next = NULL;
+ break;
+ }
+ }
+}
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Check4G Whether the host controller requires allocated memory
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ )
+{
+ USBHC_MEM_POOL *Pool;
+ UINTN PageNumber;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+
+ PageNumber = sizeof(USBHC_MEM_POOL)/PAGESIZE +1;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ PageNumber,
+ &TempPtr
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
+
+ Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);
+ Pool->Check4G = Check4G;
+ Pool->Which4G = Which4G;
+ Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
+
+ if (Pool->Head == NULL) {
+ Pool = NULL;
+ }
+
+ return Pool;
+}
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_SUCCESS The memory pool is freed.
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ )
+{
+ USBHC_MEM_BLOCK *Block;
+
+ ASSERT (Pool->Head != NULL);
+
+ //
+ // Unlink all the memory blocks from the pool, then free them.
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the
+ // first block.
+ //
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ UsbHcFreeMemBlock (Pool, Pool->Head);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ USBHC_MEM_BLOCK *NewBlock;
+ VOID *Mem;
+ UINTN AllocSize;
+ UINTN Pages;
+
+ Mem = NULL;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ Head = Pool->Head;
+ ASSERT (Head != NULL);
+
+ //
+ // First check whether current memory blocks can satisfy the allocation.
+ //
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ break;
+ }
+ }
+
+ if (Mem != NULL) {
+ return Mem;
+ }
+
+ //
+ // Create a new memory block if there is not enough memory
+ // in the pool. If the allocation size is larger than the
+ // default page number, just allocate a large enough memory
+ // block. Otherwise allocate default pages.
+ //
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
+ } else {
+ Pages = USBHC_MEM_DEFAULT_PAGES;
+ }
+
+ NewBlock = UsbHcAllocMemBlock (Pool, Pages);
+
+ if (NewBlock == NULL) {
+ DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));
+ return NULL;
+ }
+
+ //
+ // Add the new memory block to the pool, then allocate memory from it
+ //
+ UsbHcInsertMemBlockToPool (Head, NewBlock);
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
+
+ if (Mem != NULL) {
+ ZeroMem (Mem, Size);
+ }
+
+ return Mem;
+}
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ )
+{
+ USBHC_MEM_BLOCK *Head;
+ USBHC_MEM_BLOCK *Block;
+ UINT8 *ToFree;
+ UINTN AllocSize;
+ UINTN Byte;
+ UINTN Bit;
+ UINTN Count;
+
+ Head = Pool->Head;
+ AllocSize = USBHC_MEM_ROUND (Size);
+ ToFree = (UINT8 *) Mem;
+
+ for (Block = Head; Block != NULL; Block = Block->Next) {
+ //
+ // scan the memory block list for the memory block that
+ // completely contains the memory to free.
+ //
+ if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
+ //
+ // compute the start byte and bit in the bit array
+ //
+ Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
+ Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
+
+ //
+ // reset associated bits in bit arry
+ //
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
+
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
+ NEXT_BIT (Byte, Bit);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If Block == NULL, it means that the current memory isn't
+ // in the host controller's pool. This is critical because
+ // the caller has passed in a wrong memory point
+ //
+ ASSERT (Block != NULL);
+
+ //
+ // Release the current memory block if it is empty and not the head
+ //
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
+ UsbHcFreeMemBlock (Pool, Block);
+ }
+
+ return ;
+}
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h
new file mode 100644
index 0000000000..0f4e80a5c6
--- /dev/null
+++ b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h
@@ -0,0 +1,140 @@
+/** @file
+This file contains the definination for host controller memory
+management 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 _USB_HC_MEM_H_
+#define _USB_HC_MEM_H_
+
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))
+
+#define USB_HC_BIT_IS_SET(Data, Bit) \
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
+
+#define USB_HC_HIGH_32BIT(Addr64) \
+ ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
+
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
+struct _USBHC_MEM_BLOCK {
+ UINT8 *Bits; // Bit array to record which unit is allocated
+ UINTN BitsLen;
+ UINT8 *Buf;
+ UINT8 *BufHost;
+ UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
+ USBHC_MEM_BLOCK *Next;
+};
+
+//
+// USBHC_MEM_POOL is used to manage the memory used by USB
+// host controller. EHCI requires the control memory and transfer
+// data to be on the same 4G memory.
+//
+typedef struct _USBHC_MEM_POOL {
+ BOOLEAN Check4G;
+ UINT32 Which4G;
+ USBHC_MEM_BLOCK *Head;
+} USBHC_MEM_POOL;
+
+//
+// Memory allocation unit, must be 2^n, n>4
+//
+#define USBHC_MEM_UNIT 64
+
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)
+#define USBHC_MEM_DEFAULT_PAGES 16
+
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
+
+//
+// Advance the byte and bit to the next bit, adjust byte accordingly.
+//
+#define NEXT_BIT(Byte, Bit) \
+ do { \
+ (Bit)++; \
+ if ((Bit) > 7) { \
+ (Byte)++; \
+ (Bit) = 0; \
+ } \
+ } while (0)
+
+
+
+/**
+ Initialize the memory management pool for the host controller.
+
+ @param PciIo The PciIo that can be used to access the host controller.
+ @param Check4G Whether the host controller requires allocated memory
+ from one 4G address space.
+ @param Which4G The 4G memory area each memory allocated should be from.
+
+ @retval EFI_SUCCESS The memory pool is initialized.
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
+
+**/
+USBHC_MEM_POOL *
+UsbHcInitMemPool (
+ IN BOOLEAN Check4G,
+ IN UINT32 Which4G
+ );
+
+
+/**
+ Release the memory management pool.
+
+ @param Pool The USB memory pool to free.
+
+ @retval EFI_SUCCESS The memory pool is freed.
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.
+
+**/
+EFI_STATUS
+UsbHcFreeMemPool (
+ IN USBHC_MEM_POOL *Pool
+ );
+
+
+/**
+ Allocate some memory from the host controller's memory pool
+ which can be used to communicate with host controller.
+
+ @param Pool The host controller's memory pool.
+ @param Size Size of the memory to allocate.
+
+ @return The allocated memory or NULL.
+
+**/
+VOID *
+UsbHcAllocateMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN UINTN Size
+ );
+
+
+/**
+ Free the allocated memory back to the memory pool.
+
+ @param Pool The memory pool of the host controller.
+ @param Mem The memory to free.
+ @param Size The size of the memory to free.
+
+**/
+VOID
+UsbHcFreeMem (
+ IN USBHC_MEM_POOL *Pool,
+ IN VOID *Mem,
+ IN UINTN Size
+ );
+
+#endif