From 9b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164 Mon Sep 17 00:00:00 2001 From: Michael Kinney Date: Tue, 15 Dec 2015 19:22:23 +0000 Subject: [PATCH] QuarkSocPkg: Add new package for Quark SoC X1000 Changes for V4 ============== 1) Remove Unicode character from C source file 2) Move delete of QuarkSocPkg\QuarkNorthCluster\Binary\QuarkMicrocode from QuarkPlatformPkg commit to QuarkSocPkg commit Changes for V2 ============== 1) Sync with new APIs in SmmCpuFeaturesLib class 2) Use new generic PCI serial driver PciSioSerialDxe in MdeModulePkg 3) Remove PCI serial driver from QuarkSocPkg 4) Apply optimizations to MtrrLib from MtrrLib in UefiCpuPkg 5) Convert all UNI files to utf-8 6) Replace tabs with spaces and remove trailing spaces 7) Add License.txt Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney Acked-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19286 6f19259b-4bc3-4df7-8a09-765794883524 --- .../PlatformPcieHelperLib.inf | 47 + QuarkSocPkg/Contributions.txt | 218 ++ QuarkSocPkg/License.txt | 25 + .../Include/DdrMemoryController.h | 257 ++ .../QuarkNorthCluster/Include/IntelQNCBase.h | 23 + .../Include/IntelQNCConfig.h | 106 + .../QuarkNorthCluster/Include/IntelQNCDxe.h | 23 + .../QuarkNorthCluster/Include/IntelQNCPeim.h | 23 + .../QuarkNorthCluster/Include/IntelQNCRegs.h | 54 + .../Include/Library/IntelQNCLib.h | 290 ++ .../Include/Library/QNCAccessLib.h | 167 ++ .../Include/Library/QNCSmmLib.h | 63 + .../Include/Ppi/QNCMemoryInit.h | 42 + .../Include/Protocol/PchInfo.h | 54 + .../Include/Protocol/PlatformPolicy.h | 37 + .../Include/Protocol/QncS3Support.h | 90 + .../Include/Protocol/SmmIchnDispatch2.h | 121 + .../QuarkNorthCluster/Include/Protocol/Spi.h | 351 +++ .../QuarkNorthCluster/Include/QNCAccess.h | 183 ++ .../Include/QNCCommonDefinitions.h | 356 +++ .../QuarkNorthCluster/Include/QuarkNcSocId.h | 757 +++++ .../Library/IntelQNCLib/CommonHeader.h | 38 + .../Library/IntelQNCLib/IntelQNCLib.c | 777 +++++ .../Library/IntelQNCLib/IntelQNCLib.inf | 63 + .../Library/IntelQNCLib/PciExpress.c | 949 ++++++ .../Library/MtrrLib/MtrrLib.c | 2117 +++++++++++++ .../Library/MtrrLib/MtrrLib.inf | 48 + .../Library/MtrrLib/MtrrLib.uni | 24 + .../Library/QNCAccessLib/BaseAccess.c | 34 + .../Library/QNCAccessLib/QNCAccessLib.c | 333 +++ .../Library/QNCAccessLib/QNCAccessLib.inf | 43 + .../Library/QNCAccessLib/RuntimeAccess.c | 148 + .../QNCAccessLib/RuntimeQNCAccessLib.inf | 49 + .../Library/QNCSmmLib/QNCSmmLib.c | 322 ++ .../Library/QNCSmmLib/QNCSmmLib.inf | 51 + .../Library/ResetSystemLib/ResetSystemLib.c | 322 ++ .../Library/ResetSystemLib/ResetSystemLib.inf | 52 + .../Library/SmbusLib/CommonHeader.h | 31 + .../Library/SmbusLib/SmbusLib.c | 803 +++++ .../Library/SmbusLib/SmbusLib.inf | 53 + .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.c | 438 +++ .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf | 34 + .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni | 18 + .../MemoryInit/Pei/MemoryInit.c | 65 + .../MemoryInit/Pei/MemoryInit.h | 41 + .../MemoryInit/Pei/MemoryInitPei.inf | 76 + .../MemoryInit/Pei/core_types.h | 49 + .../MemoryInit/Pei/gen5_iosf_sb_definitions.h | 744 +++++ .../MemoryInit/Pei/general_definitions.h | 90 + .../QuarkNorthCluster/MemoryInit/Pei/hte.c | 542 ++++ .../QuarkNorthCluster/MemoryInit/Pei/hte.h | 72 + .../QuarkNorthCluster/MemoryInit/Pei/io.h | 138 + .../QuarkNorthCluster/MemoryInit/Pei/lprint.c | 388 +++ .../MemoryInit/Pei/meminit.c | 2645 +++++++++++++++++ .../MemoryInit/Pei/meminit.h | 28 + .../MemoryInit/Pei/meminit_utils.c | 1580 ++++++++++ .../MemoryInit/Pei/meminit_utils.h | 97 + .../MemoryInit/Pei/memory_options.h | 83 + .../QuarkNorthCluster/MemoryInit/Pei/mrc.c | 46 + .../QuarkNorthCluster/MemoryInit/Pei/mrc.h | 166 ++ .../MemoryInit/Pei/platform.c | 192 ++ .../MemoryInit/Pei/prememinit.c | 193 ++ .../MemoryInit/Pei/prememinit.h | 21 + .../QNCInit/Dxe/CommonHeader.h | 55 + .../QNCInit/Dxe/DxeQNCSmbus.c | 618 ++++ .../QNCInit/Dxe/DxeQNCSmbus.h | 211 ++ .../QNCInit/Dxe/LegacyRegion.c | 243 ++ .../QNCInit/Dxe/LegacyRegion.h | 204 ++ .../QuarkNorthCluster/QNCInit/Dxe/QNCInit.c | 527 ++++ .../QuarkNorthCluster/QNCInit/Dxe/QNCInit.h | 55 + .../QNCInit/Dxe/QNCInitDxe.inf | 98 + .../QNCInit/Dxe/QNCRootPorts.c | 82 + .../QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h | 86 + .../QNCInit/Dxe/QNCSmbusExec.c | 252 ++ .../S3Support/Dxe/QncS3Support.c | 423 +++ .../S3Support/Dxe/QncS3Support.h | 123 + .../S3Support/Dxe/QncS3Support.inf | 70 + .../Smm/Dxe/SmmAccessDxe/SmmAccess.inf | 54 + .../Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c | 395 +++ .../Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h | 235 ++ .../Smm/Dxe/SmmControlDxe/SmmControlDriver.c | 366 +++ .../Smm/Dxe/SmmControlDxe/SmmControlDxe.inf | 61 + .../DxeSmm/QncSmmDispatcher/CommonHeader.h | 51 + .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c | 38 + .../QncSmmDispatcher/QNC/QNCSmmHelpers.c | 555 ++++ .../QNC/QNCSmmPeriodicTimer.c | 430 +++ .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c | 217 ++ .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c | 96 + .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c | 153 + .../Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h | 871 ++++++ .../Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c | 800 +++++ .../QncSmmDispatcher/QNCSmmDispatcher.inf | 87 + .../DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c | 373 +++ .../DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h | 225 ++ .../DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h | 19 + .../DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h | 184 ++ .../Smm/Pei/SmmAccessPei/SmmAccessPei.c | 382 +++ .../Smm/Pei/SmmAccessPei/SmmAccessPei.inf | 51 + .../Smm/Pei/SmmControlPei/SmmControlPei.c | 282 ++ .../Smm/Pei/SmmControlPei/SmmControlPei.inf | 57 + .../QuarkNorthCluster/Spi/Common/SpiCommon.c | 956 ++++++ .../QuarkNorthCluster/Spi/Common/SpiCommon.h | 323 ++ .../QuarkNorthCluster/Spi/PchSpiRuntime.inf | 90 + .../QuarkNorthCluster/Spi/PchSpiSmm.inf | 56 + .../QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c | 211 ++ .../QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h | 85 + .../QuarkNorthCluster/Spi/Smm/PchSpi.c | 129 + .../QuarkNorthCluster/Spi/Smm/PchSpi.h | 53 + QuarkSocPkg/QuarkSocPkg.dec | 240 ++ QuarkSocPkg/QuarkSocPkg.dsc | 259 ++ QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h | 120 + .../QuarkSouthCluster/Include/I2cRegs.h | 101 + QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h | 254 ++ .../QuarkSouthCluster/Include/IohAccess.h | 24 + .../Include/IohCommonDefinitions.h | 348 +++ .../Include/Library/I2cLib.h | 158 + .../Include/Library/IohLib.h | 42 + QuarkSocPkg/QuarkSouthCluster/Include/MMC.h | 280 ++ .../QuarkSouthCluster/Include/SDCard.h | 152 + .../QuarkSouthCluster/Include/SDHostIo.h | 339 +++ .../IohInit/Dxe/CommonHeader.h | 61 + .../QuarkSouthCluster/IohInit/Dxe/IohBds.h | 89 + .../QuarkSouthCluster/IohInit/Dxe/IohData.c | 48 + .../QuarkSouthCluster/IohInit/Dxe/IohInit.c | 43 + .../IohInit/Dxe/IohInitDxe.inf | 82 + .../Library/I2cLib/CommonHeader.h | 220 ++ .../QuarkSouthCluster/Library/I2cLib/I2cLib.c | 1004 +++++++ .../Library/I2cLib/I2cLib.inf | 68 + .../Library/IohLib/CommonHeader.h | 35 + .../QuarkSouthCluster/Library/IohLib/IohLib.c | 105 + .../Library/IohLib/IohLib.inf | 55 + .../Sdio/Dxe/SDControllerDxe/ComponentName.c | 233 ++ .../Sdio/Dxe/SDControllerDxe/ComponentName.h | 147 + .../Sdio/Dxe/SDControllerDxe/SDController.c | 1789 +++++++++++ .../Sdio/Dxe/SDControllerDxe/SDController.h | 322 ++ .../Dxe/SDControllerDxe/SDControllerDxe.inf | 62 + .../Sdio/Dxe/SDMediaDeviceDxe/CEATA.c | 656 ++++ .../Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c | 396 +++ .../Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c | 221 ++ .../Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h | 145 + .../Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c | 544 ++++ .../Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c | 1716 +++++++++++ .../Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c | 323 ++ .../Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h | 468 +++ .../Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf | 66 + .../QuarkSouthCluster/Usb/Common/Pei/UsbPei.c | 326 ++ .../QuarkSouthCluster/Usb/Common/Pei/UsbPei.h | 44 + .../Usb/Common/Pei/UsbPei.inf | 59 + .../Usb/Ohci/Dxe/ComponentName.c | 225 ++ .../Usb/Ohci/Dxe/ComponentName.h | 147 + .../Usb/Ohci/Dxe/Descriptor.h | 138 + .../QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c | 2488 ++++++++++++++++ .../QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h | 669 +++++ .../Usb/Ohci/Dxe/OhciDebug.c | 84 + .../Usb/Ohci/Dxe/OhciDebug.h | 48 + .../Usb/Ohci/Dxe/OhciDxe.inf | 77 + .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c | 1399 +++++++++ .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h | 926 ++++++ .../Usb/Ohci/Dxe/OhciSched.c | 534 ++++ .../Usb/Ohci/Dxe/OhciSched.h | 231 ++ .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c | 895 ++++++ .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h | 393 +++ .../QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c | 566 ++++ .../QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h | 158 + .../Usb/Ohci/Pei/Descriptor.h | 137 + .../QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c | 1402 +++++++++ .../QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h | 258 ++ .../Usb/Ohci/Pei/OhciPei.inf | 62 + .../QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c | 1394 +++++++++ .../QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h | 881 ++++++ .../Usb/Ohci/Pei/OhciSched.c | 229 ++ .../Usb/Ohci/Pei/OhciSched.h | 114 + .../QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c | 566 ++++ .../QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h | 237 ++ .../QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c | 497 ++++ .../QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h | 140 + 176 files changed, 54761 insertions(+) create mode 100644 QuarkPlatformPkg/Library/PlatformPcieHelperLib/PlatformPcieHelperLib.inf create mode 100644 QuarkSocPkg/Contributions.txt create mode 100644 QuarkSocPkg/License.txt create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf create mode 100644 QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h create mode 100644 QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c create mode 100644 QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h create mode 100644 QuarkSocPkg/QuarkSocPkg.dec create mode 100644 QuarkSocPkg/QuarkSocPkg.dsc create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/MMC.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf create mode 100644 QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf create mode 100644 QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c create mode 100644 QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h diff --git a/QuarkPlatformPkg/Library/PlatformPcieHelperLib/PlatformPcieHelperLib.inf b/QuarkPlatformPkg/Library/PlatformPcieHelperLib/PlatformPcieHelperLib.inf new file mode 100644 index 0000000000..89747d4486 --- /dev/null +++ b/QuarkPlatformPkg/Library/PlatformPcieHelperLib/PlatformPcieHelperLib.inf @@ -0,0 +1,47 @@ +## @file +# Library producing Pci Express Helper routines. +# +# Copyright (c) 2013 Intel Corporation. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformPcieHelperLib + FILE_GUID = C153F460-5D8A-4d44-83BB-A8AF5CEF132C + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformPcieHelperLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources] + PlatformPcieHelperLib.c + SocUnit.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + QuarkPlatformPkg/QuarkPlatformPkg.dec + +[LibraryClasses] + BaseLib + PcdLib + IoLib + DebugLib + TimerLib + QNCAccessLib + IntelQNCLib 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 +Subject: [PATCH] CodeModule: Brief-single-line-summary + +Full-commit-message + +Contributed-under: TianoCore Contribution Agreement 1.0 +Signed-off-by: Contributor Name +--- + +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 +#include + +#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 +#include + +#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 +#include + +#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 + +// +// 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 + +#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 + +#include + +// +// 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 + +#include +#include +#include +#include +#include +#include + +#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.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# 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.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// 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 + +/** + 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 + +#include +#include +#include +#include + +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 + +#include + +#include +#include +#include +#include +#include + +/// +/// 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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +// +// 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 +#include + +#include +#include +#include +#include +#include +#include + +#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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 +#include +#include +#include + +#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.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# 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.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// 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 +#include +// +// The protocols, PPI and GUID defintions for this module +// +#include +// +// The Library classes this module consumes +// +#include +#include +#include + + +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; /**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 + +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 +#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_ichannel_enables & (1<channel_enables & (1<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_irank_enables & (1<channel_enables & (1<channel_enables & (1<channel_enables & (1<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_ichannel_enables & (1<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_ichannel_enables & (1<rank_enables & (1<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_ichannel_enables & (1<rank_enables & (1<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_ichannel_enables & (1<rank_enables & (1<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, "\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<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 +#include + +// +// The protocols, PPI and GUID definitions for this module +// +#include +#include +#include +#include + +// +// The Library classes this module consumes +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// +// Driver Produced Protocol Prototypes +// +#include +#include + +#include +#include +// +// 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Driver Consumed Protocol Prototypes +// +#include + +// +// Driver Consumed GUID Prototypes +// +#include + +// +// Driver produced protocol +// +#include + +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/** + 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 +#include +#include +#include +#include +#include +#include +#include + +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SpiCommon.h" +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include "SpiCommon.h" +#include +#include +#include +#include +#include + +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.

+ # @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.

+ # @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.

+ # @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 { + + PciExpressLib|MdePkg/Library/DxeRuntimePciExpressLib/DxeRuntimePciExpressLib.inf + } + QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf + QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf { + + 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 +#include +#include + +// +// The protocols, PPI and GUID defintions for this module +// +#include + +#include +#include + +// +// The Library classes this module consumes +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 +#include +#include + +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 +#include + +#include +#include +#include +#include +#include +#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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + + +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 + +#include +#include + +#include +#include +#include +#include +#include +#include + +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 -- 2.39.2