From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 134.134.136.100, mailfrom: michael.d.kinney@intel.com) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by groups.io with SMTP; Thu, 09 May 2019 20:34:45 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 May 2019 20:34:43 -0700 X-ExtLoop1: 1 Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 09 May 2019 20:34:38 -0700 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Kelly Steele , Michael Kubacki , Leif Lindholm , Ard Biesheuvel Subject: [edk2-platforms: Patch 3/8] Silicon/Intel: Import QuarkSocPkg from edk2 Date: Thu, 9 May 2019 20:34:30 -0700 Message-Id: <20190510033435.24112-4-michael.d.kinney@intel.com> X-Mailer: git-send-email 2.21.0.windows.1 In-Reply-To: <20190510033435.24112-1-michael.d.kinney@intel.com> References: <20190510033435.24112-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit https://bugzilla.tianocore.org/show_bug.cgi?id=1374 Import QuarkSocPkg from edk2/master. Cc: Kelly Steele Cc: Michael Kubacki Cc: Leif Lindholm Cc: Ard Biesheuvel Signed-off-by: Michael D Kinney --- .../Include/DdrMemoryController.h | 251 ++ .../QuarkNorthCluster/Include/IntelQNCBase.h | 17 + .../Include/IntelQNCConfig.h | 100 + .../QuarkNorthCluster/Include/IntelQNCDxe.h | 17 + .../QuarkNorthCluster/Include/IntelQNCPeim.h | 17 + .../QuarkNorthCluster/Include/IntelQNCRegs.h | 48 + .../Include/Library/IntelQNCLib.h | 284 ++ .../Include/Library/QNCAccessLib.h | 161 + .../Include/Library/QNCSmmLib.h | 57 + .../Include/Ppi/QNCMemoryInit.h | 36 + .../Include/Protocol/PchInfo.h | 48 + .../Include/Protocol/PlatformPolicy.h | 31 + .../Include/Protocol/QncS3Support.h | 84 + .../Include/Protocol/SmmIchnDispatch2.h | 115 + .../QuarkNorthCluster/Include/Protocol/Spi.h | 345 +++ .../QuarkNorthCluster/Include/QNCAccess.h | 177 ++ .../Include/QNCCommonDefinitions.h | 350 +++ .../QuarkNorthCluster/Include/QuarkNcSocId.h | 751 +++++ .../Library/IntelQNCLib/CommonHeader.h | 32 + .../Library/IntelQNCLib/IntelQNCLib.c | 771 +++++ .../Library/IntelQNCLib/IntelQNCLib.inf | 57 + .../Library/IntelQNCLib/PciExpress.c | 932 ++++++ .../Library/MtrrLib/MtrrLib.c | 2112 +++++++++++++ .../Library/MtrrLib/MtrrLib.inf | 42 + .../Library/MtrrLib/MtrrLib.uni | 18 + .../Library/QNCAccessLib/BaseAccess.c | 28 + .../Library/QNCAccessLib/QNCAccessLib.c | 327 ++ .../Library/QNCAccessLib/QNCAccessLib.inf | 37 + .../Library/QNCAccessLib/RuntimeAccess.c | 142 + .../QNCAccessLib/RuntimeQNCAccessLib.inf | 43 + .../Library/QNCSmmLib/QNCSmmLib.c | 313 ++ .../Library/QNCSmmLib/QNCSmmLib.inf | 44 + .../Library/ResetSystemLib/ResetSystemLib.c | 379 +++ .../Library/ResetSystemLib/ResetSystemLib.inf | 46 + .../Library/SmbusLib/CommonHeader.h | 25 + .../Library/SmbusLib/SmbusLib.c | 797 +++++ .../Library/SmbusLib/SmbusLib.inf | 47 + .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.c | 446 +++ .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf | 30 + .../SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni | 12 + .../MemoryInit/Pei/MemoryInit.c | 59 + .../MemoryInit/Pei/MemoryInit.h | 35 + .../MemoryInit/Pei/MemoryInitPei.inf | 70 + .../MemoryInit/Pei/core_types.h | 43 + .../MemoryInit/Pei/gen5_iosf_sb_definitions.h | 738 +++++ .../MemoryInit/Pei/general_definitions.h | 84 + .../QuarkNorthCluster/MemoryInit/Pei/hte.c | 536 ++++ .../QuarkNorthCluster/MemoryInit/Pei/hte.h | 66 + .../QuarkNorthCluster/MemoryInit/Pei/io.h | 132 + .../QuarkNorthCluster/MemoryInit/Pei/lprint.c | 382 +++ .../MemoryInit/Pei/meminit.c | 2638 +++++++++++++++++ .../MemoryInit/Pei/meminit.h | 22 + .../MemoryInit/Pei/meminit_utils.c | 1574 ++++++++++ .../MemoryInit/Pei/meminit_utils.h | 95 + .../MemoryInit/Pei/memory_options.h | 77 + .../QuarkNorthCluster/MemoryInit/Pei/mrc.c | 40 + .../QuarkNorthCluster/MemoryInit/Pei/mrc.h | 160 + .../MemoryInit/Pei/platform.c | 186 ++ .../MemoryInit/Pei/prememinit.c | 187 ++ .../MemoryInit/Pei/prememinit.h | 15 + .../QNCInit/Dxe/CommonHeader.h | 49 + .../QNCInit/Dxe/DxeQNCSmbus.c | 612 ++++ .../QNCInit/Dxe/DxeQNCSmbus.h | 205 ++ .../QNCInit/Dxe/LegacyRegion.c | 237 ++ .../QNCInit/Dxe/LegacyRegion.h | 198 ++ .../QuarkNorthCluster/QNCInit/Dxe/QNCInit.c | 518 ++++ .../QuarkNorthCluster/QNCInit/Dxe/QNCInit.h | 49 + .../QNCInit/Dxe/QNCInitDxe.inf | 92 + .../QNCInit/Dxe/QNCRootPorts.c | 76 + .../QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h | 80 + .../QNCInit/Dxe/QNCSmbusExec.c | 246 ++ .../S3Support/Dxe/QncS3Support.c | 417 +++ .../S3Support/Dxe/QncS3Support.h | 117 + .../S3Support/Dxe/QncS3Support.inf | 64 + .../Smm/Dxe/SmmAccessDxe/SmmAccess.inf | 49 + .../Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c | 405 +++ .../Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h | 230 ++ .../Smm/Dxe/SmmControlDxe/SmmControlDriver.c | 358 +++ .../Smm/Dxe/SmmControlDxe/SmmControlDxe.inf | 55 + .../DxeSmm/QncSmmDispatcher/CommonHeader.h | 45 + .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c | 32 + .../QncSmmDispatcher/QNC/QNCSmmHelpers.c | 549 ++++ .../QNC/QNCSmmPeriodicTimer.c | 424 +++ .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c | 211 ++ .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c | 90 + .../DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c | 147 + .../Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h | 868 ++++++ .../Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c | 825 ++++++ .../QncSmmDispatcher/QNCSmmDispatcher.inf | 81 + .../DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c | 367 +++ .../DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h | 219 ++ .../DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h | 13 + .../DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h | 178 ++ .../Smm/Pei/SmmAccessPei/SmmAccessPei.c | 376 +++ .../Smm/Pei/SmmAccessPei/SmmAccessPei.inf | 45 + .../Smm/Pei/SmmControlPei/SmmControlPei.c | 274 ++ .../Smm/Pei/SmmControlPei/SmmControlPei.inf | 51 + .../QuarkNorthCluster/Spi/Common/SpiCommon.c | 927 ++++++ .../QuarkNorthCluster/Spi/Common/SpiCommon.h | 317 ++ .../QuarkNorthCluster/Spi/PchSpiRuntime.inf | 84 + .../QuarkNorthCluster/Spi/PchSpiSmm.inf | 50 + .../QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c | 205 ++ .../QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h | 79 + .../QuarkNorthCluster/Spi/Smm/PchSpi.c | 123 + .../QuarkNorthCluster/Spi/Smm/PchSpi.h | 47 + Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec | 234 ++ Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc | 254 ++ .../QuarkSouthCluster/Include/CEATA.h | 114 + .../QuarkSouthCluster/Include/I2cRegs.h | 95 + .../QuarkSouthCluster/Include/Ioh.h | 248 ++ .../QuarkSouthCluster/Include/IohAccess.h | 18 + .../Include/IohCommonDefinitions.h | 342 +++ .../Include/Library/I2cLib.h | 152 + .../Include/Library/IohLib.h | 36 + .../QuarkSouthCluster/Include/MMC.h | 274 ++ .../QuarkSouthCluster/Include/SDCard.h | 146 + .../QuarkSouthCluster/Include/SDHostIo.h | 333 +++ .../IohInit/Dxe/CommonHeader.h | 55 + .../QuarkSouthCluster/IohInit/Dxe/IohBds.h | 83 + .../QuarkSouthCluster/IohInit/Dxe/IohData.c | 42 + .../QuarkSouthCluster/IohInit/Dxe/IohInit.c | 37 + .../IohInit/Dxe/IohInitDxe.inf | 76 + .../Library/I2cLib/CommonHeader.h | 214 ++ .../QuarkSouthCluster/Library/I2cLib/I2cLib.c | 998 +++++++ .../Library/I2cLib/I2cLib.inf | 62 + .../Library/IohLib/CommonHeader.h | 29 + .../QuarkSouthCluster/Library/IohLib/IohLib.c | 99 + .../Library/IohLib/IohLib.inf | 49 + .../Sdio/Dxe/SDControllerDxe/ComponentName.c | 227 ++ .../Sdio/Dxe/SDControllerDxe/ComponentName.h | 141 + .../Sdio/Dxe/SDControllerDxe/SDController.c | 1784 +++++++++++ .../Sdio/Dxe/SDControllerDxe/SDController.h | 316 ++ .../Dxe/SDControllerDxe/SDControllerDxe.inf | 56 + .../Sdio/Dxe/SDMediaDeviceDxe/CEATA.c | 647 ++++ .../Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c | 389 +++ .../Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c | 215 ++ .../Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h | 139 + .../Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c | 538 ++++ .../Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c | 1708 +++++++++++ .../Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c | 317 ++ .../Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h | 462 +++ .../Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf | 60 + .../QuarkSouthCluster/Usb/Common/Pei/UsbPei.c | 320 ++ .../QuarkSouthCluster/Usb/Common/Pei/UsbPei.h | 38 + .../Usb/Common/Pei/UsbPei.inf | 53 + .../Usb/Ohci/Dxe/ComponentName.c | 219 ++ .../Usb/Ohci/Dxe/ComponentName.h | 141 + .../Usb/Ohci/Dxe/Descriptor.h | 132 + .../QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c | 2473 +++++++++++++++ .../QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h | 663 +++++ .../Usb/Ohci/Dxe/OhciDebug.c | 78 + .../Usb/Ohci/Dxe/OhciDebug.h | 42 + .../Usb/Ohci/Dxe/OhciDxe.inf | 71 + .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c | 1390 +++++++++ .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h | 920 ++++++ .../Usb/Ohci/Dxe/OhciSched.c | 528 ++++ .../Usb/Ohci/Dxe/OhciSched.h | 225 ++ .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c | 889 ++++++ .../QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h | 387 +++ .../QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c | 560 ++++ .../QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h | 152 + .../Usb/Ohci/Pei/Descriptor.h | 131 + .../QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c | 1386 +++++++++ .../QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h | 252 ++ .../Usb/Ohci/Pei/OhciPei.inf | 56 + .../QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c | 1386 +++++++++ .../QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h | 875 ++++++ .../Usb/Ohci/Pei/OhciSched.c | 223 ++ .../Usb/Ohci/Pei/OhciSched.h | 108 + .../QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c | 560 ++++ .../QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h | 231 ++ .../QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c | 491 +++ .../QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h | 134 + 173 files changed, 53495 insertions(+) create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c create mode 100644 Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h new file mode 100644 index 0000000000..fe96af4405 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/DdrMemoryController.h @@ -0,0 +1,251 @@ +/** @file +Memory controller configuration. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef __DDR_MEMORY_CONTROLLER_H__ +#define __DDR_MEMORY_CONTROLLER_H__ + +// +// DDR timing data definitions. +// These are used to create bitmaps of valid timing configurations. +// + +#define DUAL_CHANNEL_DDR_TIMING_DATA_FREQUENCY_UNKNOWN 0xFF +#define DUAL_CHANNEL_DDR_TIMING_DATA_REFRESH_RATE_UNKNOWN 0xFF + +#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_20 0x01 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_25 0x00 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_30 0x02 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_ALL 0x03 + + +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_02 0x02 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_03 0x01 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_04 0x00 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_ALL 0x03 + +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_02 0x02 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_03 0x01 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_04 0x00 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_ALL 0x03 + +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_05 0x05 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_06 0x04 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_07 0x03 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_08 0x02 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_09 0x01 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_10 0x00 +#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_ALL 0x07 + +#define DUAL_CHANNEL_DDR_DATA_TYPE_REGISTERED 0x01 +#define DUAL_CHANNEL_DDR_DATA_TYPE_UNREGISTERED 0x02 +#define DUAL_CHANNEL_DDR_DATA_TYPE_BUFFERED 0x04 +#define DUAL_CHANNEL_DDR_DATA_TYPE_UNBUFFERED 0x08 +#define DUAL_CHANNEL_DDR_DATA_TYPE_SDR 0x10 +#define DUAL_CHANNEL_DDR_DATA_TYPE_DDR 0x20 + + +// +// Maximum number of SDRAM channels supported by the memory controller +// +#define MAX_CHANNELS 1 + +// +// Maximum number of DIMM sockets supported by the memory controller +// +#define MAX_SOCKETS 1 + +// +// Maximum number of sides supported per DIMM +// +#define MAX_SIDES 2 + +// +// Maximum number of "Socket Sets", where a "Socket Set is a set of matching +// DIMM's from the various channels +// +#define MAX_SOCKET_SETS 2 + +// +// Maximum number of rows supported by the memory controller +// +#define MAX_ROWS (MAX_SIDES * MAX_SOCKETS) + +// +// Maximum number of memory ranges supported by the memory controller +// +#define MAX_RANGES (MAX_ROWS + 5) + +// +// Maximum Number of Log entries +// +#define MEMORY_LOG_MAX_INDEX 16 + + +typedef struct _MEMORY_LOG_ENTRY { + EFI_STATUS_CODE_VALUE Event; + EFI_STATUS_CODE_TYPE Severity; + UINT8 Data; +} MEMORY_LOG_ENTRY; + +typedef struct _MEMORY_LOG { + UINT8 Index; + MEMORY_LOG_ENTRY Entry[MEMORY_LOG_MAX_INDEX]; +} MEMORY_LOG; + + + +// +// Defined ECC types +// +#define DUAL_CHANNEL_DDR_ECC_TYPE_NONE 0x01 // No error checking +#define DUAL_CHANNEL_DDR_ECC_TYPE_EC 0x02 // Error checking only +#define DUAL_CHANNEL_DDR_ECC_TYPE_SECC 0x04 // Software Scrubbing ECC +#define DUAL_CHANNEL_DDR_ECC_TYPE_HECC 0x08 // Hardware Scrubbing ECC +#define DUAL_CHANNEL_DDR_ECC_TYPE_CKECC 0x10 // Chip Kill ECC + +// +// Row configuration status values +// +#define DUAL_CHANNEL_DDR_ROW_CONFIG_SUCCESS 0x00 // No error +#define DUAL_CHANNEL_DDR_ROW_CONFIG_UNKNOWN 0x01 // Pattern mismatch, no memory +#define DUAL_CHANNEL_DDR_ROW_CONFIG_UNSUPPORTED 0x02 // Memory type not supported +#define DUAL_CHANNEL_DDR_ROW_CONFIG_ADDRESS_ERROR 0x03 // Row/Col/Bnk mismatch +#define DUAL_CHANNEL_DDR_ROW_CONFIG_ECC_ERROR 0x04 // Received ECC error +#define DUAL_CHANNEL_DDR_ROW_CONFIG_NOT_PRESENT 0x05 // Row is not present +#define DUAL_CHANNEL_DDR_ROW_CONFIG_DISABLED 0x06 // Row is disabled + + +// +// Memory range types +// +typedef enum { + DualChannelDdrMainMemory, + DualChannelDdrSmramCacheable, + DualChannelDdrSmramNonCacheable, + DualChannelDdrGraphicsMemoryCacheable, + DualChannelDdrGraphicsMemoryNonCacheable, + DualChannelDdrReservedMemory, + DualChannelDdrMaxMemoryRangeType +} DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE; + +// +// Memory map range information +// +typedef struct { + EFI_PHYSICAL_ADDRESS PhysicalAddress; + EFI_PHYSICAL_ADDRESS CpuAddress; + EFI_PHYSICAL_ADDRESS RangeLength; + DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE Type; +} DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE; +typedef struct { + unsigned dramType :1; /**< Type: 0 = RESERVED; 1 = DDR2 */ + unsigned dramWidth :1; /**< Width: 0 = x8; 1 = x16 */ + unsigned dramDensity :2; /**< Density: 00b = 2Gb; 01b = 1Gb; 10b = 512Mb; 11b = 256Mb */ + unsigned dramSpeed :1; /**< Speed Grade: 0 = RESERVED; 1 = 800MT/s;*/ + unsigned dramTimings :3; /**< Timings: 4-4-4, 5-5-5, 6-6-6 */ + unsigned dramRanks :1; /**< Ranks: 0 = Single Rank; 1 = Dual Rank */ +} DramGeometry; /**< DRAM Geometry Descriptor */ + +typedef union _RegDRP { + UINT32 raw; + struct { + unsigned rank0Enabled :1; /**< Rank 0 Enable */ + unsigned rank0DevWidth :2; /**< DRAM Device Width (x8,x16) */ + unsigned rank0DevDensity :2; /**< DRAM Device Density (256Mb,512Mb,1Gb,2Gb) */ + unsigned reserved2 :1; + unsigned rank1Enabled :1; /**< Rank 1 Enable */ + unsigned reserved3 :5; + unsigned dramType :1; /**< DRAM Type (0=DDR2) */ + unsigned reserved4 :5; + unsigned reserved5 :14; + } field; +} RegDRP; /**< DRAM Rank Population and Interface Register */ + + +typedef union { + UINT32 raw; + struct { + unsigned dramFrequency :3; /**< DRAM Frequency (000=RESERVED,010=667,011=800) */ + unsigned tRP :2; /**< Precharge to Activate Delay (3,4,5,6) */ + unsigned reserved1 :1; + unsigned tRCD :2; /**< Activate to CAS Delay (3,4,5,6) */ + unsigned reserved2 :1; + unsigned tCL :2; /**< CAS Latency (3,4,5,6) */ + unsigned reserved3 :21; + } field; +} RegDTR0; /**< DRAM Timing Register 0 */ + +typedef union { + UINT32 raw; + struct { + unsigned tWRRD_dly :2; /**< Additional Write to Read Delay (0,1,2,3) */ + unsigned reserved1 :1; + unsigned tRDWR_dly :2; /**< Additional Read to Write Delay (0,1,2,3) */ + unsigned reserved2 :1; + unsigned tRDRD_dr_dly :1; /**< Additional Read to Read Delay (1,2) */ + unsigned reserved3 :1; + unsigned tRD_dly :3; /**< Additional Read Data Sampling Delay (0-7) */ + unsigned reserved4 :1; + unsigned tRCVEN_halfclk_dly :4; /**< Additional RCVEN Half Clock Delay Control */ + unsigned reserved5 :1; + unsigned readDqDelay :2; /**< Read DQ Delay */ + unsigned reserved6 :13; + } field; +} RegDTR1; /**< DRAM Timing Register 1 */ + +typedef union { + UINT32 raw; + struct { + unsigned ckStaticDisable :1; /**< CK/CK# Static Disable */ + unsigned reserved1 :3; + unsigned ckeStaticDisable :2; /**< CKE Static Disable */ + unsigned reserved2 :8; + unsigned refreshPeriod :2; /**< Refresh Period (disabled,128clks,3.9us,7.8us) */ + unsigned refreshQueueDepth :2; /**< Refresh Queue Depth (1,2,4,8) */ + unsigned reserved5 :13; + unsigned initComplete :1; /**< Initialization Complete */ + } field; +} RegDCO; + +// +// MRC Data Structure +// +typedef struct { + RegDRP drp; + RegDTR0 dtr0; + RegDTR1 dtr1; + RegDCO dco; + UINT32 reg0104; + UINT32 reg0120; + UINT32 reg0121; + UINT32 reg0123; + UINT32 reg0111; + UINT32 reg0130; + UINT8 refreshPeriod; /**< Placeholder for the chosen refresh + * period. This value will NOT be + * programmed into DCO until all + * initialization is done. + */ + UINT8 ddr2Odt; /**< 0 = Disabled, 1 = 75 ohm, 2 = 150ohm, 3 = 50ohm */ + UINT8 sku; /**< Detected QuarkNcSocId SKU */ + UINT8 capabilities; /**< Capabilities Available on this part */ + UINT8 state; /**< NORMAL_BOOT, S3_RESUME */ + UINT32 memSize; /**< Memory size */ + UINT16 pmBase; /**< PM Base */ + UINT16 mrcVersion; /**< MRC Version */ + UINT32 hecbase; /**< HECBASE shifted left 16 bits */ + DramGeometry geometry; /**< DRAM Geometry */ +} MRC_DATA_STRUCTURE; /**< QuarkNcSocId Memory Parameters for MRC */ + +typedef struct _EFI_MEMINIT_CONFIG_DATA { + MRC_DATA_STRUCTURE MrcData; +} EFI_MEMINIT_CONFIG_DATA; + + + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h new file mode 100644 index 0000000000..8c21640f8c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCBase.h @@ -0,0 +1,17 @@ +/** @file +Public include file for the QNC Base + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __INTEL_QNC_BASE_H__ +#define __INTEL_QNC_BASE_H__ + +#include +#include + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h new file mode 100644 index 0000000000..17c03a1c72 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCConfig.h @@ -0,0 +1,100 @@ +/** @file +Some configuration of QNC Package + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __INTEL_QNC_CONFIG_H__ +#define __INTEL_QNC_CONFIG_H__ + +// +// QNC Fixed configurations. +// + +// +// Memory arbiter fixed config values. +// +#define QNC_FIXED_CONFIG_ASTATUS ((UINT32) (\ + (ASTATUS_PRI_NORMAL << ASTATUS0_DEFAULT_BP) | \ + (ASTATUS_PRI_NORMAL << ASTATUS1_DEFAULT_BP) | \ + (ASTATUS_PRI_URGENT << ASTATUS0_RASISED_BP) | \ + (ASTATUS_PRI_URGENT << ASTATUS1_RASISED_BP) \ + )) + +// +// Memory Manager fixed config values. +// +#define V_DRAM_NON_HOST_RQ_LIMIT 2 + +// +// RMU Thermal config fixed config values for TS in Vref Mode. +// +#define V_TSCGF1_CONFIG_ISNSCURRENTSEL_VREF_MODE 0x04 +#define V_TSCGF2_CONFIG2_ISPARECTRL_VREF_MODE 0x01 +#define V_TSCGF1_CONFIG_IBGEN_VREF_MODE 1 +#define V_TSCGF2_CONFIG_IDSCONTROL_VREF_MODE 0x011b +#define V_TSCGF2_CONFIG2_ICALCOARSETUNE_VREF_MODE 0x34 + +// +// RMU Thermal config fixed config values for TS in Ratiometric mode. +// +#define V_TSCGF1_CONFIG_ISNSCURRENTSEL_RATIO_MODE 0x04 +#define V_TSCGF1_CONFIG_ISNSCHOPSEL_RATIO_MODE 0x02 +#define V_TSCGF1_CONFIG_ISNSINTERNALVREFEN_RATIO_MODE 1 +#define V_TSCGF2_CONFIG_IDSCONTROL_RATIO_MODE 0x011f +#define V_TSCGF2_CONFIG_IDSTIMING_RATIO_MODE 0x0001 +#define V_TSCGF2_CONFIG2_ICALCONFIGSEL_RATIO_MODE 0x01 +#define V_TSCGF2_CONFIG2_ISPARECTRL_RATIO_MODE 0x00 +#define V_TSCGF1_CONFIG_IBGEN_RATIO_MODE 0 +#define V_TSCGF1_CONFIG_IBGCHOPEN_RATIO_MODE 0 +#define V_TSCGF3_CONFIG_ITSGAMMACOEFF_RATIO_MODE 0xC8 +#define V_TSCGF2_CONFIG2_ICALCOARSETUNE_RATIO_MODE 0x17 + +// +// iCLK fixed config values. +// +#define V_MUXTOP_FLEX2 3 +#define V_MUXTOP_FLEX1 1 + +// +// PCIe Root Port fixed config values. +// +#define V_PCIE_ROOT_PORT_SBIC_VALUE (B_QNC_PCIE_IOSFSBCTL_SBIC_IDLE_NEVER) + +// +// QNC structures for configuration. +// + +typedef union { + struct { + UINT32 PortErrorMask :8; + UINT32 SlotImplemented :1; + UINT32 Reserved1 :1; + UINT32 AspmEnable :1; + UINT32 AspmAutoEnable :1; + UINT32 AspmL0sEnable :2; + UINT32 AspmL1Enable :1; + UINT32 PmeInterruptEnable :1; + UINT32 PhysicalSlotNumber :13; + UINT32 Reserved2 :1; + UINT32 PmSciEnable :1; + UINT32 HotplugSciEnable :1; + } Bits; + UINT32 Uint32; +} PCIEXP_ROOT_PORT_CONFIGURATION; + +typedef union { + UINT32 Uint32; + struct { + UINT32 Pcie_0 :1; // 0: Disabled; 1: Enabled* + UINT32 Pcie_1 :1; // 0: Disabled; 1: Enabled* + UINT32 Smbus :1; // 0: Disabled; 1: Enabled* + UINT32 Rsvd :29; // 0 + } Bits; +} QNC_DEVICE_ENABLES; + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h new file mode 100644 index 0000000000..45725a4976 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCDxe.h @@ -0,0 +1,17 @@ +/** @file +Public include file for the QNC Dxe + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __INTEL_QNC_DXE_H__ +#define __INTEL_QNC_DXE_H__ + +#include +#include + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h new file mode 100644 index 0000000000..90cbe35ef9 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCPeim.h @@ -0,0 +1,17 @@ +/** @file +Public include file for the QNC Pei + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __INTEL_QNC_PEIM_H__ +#define __INTEL_QNC_PEIM_H__ + +#include +#include + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h new file mode 100644 index 0000000000..6f6dd8b323 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/IntelQNCRegs.h @@ -0,0 +1,48 @@ +/** @file +Registers definition for Intel QuarkNcSocId. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __INTEL_QNC_REGS_H__ +#define __INTEL_QNC_REGS_H__ + +#include + +// +// PCI HostBridge Segment number +// +#define QNC_PCI_HOST_BRIDGE_SEGMENT_NUMBER 0 + +// +// PCI RootBridge resource allocation's attribute +// +#define QNC_PCI_ROOT_BRIDGE_RESOURCE_ALLOCATION_ATTRIBUTE \ + EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM + +// +// PCI HostBridge resource appeture +// +#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSBASE 0x0 +#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSLIMIT 0xff +#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_TSEG_SIZE 0x10000000 + +// +// PCI RootBridge configure port +// +#define QNC_PCI_ROOT_BRIDGE_CONFIGURATION_ADDRESS_PORT 0xCF8 +#define QNC_PCI_ROOT_BRIDGE_CONFIGURATION_DATA_PORT 0xCFC + +// +// PCI Rootbridge's support feature +// +#define QNC_PCI_ROOT_BRIDGE_SUPPORTED (EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | \ + EFI_PCI_ATTRIBUTE_ISA_IO | \ + EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | \ + EFI_PCI_ATTRIBUTE_VGA_MEMORY | \ + EFI_PCI_ATTRIBUTE_VGA_IO) + +#endif // __INTEL_QNC_REGS_H__ diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h new file mode 100644 index 0000000000..218fa84917 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/IntelQNCLib.h @@ -0,0 +1,284 @@ +/** @file +Library that provides QNC specific library services in PEI phase + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __INTEL_QNC_LIB_H__ +#define __INTEL_QNC_LIB_H__ + +/** + This function initializes the QNC register before MRC. + It sets RCBA, PMBASE, disable Watchdog timer and initialize QNC GPIO. + If the function cannot complete it'll ASSERT(). +**/ +VOID +EFIAPI +PeiQNCPreMemInit ( + VOID + ); + + +/** + Used to check SCH if it's S3 state. Clear the register state after query. + + @retval TRUE if it's S3 state. + @retval FALSE if it's not S3 state. + +**/ +BOOLEAN +EFIAPI +QNCCheckS3AndClearState ( + VOID + ); + +/** + Used to check SCH if system wakes up from power on reset. Clear the register state after query. + + @retval TRUE if system wakes up from power on reset + @retval FALSE if system does not wake up from power on reset + +**/ +BOOLEAN +EFIAPI +QNCCheckPowerOnResetAndClearState ( + VOID + ); + +/** + This function is used to clear SMI and wake status. + +**/ +VOID +EFIAPI +QNCClearSmiAndWake ( + VOID + ); + +/** + Used to initialize the QNC register after MRC. + +**/ +VOID +EFIAPI +PeiQNCPostMemInit ( + VOID + ); + +/** Send DRAM Ready opcode. + + @param[in] OpcodeParam Parameter to DRAM ready opcode. + + @retval VOID +**/ +VOID +EFIAPI +QNCSendOpcodeDramReady ( + IN UINT32 OpcodeParam + ); + +/** + + Relocate RMU Main binary to memory after MRC to improve performance. + + @param[in] DestBaseAddress - Specify the new memory address for the RMU Main binary. + @param[in] SrcBaseAddress - Specify the current memory address for the RMU Main binary. + @param[in] Size - Specify size of the RMU Main binary. + + @retval VOID + +**/ +VOID +EFIAPI +RmuMainRelocation ( + IN CONST UINT32 DestBaseAddress, + IN CONST UINT32 SrcBaseAddress, + IN CONST UINTN Size + ); + +/** + Get the total memory size + +**/ +UINT32 +EFIAPI +QNCGetTotalMemorysize ( + VOID + ); + +/** + Get the memory range of TSEG. + The TSEG's memory is below TOLM. + + @param[out] BaseAddress The base address of TSEG's memory range + @param[out] MemorySize The size of TSEG's memory range + +**/ +VOID +EFIAPI +QNCGetTSEGMemoryRange ( + OUT UINT64 *BaseAddress, + OUT UINT64 *MemorySize + ); + +/** + Updates the PAM registers in the MCH for the requested range and mode. + + @param Start The start address of the memory region + @param Length The length, in bytes, of the memory region + @param ReadEnable Pointer to the boolean variable on whether to enable read for legacy memory section. + If NULL, then read attribute will not be touched by this call. + @param ReadEnable Pointer to the boolean variable on whether to enable write for legacy memory section. + If NULL, then write attribute will not be touched by this call. + @param Granularity A pointer to granularity, in bytes, that the PAM registers support + + @retval RETURN_SUCCESS The PAM registers in the MCH were updated + @retval RETURN_INVALID_PARAMETER The memory range is not valid in legacy region. + +**/ +RETURN_STATUS +EFIAPI +QNCLegacyRegionManipulation ( + IN UINT32 Start, + IN UINT32 Length, + IN BOOLEAN *ReadEnable, + IN BOOLEAN *WriteEnable, + OUT UINT32 *Granularity + ); + +/** + Do early init of pci express rootports on Soc. + +**/ +VOID +EFIAPI +PciExpressEarlyInit ( + VOID + ); + +/** + Complete initialization of all the pci express rootports on Soc. +**/ +EFI_STATUS +EFIAPI +PciExpressInit ( + ); + +/** + Determine if QNC is supported. + + @retval FALSE QNC is not supported. + @retval TRUE QNC is supported. +**/ +BOOLEAN +EFIAPI +IsQncSupported ( + VOID + ); + +/** + Get the DeviceId of the SoC + + @retval PCI DeviceId of the SoC +**/ +UINT16 +EFIAPI +QncGetSocDeviceId ( + VOID + ); + +/** + Enable SMI detection of legacy flash access violations. +**/ +VOID +EFIAPI +QncEnableLegacyFlashAccessViolationSmi ( + VOID + ); + +/** + Setup RMU Thermal sensor registers for Vref mode. +**/ +VOID +EFIAPI +QNCThermalSensorSetVRefMode ( + VOID + ); + +/** + Setup RMU Thermal sensor registers for Ratiometric mode. +**/ +VOID +EFIAPI +QNCThermalSensorSetRatiometricMode ( + VOID + ); + +/** + Setup RMU Thermal sensor trip point values. + + @param[in] CatastrophicTripOnDegreesCelsius - Catastrophic set trip point threshold. + @param[in] HotTripOnDegreesCelsius - Hot set trip point threshold. + @param[in] HotTripOffDegreesCelsius - Hot clear trip point threshold. + + @retval VOID +**/ +EFI_STATUS +EFIAPI +QNCThermalSensorSetTripValues ( + IN CONST UINTN CatastrophicTripOnDegreesCelsius, + IN CONST UINTN HotTripOnDegreesCelsius, + IN CONST UINTN HotTripOffDegreesCelsius + ); + +/** + Enable RMU Thermal sensor with a Catastrophic Trip point. + + @retval EFI_SUCCESS Trip points setup. + @retval EFI_INVALID_PARAMETER Invalid trip point value. + +**/ +EFI_STATUS +EFIAPI +QNCThermalSensorEnableWithCatastrophicTrip ( + IN CONST UINTN CatastrophicTripOnDegreesCelsius + ); + +/** + Lock all RMU Thermal sensor control & trip point registers. + +**/ +VOID +EFIAPI +QNCThermalSensorLockAllRegisters ( + VOID + ); + +/** + Set chipset policy for double bit ECC error. + + @param[in] PolicyValue Policy to config on double bit ECC error. + +**/ +VOID +EFIAPI +QNCPolicyDblEccBitErr ( + IN CONST UINT32 PolicyValue + ); + +/** + Determine if running on secure Quark hardware Sku. + + @retval FALSE Base Quark Sku or unprovisioned Secure Sku running. + @retval TRUE Provisioned SecureSku hardware running. +**/ +BOOLEAN +EFIAPI +QncIsSecureProvisionedSku ( + VOID + ); +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h new file mode 100644 index 0000000000..290902c67f --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCAccessLib.h @@ -0,0 +1,161 @@ +/** @file +Library functions for Setting QNC internal network port + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __QNC_ACCESS_LIB_H__ +#define __QNC_ACCESS_LIB_H__ + +#include + +#define MESSAGE_READ_DW(Port, Reg) \ + (UINT32)((QUARK_OPCODE_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0) + +#define MESSAGE_WRITE_DW(Port, Reg) \ + (UINT32)((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0) + +#define ALT_MESSAGE_READ_DW(Port, Reg) \ + (UINT32)((QUARK_ALT_OPCODE_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0) + +#define ALT_MESSAGE_WRITE_DW(Port, Reg) \ + (UINT32)((QUARK_ALT_OPCODE_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0) + +#define MESSAGE_IO_READ_DW(Port, Reg) \ + (UINT32)((QUARK_OPCODE_IO_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0) + +#define MESSAGE_IO_WRITE_DW(Port, Reg) \ + (UINT32)((QUARK_OPCODE_IO_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0) + +#define MESSAGE_SHADOW_DW(Port, Reg) \ + (UINT32)((QUARK_DRAM_BASE_ADDR_READY << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0) + + +/** + Read required data from QNC internal message network +**/ +UINT32 +EFIAPI +QNCPortRead( + UINT8 Port, + UINT32 RegAddress + ); + +/** + Write prepared data into QNC internal message network. + +**/ +VOID +EFIAPI +QNCPortWrite ( + UINT8 Port, + UINT32 RegAddress, + UINT32 WriteValue + ); + +/** + Read required data from QNC internal message network +**/ +UINT32 +EFIAPI +QNCAltPortRead( + UINT8 Port, + UINT32 RegAddress + ); + +/** + Write prepared data into QNC internal message network. + +**/ +VOID +EFIAPI +QNCAltPortWrite ( + UINT8 Port, + UINT32 RegAddress, + UINT32 WriteValue + ); + +/** + Read required data from QNC internal message network +**/ +UINT32 +EFIAPI +QNCPortIORead( + UINT8 Port, + UINT32 RegAddress + ); + +/** + Write prepared data into QNC internal message network. + +**/ +VOID +EFIAPI +QNCPortIOWrite ( + UINT8 Port, + UINT32 RegAddress, + UINT32 WriteValue + ); + +/** + This is for the special consideration for QNC MMIO write, as required by FWG, + a reading must be performed after MMIO writing to ensure the expected write + is processed and data is flushed into chipset + +**/ +RETURN_STATUS +EFIAPI +QNCMmIoWrite ( + UINT32 MmIoAddress, + QNC_MEM_IO_WIDTH Width, + UINT32 DataNumber, + VOID *pData + ); + +UINT32 +EFIAPI +QncHsmmcRead ( + VOID + ); + +VOID +EFIAPI +QncHsmmcWrite ( + UINT32 WriteValue + ); + +VOID +EFIAPI +QncImrWrite ( + UINT32 ImrBaseOffset, + UINT32 ImrLow, + UINT32 ImrHigh, + UINT32 ImrReadMask, + UINT32 ImrWriteMask + ); + +VOID +EFIAPI +QncIClkAndThenOr ( + UINT32 RegAddress, + UINT32 AndValue, + UINT32 OrValue + ); + +VOID +EFIAPI +QncIClkOr ( + UINT32 RegAddress, + UINT32 OrValue + ); + +UINTN +EFIAPI +QncGetPciExpressBaseAddress ( + VOID + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h new file mode 100644 index 0000000000..a68ecc4566 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Library/QNCSmmLib.h @@ -0,0 +1,57 @@ +/** @file +QNC Smm Library Services header file. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __QNC_SMM_LIB_H__ +#define __QNC_SMM_LIB_H__ + +/** + This routine is the chipset code that accepts a request to "open" a region of SMRAM. + The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory. + The use of "open" means that the memory is visible from all boot-service + and SMM agents. + + @retval FALSE Cannot open a locked SMRAM region + @retval TRUE Success to open SMRAM region. +**/ +BOOLEAN +EFIAPI +QNCOpenSmramRegion ( + VOID + ); + +/** + This routine is the chipset code that accepts a request to "close" a region of SMRAM. + The region could be legacy AB or TSEG near top of physical memory. + The use of "close" means that the memory is only visible from SMM agents, + not from BS or RT code. + + @retval FALSE Cannot open a locked SMRAM region + @retval TRUE Success to open SMRAM region. +**/ +BOOLEAN +EFIAPI +QNCCloseSmramRegion ( + VOID + ); + +/** + This routine is the chipset code that accepts a request to "lock" SMRAM. + The region could be legacy AB or TSEG near top of physical memory. + The use of "lock" means that the memory can no longer be opened + to BS state. +**/ +VOID +EFIAPI +QNCLockSmramRegion ( + VOID + ); + + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h new file mode 100644 index 0000000000..498a42b18b --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Ppi/QNCMemoryInit.h @@ -0,0 +1,36 @@ +/** @file +Memory Initialization PPI used in EFI PEI interface + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __QNC_MEMORY_INIT_H__ +#define __QNC_MEMORY_INIT_H__ + +#include "mrc.h" + +#define PEI_QNC_MEMORY_INIT_PPI_GUID \ + {0x21ff1fee, 0xd33a, 0x4fce, {0xa6, 0x5e, 0x95, 0x5e, 0xa3, 0xc4, 0x1f, 0x40}} + + + + +// +// PPI Function Declarations +// +typedef +VOID +(EFIAPI *PEI_QNC_MEMORY_INIT) ( + IN OUT MRCParams_t *MRCDATA + ); + +typedef struct _PEI_QNC_MEMORY_INIT_PPI { + PEI_QNC_MEMORY_INIT MrcStart; +}PEI_QNC_MEMORY_INIT_PPI; + +extern EFI_GUID gQNCMemoryInitPpiGuid; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h new file mode 100644 index 0000000000..18e7f5c4dd --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PchInfo.h @@ -0,0 +1,48 @@ +/** @file +This file defines the QNC Info Protocol. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ +#ifndef _PCH_INFO_H_ +#define _PCH_INFO_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gEfiQncInfoProtocolGuid; + +// +// Forward reference for ANSI C compatibility +// +typedef struct _EFI_QNC_INFO_PROTOCOL EFI_QNC_INFO_PROTOCOL; + +// +// Protocol revision number +// Any backwards compatible changes to this protocol will result in an update in the revision number +// Major changes will require publication of a new protocol +// +// Revision 1: Original version +// Revision 2: Add RCVersion item to EFI_QNC_INFO_PROTOCOL +// +#define QNC_INFO_PROTOCOL_REVISION_1 1 +#define QNC_INFO_PROTOCOL_REVISION_2 2 + +// +// RCVersion[7:0] is the release number. +// +#define QNC_RC_VERSION 0x01020000 + +// +// Protocol definition +// +struct _EFI_QNC_INFO_PROTOCOL { + UINT8 Revision; + UINT8 BusNumber; + UINT32 RCVersion; +}; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h new file mode 100644 index 0000000000..ad79ae3e87 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/PlatformPolicy.h @@ -0,0 +1,31 @@ +/** @file +Protocol used for Platform Policy definition. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +#ifndef _PLATFORM_POLICY_H_ +#define _PLATFORM_POLICY_H_ + +typedef struct _EFI_PLATFORM_POLICY_PROTOCOL EFI_PLATFORM_POLICY_PROTOCOL; + +#define EFI_PLATFORM_POLICY_PROTOCOL_GUID \ + { \ + 0x2977064f, 0xab96, 0x4fa9, { 0x85, 0x45, 0xf9, 0xc4, 0x02, 0x51, 0xe0, 0x7f } \ + } + +// +// Protocol to describe various platform information. Add to this as needed. +// +struct _EFI_PLATFORM_POLICY_PROTOCOL { + UINT8 NumRsvdSmbusAddresses; + UINT8 *RsvdSmbusAddresses; +}; + +extern EFI_GUID gEfiPlatformPolicyProtocolGuid; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h new file mode 100644 index 0000000000..d9d697d844 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/QncS3Support.h @@ -0,0 +1,84 @@ +/** @file +This file defines the QNC S3 support Protocol. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ +#ifndef _QNC_S3_SUPPORT_PROTOCOL_H_ +#define _QNC_S3_SUPPORT_PROTOCOL_H_ + +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gEfiQncS3SupportProtocolGuid; + +// +// Forward reference for ANSI C compatibility +// +typedef struct _EFI_QNC_S3_SUPPORT_PROTOCOL EFI_QNC_S3_SUPPORT_PROTOCOL; + +typedef enum { + QncS3ItemTypeInitPcieRootPortDownstream, + QncS3ItemTypeMax +} EFI_QNC_S3_DISPATCH_ITEM_TYPE; + +// +// It's better not to use pointer here because the size of pointer in DXE is 8, but it's 4 in PEI +// plug 4 to ParameterSize in PEIM if you really need it +// +typedef struct { + UINT32 Reserved; +} EFI_QNC_S3_PARAMETER_INIT_PCIE_ROOT_PORT_DOWNSTREAM; + +typedef union { + EFI_QNC_S3_PARAMETER_INIT_PCIE_ROOT_PORT_DOWNSTREAM PcieRootPortData; +} EFI_DISPATCH_CONTEXT_UNION; + +typedef struct { + EFI_QNC_S3_DISPATCH_ITEM_TYPE Type; + VOID *Parameter; +} EFI_QNC_S3_DISPATCH_ITEM; + +// +// Member functions +// +typedef +EFI_STATUS +(EFIAPI *EFI_QNC_S3_SUPPORT_SET_S3_DISPATCH_ITEM) ( + IN EFI_QNC_S3_SUPPORT_PROTOCOL * This, + IN EFI_QNC_S3_DISPATCH_ITEM * DispatchItem, + OUT VOID **S3DispatchEntryPoint, + OUT VOID **Context + ); + +/*++ + +Routine Description: + + Set an item to be dispatched at S3 resume time. At the same time, the entry point + of the QNC S3 support image is returned to be used in subsequent boot script save + call + +Arguments: + + This - Pointer to the protocol instance. + DispatchItem - The item to be dispatched. + S3DispatchEntryPoint - The entry point of the QNC S3 support image. + +Returns: + + EFI_STATUS + +--*/ + +// +// Protocol definition +// +struct _EFI_QNC_S3_SUPPORT_PROTOCOL { + EFI_QNC_S3_SUPPORT_SET_S3_DISPATCH_ITEM SetDispatchItem; +}; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h new file mode 100644 index 0000000000..57d919bc5a --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/SmmIchnDispatch2.h @@ -0,0 +1,115 @@ +/** @file +Intel-only SMM Child Dispatcher Protocol. + +This protocol provides a parent dispatch service for a collection of +chipset-specific SMI source. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef __SMM_ICHN_DISPATCH2_H__ +#define __SMM_ICHN_DISPATCH2_H__ + +// +// Share some common definitions with Framework SMM +// +#include + +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h new file mode 100644 index 0000000000..ee549baa9b --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/Protocol/Spi.h @@ -0,0 +1,345 @@ +/** @file +This file defines the EFI SPI Protocol which implements the +Intel(R) ICH SPI Host Controller Compatibility Interface. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ +#ifndef _SPI_H_ +#define _SPI_H_ + +// +// Define the SPI protocol GUID +// +// EDK and EDKII have different GUID formats +// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#define EFI_SPI_PROTOCOL_GUID \ + { \ + 0x1156efc6, 0xea32, 0x4396, 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 \ + } +#define EFI_SMM_SPI_PROTOCOL_GUID \ + { \ + 0xD9072C35, 0xEB8F, 0x43ad, 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 \ + } +#else +#define EFI_SPI_PROTOCOL_GUID \ + { \ + 0x1156efc6, 0xea32, 0x4396, \ + { \ + 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 \ + } \ + } +#define EFI_SMM_SPI_PROTOCOL_GUID \ + { \ + 0xD9072C35, 0xEB8F, 0x43ad, \ + { \ + 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 \ + } \ + } +#endif +// +// Extern the GUID for protocol users. +// +extern EFI_GUID gEfiSpiProtocolGuid; +extern EFI_GUID gEfiSmmSpiProtocolGuid; + +// +// Forward reference for ANSI C compatibility +// +typedef struct _EFI_SPI_PROTOCOL EFI_SPI_PROTOCOL; + +// +// SPI protocol data structures and definitions +// +// +// Number of Prefix Opcodes allowed on the SPI interface +// +#define SPI_NUM_PREFIX_OPCODE 2 + +// +// Number of Opcodes in the Opcode Menu +// +#define SPI_NUM_OPCODE 8 + +#ifdef SERVER_BIOS_FLAG +// +// SPI default opcode slots +// +#define SPI_OPCODE_JEDEC_ID_INDEX 0 +#endif // SERVER_BIOS_FLAG + +// +// Opcode Type +// EnumSpiOpcodeCommand: Command without address +// EnumSpiOpcodeRead: Read with address +// EnumSpiOpcodeWrite: Write with address +// +typedef enum { + EnumSpiOpcodeReadNoAddr, + EnumSpiOpcodeWriteNoAddr, + EnumSpiOpcodeRead, + EnumSpiOpcodeWrite, + EnumSpiOpcodeMax +} SPI_OPCODE_TYPE; + +typedef enum { + EnumSpiCycle20MHz, + EnumSpiCycle33MHz, + EnumSpiCycle66MHz, // not supported by PCH + EnumSpiCycle50MHz, + EnumSpiCycleMax +} SPI_CYCLE_FREQUENCY; + +typedef enum { + EnumSpiRegionAll, + EnumSpiRegionBios, + EnumSpiRegionMe, + EnumSpiRegionGbE, + EnumSpiRegionDescriptor, + EnumSpiRegionPlatformData, + EnumSpiRegionMax +} SPI_REGION_TYPE; + +// +// Hardware Sequencing required operations (as listed in CougarPoint EDS Table 5-55: "Hardware +// Sequencing Commands and Opcode Requirements" +// +typedef enum { + EnumSpiOperationWriteStatus, + EnumSpiOperationProgramData_1_Byte, + EnumSpiOperationProgramData_64_Byte, + EnumSpiOperationReadData, + EnumSpiOperationWriteDisable, + EnumSpiOperationReadStatus, + EnumSpiOperationWriteEnable, + EnumSpiOperationFastRead, + EnumSpiOperationEnableWriteStatus, + EnumSpiOperationErase_256_Byte, + EnumSpiOperationErase_4K_Byte, + EnumSpiOperationErase_8K_Byte, + EnumSpiOperationErase_64K_Byte, + EnumSpiOperationFullChipErase, + EnumSpiOperationJedecId, + EnumSpiOperationDualOutputFastRead, + EnumSpiOperationDiscoveryParameters, + EnumSpiOperationOther, + EnumSpiOperationMax +} SPI_OPERATION; + +// +// Opcode menu entries +// Type Operation Type (value to be programmed to the OPTYPE register) +// Code The opcode (value to be programmed to the OPMENU register) +// Frequency The expected frequency to be used (value to be programmed to the SSFC +// Register) +// Operation Which Hardware Sequencing required operation this opcode respoinds to. +// The required operations are listed in EDS Table 5-55: "Hardware +// Sequencing Commands and Opcode Requirements" +// If the opcode does not corresponds to any operation listed, use +// EnumSpiOperationOther +// +typedef struct _SPI_OPCODE_MENU_ENTRY { + SPI_OPCODE_TYPE Type; + UINT8 Code; + SPI_CYCLE_FREQUENCY Frequency; + SPI_OPERATION Operation; +} SPI_OPCODE_MENU_ENTRY; + +// +// Initialization data table loaded to the SPI host controller +// VendorId Vendor ID of the SPI device +// DeviceId0 Device ID0 of the SPI device +// DeviceId1 Device ID1 of the SPI device +// PrefixOpcode Prefix opcodes which are loaded into the SPI host controller +// OpcodeMenu Opcodes which are loaded into the SPI host controller Opcode Menu +// BiosStartOffset The offset of the start of the BIOS image relative to the flash device. +// Please note this is a Flash Linear Address, NOT a memory space address. +// This value is platform specific and depends on the system flash map. +// This value is only used on non Descriptor mode. +// BiosSize The the BIOS Image size in flash. This value is platform specific +// and depends on the system flash map. Please note BIOS Image size may +// be smaller than BIOS Region size (in Descriptor Mode) or the flash size +// (in Non Descriptor Mode), and in this case, BIOS Image is supposed to be +// placed at the top end of the BIOS Region (in Descriptor Mode) or the flash +// (in Non Descriptor Mode) +// +typedef struct _SPI_INIT_TABLE { + UINT8 VendorId; + UINT8 DeviceId0; + UINT8 DeviceId1; + UINT8 PrefixOpcode[SPI_NUM_PREFIX_OPCODE]; + SPI_OPCODE_MENU_ENTRY OpcodeMenu[SPI_NUM_OPCODE]; + UINTN BiosStartOffset; + UINTN BiosSize; +} SPI_INIT_TABLE; + +// +// Public Info struct to show current initialized state of the spi interface. +// OpcodeIndex must be less then SPI_NUM_OPCODE for operation to be supported. +// +typedef struct _SPI_INIT_INFO { + SPI_INIT_TABLE *InitTable; + UINT8 JedecIdOpcodeIndex; + UINT8 OtherOpcodeIndex; + UINT8 WriteStatusOpcodeIndex; + UINT8 ProgramOpcodeIndex; + UINT8 ReadOpcodeIndex; + UINT8 EraseOpcodeIndex; + UINT8 ReadStatusOpcodeIndex; + UINT8 FullChipEraseOpcodeIndex; +} SPI_INIT_INFO; + +// +// Protocol member functions +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SPI_INIT) ( + IN EFI_SPI_PROTOCOL * This, + IN SPI_INIT_TABLE * InitTable + ); +/*++ + +Routine Description: + + Initializes the host controller to execute SPI commands. + +Arguments: + + This Pointer to the EFI_SPI_PROTOCOL instance. + InitTable Pointer to caller-allocated buffer containing the SPI + interface initialization table. + +Returns: + + EFI_SUCCESS Opcode initialization on the SPI host controller completed. + EFI_ACCESS_DENIED The SPI configuration interface is locked. + EFI_OUT_OF_RESOURCES Not enough resource available to initialize the device. + EFI_DEVICE_ERROR Device error, operation failed. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SPI_LOCK) ( + IN EFI_SPI_PROTOCOL * This + ); +/*++ + +Routine Description: + + Lock the SPI Static Configuration Interface. + Once locked, the interface is no longer open for configuration changes. + The lock state automatically clears on next system reset. + +Arguments: + + This Pointer to the EFI_SPI_PROTOCOL instance. + +Returns: + + EFI_SUCCESS Lock operation succeed. + EFI_DEVICE_ERROR Device error, operation failed. + EFI_ACCESS_DENIED The interface has already been locked. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SPI_EXECUTE) ( + IN EFI_SPI_PROTOCOL * This, + IN UINT8 OpcodeIndex, + IN UINT8 PrefixOpcodeIndex, + IN BOOLEAN DataCycle, + IN BOOLEAN Atomic, + IN BOOLEAN ShiftOut, + IN UINTN Address, + IN UINT32 DataByteCount, + IN OUT UINT8 *Buffer, + IN SPI_REGION_TYPE SpiRegionType + ); +/*++ + +Routine Description: + + Execute SPI commands from the host controller. + +Arguments: + + This Pointer to the EFI_SPI_PROTOCOL instance. + OpcodeIndex Index of the command in the OpCode Menu. + PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence. + DataCycle TRUE if the SPI cycle contains data + Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed. + ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in. + Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform + Region, this value specifies the offset from the Region Base; for BIOS Region, + this value specifies the offset from the start of the BIOS Image. In Non + Descriptor Mode, this value specifies the offset from the start of the BIOS Image. + Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor + Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is + supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or + the flash (in Non Descriptor Mode) + DataByteCount Number of bytes in the data portion of the SPI cycle. + Buffer Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle. + SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe, + EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in + Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode + and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative + to base of the 1st flash device (i.e., it is a Flash Linear Address). + +Returns: + + EFI_SUCCESS Command succeed. + EFI_INVALID_PARAMETER The parameters specified are not valid. + EFI_UNSUPPORTED Command not supported. + EFI_DEVICE_ERROR Device error, command aborts abnormally. + +--*/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SPI_INFO) ( + IN EFI_SPI_PROTOCOL *This, + OUT SPI_INIT_INFO **InitInfoPtr + ); +/*++ + +Routine Description: + + Return info about SPI host controller, to help callers usage of Execute + service. + + If 0xff is returned as an opcode index in init info struct + then device does not support the operation. + +Arguments: + + This Pointer to the EFI_SPI_PROTOCOL instance. + InitInfoPtr Pointer to init info written to this memory location. + +Returns: + + EFI_SUCCESS Information returned. + EFI_INVALID_PARAMETER Invalid parameter. + EFI_NOT_READY Required resources not setup. + Others Unexpected error happened. + +--*/ + +// +// Protocol definition +// +struct _EFI_SPI_PROTOCOL { + EFI_SPI_INIT Init; + EFI_SPI_LOCK Lock; + EFI_SPI_EXECUTE Execute; + EFI_SPI_INFO Info; +}; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h new file mode 100644 index 0000000000..a03454369c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCAccess.h @@ -0,0 +1,177 @@ +/** @file +Macros to simplify and abstract the interface to PCI configuration. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +#ifndef _QNC_ACCESS_H_ +#define _QNC_ACCESS_H_ + +#include "QuarkNcSocId.h" +#include "QNCCommonDefinitions.h" + +#define EFI_LPC_PCI_ADDRESS( Register ) \ + EFI_PCI_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, Register) + +// +// QNC Controller PCI access macros +// +#define QNC_RCRB_BASE (QNCMmio32 (PciDeviceMmBase (0, PCI_DEVICE_NUMBER_QNC_LPC, 0), R_QNC_LPC_RCBA) & B_QNC_LPC_RCBA_MASK) + +// +// Device 0x1f, Function 0 +// + +#define LpcPciCfg32( Register ) \ + QNCMmPci32(0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register ) + +#define LpcPciCfg32Or( Register, OrData ) \ + QNCMmPci32Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData ) + +#define LpcPciCfg32And( Register, AndData ) \ + QNCMmPci32And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData ) + +#define LpcPciCfg32AndThenOr( Register, AndData, OrData ) \ + QNCMmPci32AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData ) + +#define LpcPciCfg16( Register ) \ + QNCMmPci16( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register ) + +#define LpcPciCfg16Or( Register, OrData ) \ + QNCMmPci16Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData ) + +#define LpcPciCfg16And( Register, AndData ) \ + QNCMmPci16And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData ) + +#define LpcPciCfg16AndThenOr( Register, AndData, OrData ) \ + QNCMmPci16AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData ) + +#define LpcPciCfg8( Register ) \ + QNCMmPci8( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register ) + +#define LpcPciCfg8Or( Register, OrData ) \ + QNCMmPci8Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData ) + +#define LpcPciCfg8And( Register, AndData ) \ + QNCMmPci8And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData ) + +#define LpcPciCfg8AndThenOr( Register, AndData, OrData ) \ + QNCMmPci8AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData ) + +// +// Root Complex Register Block +// + +#define MmRcrb32( Register ) \ + QNCMmio32( QNC_RCRB_BASE, Register ) + +#define MmRcrb32Or( Register, OrData ) \ + QNCMmio32Or( QNC_RCRB_BASE, Register, OrData ) + +#define MmRcrb32And( Register, AndData ) \ + QNCMmio32And( QNC_RCRB_BASE, Register, AndData ) + +#define MmRcrb32AndThenOr( Register, AndData, OrData ) \ + QNCMmio32AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData ) + +#define MmRcrb16( Register ) \ + QNCMmio16( QNC_RCRB_BASE, Register ) + +#define MmRcrb16Or( Register, OrData ) \ + QNCMmio16Or( QNC_RCRB_BASE, Register, OrData ) + +#define MmRcrb16And( Register, AndData ) \ + QNCMmio16And( QNC_RCRB_BASE, Register, AndData ) + +#define MmRcrb16AndThenOr( Register, AndData, OrData ) \ + QNCMmio16AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData ) + +#define MmRcrb8( Register ) \ + QNCMmio8( QNC_RCRB_BASE, Register ) + +#define MmRcrb8Or( Register, OrData ) \ + QNCMmio8Or( QNC_RCRB_BASE, Register, OrData ) + +#define MmRcrb8And( Register, AndData ) \ + QNCMmio8And( QNC_RCRB_BASE, Register, AndData ) + +#define MmRcrb8AndThenOr( Register, AndData, OrData ) \ + QNCMmio8AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData ) + +// +// Memory Controller PCI access macros +// + +// +// Device 0, Function 0 +// + +#define McD0PciCfg64(Register) QNCMmPci32 (0, MC_BUS, 0, 0, Register) +#define McD0PciCfg64Or(Register, OrData) QNCMmPci32Or (0, MC_BUS, 0, 0, Register, OrData) +#define McD0PciCfg64And(Register, AndData) QNCMmPci32And (0, MC_BUS, 0, 0, Register, AndData) +#define McD0PciCfg64AndThenOr(Register, AndData, OrData) QNCMmPci32AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData) + +#define McD0PciCfg32(Register) QNCMmPci32 (0, MC_BUS, 0, 0, Register) +#define McD0PciCfg32Or(Register, OrData) QNCMmPci32Or (0, MC_BUS, 0, 0, Register, OrData) +#define McD0PciCfg32And(Register, AndData) QNCMmPci32And (0, MC_BUS, 0, 0, Register, AndData) +#define McD0PciCfg32AndThenOr(Register, AndData, OrData) QNCMmPci32AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData) + +#define McD0PciCfg16(Register) QNCMmPci16 (0, MC_BUS, 0, 0, Register) +#define McD0PciCfg16Or(Register, OrData) QNCMmPci16Or (0, MC_BUS, 0, 0, Register, OrData) +#define McD0PciCfg16And(Register, AndData) QNCMmPci16And (0, MC_BUS, 0, 0, Register, AndData) +#define McD0PciCfg16AndThenOr(Register, AndData, OrData) QNCMmPci16AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData) + +#define McD0PciCfg8(Register) QNCMmPci8 (0, MC_BUS, 0, 0, Register) +#define McD0PciCfg8Or(Register, OrData) QNCMmPci8Or (0, MC_BUS, 0, 0, Register, OrData) +#define McD0PciCfg8And(Register, AndData) QNCMmPci8And (0, MC_BUS, 0, 0, Register, AndData) +#define McD0PciCfg8AndThenOr( Register, AndData, OrData ) QNCMmPci8AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData) + + +// +// Memory Controller Hub Memory Mapped IO register access ??? +// +#define MCH_REGION_BASE (McD0PciCfg64 (MC_MCHBAR_OFFSET) & ~BIT0) +#define McMmioAddress(Register) ((UINTN) MCH_REGION_BASE + (UINTN) (Register)) + +#define McMmio32Ptr(Register) ((volatile UINT32*) McMmioAddress (Register)) +#define McMmio64Ptr(Register) ((volatile UINT64*) McMmioAddress (Register)) + +#define McMmio64(Register) *McMmio64Ptr( Register ) +#define McMmio64Or(Register, OrData) (McMmio64 (Register) |= (UINT64)(OrData)) +#define McMmio64And(Register, AndData) (McMmio64 (Register) &= (UINT64)(AndData)) +#define McMmio64AndThenOr(Register, AndData, OrData) (McMmio64 ( Register ) = (McMmio64( Register ) & (UINT64)(AndData)) | (UINT64)(OrData)) + +#define McMmio32(Register) *McMmio32Ptr (Register) +#define McMmio32Or(Register, OrData) (McMmio32 (Register) |= (UINT32)(OrData)) +#define McMmio32And(Register, AndData) (McMmio32 (Register) &= (UINT32)(AndData)) +#define McMmio32AndThenOr(Register, AndData, OrData) (McMmio32 (Register) = (McMmio32 (Register) & (UINT32) (AndData)) | (UINT32) (OrData)) + +#define McMmio16Ptr(Register) ((volatile UINT16*) McMmioAddress (Register)) +#define McMmio16(Register) *McMmio16Ptr (Register) +#define McMmio16Or(Register, OrData) (McMmio16 (Register) |= (UINT16) (OrData)) +#define McMmio16And(Register, AndData) (McMmio16 (Register) &= (UINT16) (AndData)) +#define McMmio16AndThenOr(Register, AndData, OrData) (McMmio16 (Register) = (McMmio16 (Register) & (UINT16) (AndData)) | (UINT16) (OrData)) + +#define McMmio8Ptr(Register) ((volatile UINT8 *)McMmioAddress (Register)) +#define McMmio8(Register) *McMmio8Ptr (Register) +#define McMmio8Or(Register, OrData) (McMmio8 (Register) |= (UINT8) (OrData)) +#define McMmio8And(Register, AndData) (McMmio8 (Register) &= (UINT8) (AndData)) +#define McMmio8AndThenOr(Register, AndData, OrData) (McMmio8 (Register) = (McMmio8 (Register) & (UINT8) (AndData)) | (UINT8) (OrData)) + +// +// QNC memory mapped related data structure deifinition +// +typedef enum { + QNCMmioWidthUint8 = 0, + QNCMmioWidthUint16 = 1, + QNCMmioWidthUint32 = 2, + QNCMmioWidthUint64 = 3, + QNCMmioWidthMaximum +} QNC_MEM_IO_WIDTH; + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h new file mode 100644 index 0000000000..1e0451302b --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QNCCommonDefinitions.h @@ -0,0 +1,350 @@ +/** @file +This header file provides common definitions just for MCH using to avoid including extra module's file. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _QNC_COMMON_DEFINITIONS_H_ +#define _QNC_COMMON_DEFINITIONS_H_ + +// +// PCI CONFIGURATION MAP REGISTER OFFSETS +// +#ifndef PCI_VID +#define PCI_VID 0x0000 // Vendor ID Register +#define PCI_DID 0x0002 // Device ID Register +#define PCI_CMD 0x0004 // PCI Command Register +#define PCI_STS 0x0006 // PCI Status Register +#define PCI_RID 0x0008 // Revision ID Register +#define PCI_IFT 0x0009 // Interface Type +#define PCI_SCC 0x000A // Sub Class Code Register +#define PCI_BCC 0x000B // Base Class Code Register +#define PCI_CLS 0x000C // Cache Line Size +#define PCI_PMLT 0x000D // Primary Master Latency Timer +#define PCI_HDR 0x000E // Header Type Register +#define PCI_BIST 0x000F // Built in Self Test Register +#define PCI_BAR0 0x0010 // Base Address Register 0 +#define PCI_BAR1 0x0014 // Base Address Register 1 +#define PCI_BAR2 0x0018 // Base Address Register 2 +#define PCI_PBUS 0x0018 // Primary Bus Number Register +#define PCI_SBUS 0x0019 // Secondary Bus Number Register +#define PCI_SUBUS 0x001A // Subordinate Bus Number Register +#define PCI_SMLT 0x001B // Secondary Master Latency Timer +#define PCI_BAR3 0x001C // Base Address Register 3 +#define PCI_IOBASE 0x001C // I/O base Register +#define PCI_IOLIMIT 0x001D // I/O Limit Register +#define PCI_SECSTATUS 0x001E // Secondary Status Register +#define PCI_BAR4 0x0020 // Base Address Register 4 +#define PCI_MEMBASE 0x0020 // Memory Base Register +#define PCI_MEMLIMIT 0x0022 // Memory Limit Register +#define PCI_BAR5 0x0024 // Base Address Register 5 +#define PCI_PRE_MEMBASE 0x0024 // Prefetchable memory Base register +#define PCI_PRE_MEMLIMIT 0x0026 // Prefetchable memory Limit register +#define PCI_PRE_MEMBASE_U 0x0028 // Prefetchable memory base upper 32 bits +#define PCI_PRE_MEMLIMIT_U 0x002C // Prefetchable memory limit upper 32 bits +#define PCI_SVID 0x002C // Subsystem Vendor ID +#define PCI_SID 0x002E // Subsystem ID +#define PCI_IOBASE_U 0x0030 // I/O base Upper Register +#define PCI_IOLIMIT_U 0x0032 // I/O Limit Upper Register +#define PCI_CAPP 0x0034 // Capabilities Pointer +#define PCI_EROM 0x0038 // Expansion ROM Base Address +#define PCI_INTLINE 0x003C // Interrupt Line Register +#define PCI_INTPIN 0x003D // Interrupt Pin Register +#define PCI_MAXGNT 0x003E // Max Grant Register +#define PCI_BRIDGE_CNTL 0x003E // Bridge Control Register +#define PCI_MAXLAT 0x003F // Max Latency Register +#endif +// +// Bit Difinitions +// +#ifndef BIT0 +#define BIT0 0x0001 +#define BIT1 0x0002 +#define BIT2 0x0004 +#define BIT3 0x0008 +#define BIT4 0x0010 +#define BIT5 0x0020 +#define BIT6 0x0040 +#define BIT7 0x0080 +#define BIT8 0x0100 +#define BIT9 0x0200 +#define BIT10 0x0400 +#define BIT11 0x0800 +#define BIT12 0x1000 +#define BIT13 0x2000 +#define BIT14 0x4000 +#define BIT15 0x8000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 +#endif + + +// +// Common Memory mapped Io access macros ------------------------------------------ +// +#define QNCMmioAddress( BaseAddr, Register ) \ + ( (UINTN)BaseAddr + \ + (UINTN)(Register) \ + ) + +// +// UINT64 +// +#define QNCMmio64Ptr( BaseAddr, Register ) \ + ( (volatile UINT64 *)QNCMmioAddress( BaseAddr, Register ) ) + +#define QNCMmio64( BaseAddr, Register ) \ + *QNCMmio64Ptr( BaseAddr, Register ) + +#define QNCMmio64Or( BaseAddr, Register, OrData ) \ + QNCMmio64( BaseAddr, Register ) = \ + (UINT64) ( \ + QNCMmio64( BaseAddr, Register ) | \ + (UINT64)(OrData) \ + ) + +#define QNCMmio64And( BaseAddr, Register, AndData ) \ + QNCMmio64( BaseAddr, Register ) = \ + (UINT64) ( \ + QNCMmio64( BaseAddr, Register ) & \ + (UINT64)(AndData) \ + ) + +#define QNCMmio64AndThenOr( BaseAddr, Register, AndData, OrData ) \ + QNCMmio64( BaseAddr, Register ) = \ + (UINT64) ( \ + ( QNCMmio64( BaseAddr, Register ) & \ + (UINT64)(AndData) \ + ) | \ + (UINT64)(OrData) \ + ) + +// +// UINT32 +// +#define QNCMmio32Ptr( BaseAddr, Register ) \ + ( (volatile UINT32 *)QNCMmioAddress( BaseAddr, Register ) ) + +#define QNCMmio32( BaseAddr, Register ) \ + *QNCMmio32Ptr( BaseAddr, Register ) + +#define QNCMmio32Or( BaseAddr, Register, OrData ) \ + QNCMmio32( BaseAddr, Register ) = \ + (UINT32) ( \ + QNCMmio32( BaseAddr, Register ) | \ + (UINT32)(OrData) \ + ) + +#define QNCMmio32And( BaseAddr, Register, AndData ) \ + QNCMmio32( BaseAddr, Register ) = \ + (UINT32) ( \ + QNCMmio32( BaseAddr, Register ) & \ + (UINT32)(AndData) \ + ) + +#define QNCMmio32AndThenOr( BaseAddr, Register, AndData, OrData ) \ + QNCMmio32( BaseAddr, Register ) = \ + (UINT32) ( \ + ( QNCMmio32( BaseAddr, Register ) & \ + (UINT32)(AndData) \ + ) | \ + (UINT32)(OrData) \ + ) +// +// UINT16 +// + +#define QNCMmio16Ptr( BaseAddr, Register ) \ + ( (volatile UINT16 *)QNCMmioAddress( BaseAddr, Register ) ) + +#define QNCMmio16( BaseAddr, Register ) \ + *QNCMmio16Ptr( BaseAddr, Register ) + +#define QNCMmio16Or( BaseAddr, Register, OrData ) \ + QNCMmio16( BaseAddr, Register ) = \ + (UINT16) ( \ + QNCMmio16( BaseAddr, Register ) | \ + (UINT16)(OrData) \ + ) + +#define QNCMmio16And( BaseAddr, Register, AndData ) \ + QNCMmio16( BaseAddr, Register ) = \ + (UINT16) ( \ + QNCMmio16( BaseAddr, Register ) & \ + (UINT16)(AndData) \ + ) + +#define QNCMmio16AndThenOr( BaseAddr, Register, AndData, OrData ) \ + QNCMmio16( BaseAddr, Register ) = \ + (UINT16) ( \ + ( QNCMmio16( BaseAddr, Register ) & \ + (UINT16)(AndData) \ + ) | \ + (UINT16)(OrData) \ + ) +// +// UINT8 +// +#define QNCMmio8Ptr( BaseAddr, Register ) \ + ( (volatile UINT8 *)QNCMmioAddress( BaseAddr, Register ) ) + +#define QNCMmio8( BaseAddr, Register ) \ + *QNCMmio8Ptr( BaseAddr, Register ) + +#define QNCMmio8Or( BaseAddr, Register, OrData ) \ + QNCMmio8( BaseAddr, Register ) = \ + (UINT8) ( \ + QNCMmio8( BaseAddr, Register ) | \ + (UINT8)(OrData) \ + ) + +#define QNCMmio8And( BaseAddr, Register, AndData ) \ + QNCMmio8( BaseAddr, Register ) = \ + (UINT8) ( \ + QNCMmio8( BaseAddr, Register ) & \ + (UINT8)(AndData) \ + ) + +#define QNCMmio8AndThenOr( BaseAddr, Register, AndData, OrData ) \ + QNCMmio8( BaseAddr, Register ) = \ + (UINT8) ( \ + ( QNCMmio8( BaseAddr, Register ) & \ + (UINT8)(AndData) \ + ) | \ + (UINT8)(OrData) \ + ) + +// +// Common Memory mapped Pci access macros ------------------------------------------ +// + +#define QNCMmPciAddress( Segment, Bus, Device, Function, Register ) \ + ( (UINTN) QncGetPciExpressBaseAddress() + \ + (UINTN)(Bus << 20) + \ + (UINTN)(Device << 15) + \ + (UINTN)(Function << 12) + \ + (UINTN)(Register) \ + ) + +// +// Macro to calculate the Pci device's base memory mapped address +// +#define PciDeviceMmBase( Bus, Device, Function) \ + ( (UINTN) QncGetPciExpressBaseAddress () + \ + (UINTN)(Bus << 20) + \ + (UINTN)(Device << 15) + \ + (UINTN)(Function << 12) \ + ) + +// +// UINT32 +// +#define QNCMmPci32Ptr( Segment, Bus, Device, Function, Register ) \ + ( (volatile UINT32 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) ) + +#define QNCMmPci32( Segment, Bus, Device, Function, Register ) \ + *QNCMmPci32Ptr( Segment, Bus, Device, Function, Register ) + +#define QNCMmPci32Or( Segment, Bus, Device, Function, Register, OrData ) \ + QNCMmPci32( Segment, Bus, Device, Function, Register ) = \ + (UINT32) ( \ + QNCMmPci32( Segment, Bus, Device, Function, Register ) | \ + (UINT32)(OrData) \ + ) + +#define QNCMmPci32And( Segment, Bus, Device, Function, Register, AndData ) \ + QNCMmPci32( Segment, Bus, Device, Function, Register ) = \ + (UINT32) ( \ + QNCMmPci32( Segment, Bus, Device, Function, Register ) & \ + (UINT32)(AndData) \ + ) + +#define QNCMmPci32AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \ + QNCMmPci32( Segment, Bus, Device, Function, Register ) = \ + (UINT32) ( \ + ( QNCMmPci32( Segment, Bus, Device, Function, Register ) & \ + (UINT32)(AndData) \ + ) | \ + (UINT32)(OrData) \ + ) +// +// UINT16 +// +#define QNCMmPci16Ptr( Segment, Bus, Device, Function, Register ) \ + ( (volatile UINT16 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) ) + +#define QNCMmPci16( Segment, Bus, Device, Function, Register ) \ + *QNCMmPci16Ptr( Segment, Bus, Device, Function, Register ) + +#define QNCMmPci16Or( Segment, Bus, Device, Function, Register, OrData ) \ + QNCMmPci16( Segment, Bus, Device, Function, Register ) = \ + (UINT16) ( \ + QNCMmPci16( Segment, Bus, Device, Function, Register ) | \ + (UINT16)(OrData) \ + ) + +#define QNCMmPci16And( Segment, Bus, Device, Function, Register, AndData ) \ + QNCMmPci16( Segment, Bus, Device, Function, Register ) = \ + (UINT16) ( \ + QNCMmPci16( Segment, Bus, Device, Function, Register ) & \ + (UINT16)(AndData) \ + ) + +#define QNCMmPci16AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \ + QNCMmPci16( Segment, Bus, Device, Function, Register ) = \ + (UINT16) ( \ + ( QNCMmPci16( Segment, Bus, Device, Function, Register ) & \ + (UINT16)(AndData) \ + ) | \ + (UINT16)(OrData) \ + ) +// +// UINT8 +// +#define QNCMmPci8Ptr( Segment, Bus, Device, Function, Register ) \ + ( (volatile UINT8 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) ) + +#define QNCMmPci8( Segment, Bus, Device, Function, Register ) \ + *QNCMmPci8Ptr( Segment, Bus, Device, Function, Register ) + +#define QNCMmPci8Or( Segment, Bus, Device, Function, Register, OrData ) \ + QNCMmPci8( Segment, Bus, Device, Function, Register ) = \ + (UINT8) ( \ + QNCMmPci8( Segment, Bus, Device, Function, Register ) | \ + (UINT8)(OrData) \ + ) + +#define QNCMmPci8And( Segment, Bus, Device, Function, Register, AndData ) \ + QNCMmPci8( Segment, Bus, Device, Function, Register ) = \ + (UINT8) ( \ + QNCMmPci8( Segment, Bus, Device, Function, Register ) & \ + (UINT8)(AndData) \ + ) + +#define QNCMmPci8AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \ + QNCMmPci8( Segment, Bus, Device, Function, Register ) = \ + (UINT8) ( \ + ( QNCMmPci8( Segment, Bus, Device, Function, Register ) & \ + (UINT8)(AndData) \ + ) | \ + (UINT8)(OrData) \ + ) + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h new file mode 100644 index 0000000000..33aab21f1d --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Include/QuarkNcSocId.h @@ -0,0 +1,751 @@ +/** @file +QuarkNcSocId Register Definitions + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +Definitions beginning with "R_" are registers +Definitions beginning with "B_" are bits within registers +Definitions beginning with "V_" are meaningful values of bits within the registers +Definitions beginning with "S_" are register sizes +Definitions beginning with "N_" are the bit position + +**/ + +#ifndef _QUARK_NC_SOC_ID_H_ +#define _QUARK_NC_SOC_ID_H_ + +// +// QNC GMCH Equates +// + +// +// DEVICE 0 (Memroy Controller Hub) +// +#define MC_BUS PCI_BUS_NUMBER_QNC +#define MC_DEV 0x00 +#define MC_FUN 0x00 + +#define QUARK_MC_VENDOR_ID V_INTEL_VENDOR_ID +#define QUARK_MC_DEVICE_ID 0x0958 +#define QUARK2_MC_DEVICE_ID 0x12C0 +#define QNC_MC_REV_ID_A0 0x00 + + +// +// MCR - B0:D0:F0:RD0h (WO)- Message control register +// [31:24] Message opcode - D0 read; E0 write; +// [23:16] Message port +// [15:8 ] Message target register address +// [ 7:4 ] Message write byte enable : F is enable +// [ 3:0 ] Reserved +// +#define QNC_ACCESS_PORT_MCR 0xD0 // Message Control Register +// Always Set to 0xF0 + +// +//MDR - B0:D0:F0:RD4h (RW)- Message data register +// +#define QNC_ACCESS_PORT_MDR 0xD4 // Message Data Register + +// +//MEA - B0:D0:F0:RD8h (RW)- Message extended address register +// +#define QNC_ACCESS_PORT_MEA 0xD8 // Message Extended Address Register + +#define QNC_MCR_OP_OFFSET 24 // Offset of the opcode field in MCR +#define QNC_MCR_PORT_OFFSET 16 // Offset of the port field in MCR +#define QNC_MCR_REG_OFFSET 8 // Offset of the register field in MCR + +// +// Misc Useful Macros +// + +#define LShift16(value) (value << 16) + +// +// QNC Message OpCodes and Attributes +// +#define QUARK_OPCODE_READ 0x10 // Quark message bus "read" opcode +#define QUARK_OPCODE_WRITE 0x11 // Quark message bus "write" opcode + +// +// Alternative opcodes for the SCSS block +// +#define QUARK_ALT_OPCODE_READ 0x06 // Quark message bus "read" opcode +#define QUARK_ALT_OPCODE_WRITE 0x07 // Quark message bus "write" opcode + +// +// QNC Message OpCodes and Attributes for IO +// +#define QUARK_OPCODE_IO_READ 0x02 // Quark message bus "IO read" opcode +#define QUARK_OPCODE_IO_WRITE 0x03 // Quark message bus "IO write" opcode + + +#define QUARK_DRAM_BASE_ADDR_READY 0x78 // Quark message bus "RMU Main binary shadow" opcode + +#define QUARK_ECC_SCRUB_RESUME 0xC2 // Quark Remote Management Unit "scrub resume" opcode +#define QUARK_ECC_SCRUB_PAUSE 0xC3 // Quark Remote Management Unit "scrub pause" opcode + +// +// QNC Message Ports and Registers +// +// Start of SB Port IDs +#define QUARK_NC_MEMORY_ARBITER_SB_PORT_ID 0x00 +#define QUARK_NC_MEMORY_CONTROLLER_SB_PORT_ID 0x01 +#define QUARK_NC_HOST_BRIDGE_SB_PORT_ID 0x03 +#define QUARK_NC_RMU_SB_PORT_ID 0x04 +#define QUARK_NC_MEMORY_MANAGER_SB_PORT_ID 0x05 +#define QUARK_SC_USB_AFE_SB_PORT_ID 0x14 +#define QUARK_SC_PCIE_AFE_SB_PORT_ID 0x16 +#define QUARK_SCSS_SOC_UNIT_SB_PORT_ID 0x31 +#define QUARK_SCSS_FUSE_SB_PORT_ID 0x33 +#define QUARK_ICLK_SB_PORT_ID 0x32 +#define QUARK_SCSS_CRU_SB_PORT_ID 0x34 + +// +// Quark Memory Arbiter Registers. +// +#define QUARK_NC_MEMORY_ARBITER_REG_ASTATUS 0x21 // Memory Arbiter PRI Status encodings register. +#define ASTATUS_PRI_CASUAL 0x0 // Serviced only if convenient +#define ASTATUS_PRI_IMPENDING 0x1 // Serviced if the DRAM is in Self-Refresh. +#define ASTATUS_PRI_NORMAL 0x2 // Normal request servicing. +#define ASTATUS_PRI_URGENT 0x3 // Urgent request servicing. +#define ASTATUS1_RASISED_BP (10) +#define ASTATUS1_RASISED_BP_MASK (0x03 << ASTATUS1_RASISED_BP) +#define ASTATUS0_RASISED_BP (8) +#define ASTATUS0_RASISED_BP_MASK (0x03 << ASTATUS1_RASISED_BP) +#define ASTATUS1_DEFAULT_BP (2) +#define ASTATUS1_DEFAULT_BP_MASK (0x03 << ASTATUS1_RASISED_BP) +#define ASTATUS0_DEFAULT_BP (0) +#define ASTATUS0_DEFAULT_BP_MASK (0x03 << ASTATUS1_RASISED_BP) + +// +// Quark Memory Controller Registers. +// +#define QUARK_NC_MEMORY_CONTROLLER_REG_DFUSESTAT 0x70 // Fuse status register. +#define B_DFUSESTAT_ECC_DIS (BIT0) // Disable ECC. + +// +// Quark Remote Management Unit Registers. +// +#define QNC_MSG_TMPM_REG_PMBA 0x70 // Power Management I/O Base Address + +#define QUARK_NC_RMU_REG_CONFIG 0x71 // Remote Management Unit configuration register. +#define TS_LOCK_AUX_TRIP_PT_REGS_ENABLE (BIT6) +#define TS_LOCK_THRM_CTRL_REGS_ENABLE (BIT5) + +#define QUARK_NC_RMU_REG_OPTIONS_1 0x72 // Remote Management Unit Options register 1. +#define OPTIONS_1_DMA_DISABLE (BIT0) + +#define QUARK_NC_RMU_REG_WDT_CONTROL 0x74 // Remote Management Unit Watchdog control register. +#define B_WDT_CONTROL_DBL_ECC_BIT_ERR_MASK (BIT19 | BIT18) +#define B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP 18 +#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_NONE (0x0 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP) +#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_CAT (0x1 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP) +#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_WARM (0x2 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP) +#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_SERR (0x3 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP) + +#define QUARK_NC_RMU_REG_TS_MODE 0xB0 // Remote Management Unit Thermal sensor mode register. +#define TS_ENABLE (BIT15) +#define QUARK_NC_RMU_REG_TS_TRIP 0xB2 // Remote Management Unit Thermal sensor programmable trip point register. +#define TS_HOT_TRIP_CLEAR_THOLD_BP 24 +#define TS_HOT_TRIP_CLEAR_THOLD_MASK (0xFF << TS_HOT_TRIP_CLEAR_THOLD_BP) +#define TS_CAT_TRIP_CLEAR_THOLD_BP 16 +#define TS_CAT_TRIP_CLEAR_THOLD_MASK (0xFF << TS_CAT_TRIP_CLEAR_THOLD_BP) +#define TS_HOT_TRIP_SET_THOLD_BP 8 +#define TS_HOT_TRIP_SET_THOLD_MASK (0xFF << TS_HOT_TRIP_SET_THOLD_BP) +#define TS_CAT_TRIP_SET_THOLD_BP 0 +#define TS_CAT_TRIP_SET_THOLD_MASK (0xFF << TS_CAT_TRIP_SET_THOLD_BP) + +#define QUARK_NC_ECC_SCRUB_CONFIG_REG 0x50 +#define SCRUB_CFG_INTERVAL_SHIFT 0x00 +#define SCRUB_CFG_INTERVAL_MASK 0xFF +#define SCRUB_CFG_BLOCKSIZE_SHIFT 0x08 +#define SCRUB_CFG_BLOCKSIZE_MASK 0x1F +#define SCRUB_CFG_ACTIVE (BIT13) +#define SCRUB_CFG_INVALID 0x00000FFF + +#define QUARK_NC_ECC_SCRUB_START_MEM_REG 0x76 +#define QUARK_NC_ECC_SCRUB_END_MEM_REG 0x77 +#define QUARK_NC_ECC_SCRUB_NEXT_READ_REG 0x7C + +#define SCRUB_RESUME_MSG() ((UINT32)( \ + (QUARK_ECC_SCRUB_RESUME << QNC_MCR_OP_OFFSET) | \ + (QUARK_NC_RMU_SB_PORT_ID << QNC_MCR_PORT_OFFSET) | \ + 0xF0)) + +#define SCRUB_PAUSE_MSG() ((UINT32)( \ + (QUARK_ECC_SCRUB_PAUSE << QNC_MCR_OP_OFFSET) | \ + (QUARK_NC_RMU_SB_PORT_ID << QNC_MCR_PORT_OFFSET) | \ + 0xF0)) + +// +// Quark Memory Manager Registers +// +#define QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK 0x82 +#define BLOCK_ENABLE_PG (1 << 28) +#define BLOCK_DISABLE_PG (1 << 29) +#define QUARK_NC_MEMORY_MANAGER_BIMRVCTL 0x19 +#define EnableIMRInt BIT31 +#define QUARK_NC_MEMORY_MANAGER_BSMMVCTL 0x1C +#define EnableSMMInt BIT31 +#define QUARK_NC_MEMORY_MANAGER_BTHCTRL 0x20 +#define DRAM_NON_HOST_RQ_LIMIT_BP 0 +#define DRAM_NON_HOST_RQ_LIMIT_MASK (0x3f << DRAM_NON_HOST_RQ_LIMIT_BP) + +#define QUARK_NC_TOTAL_IMR_SET 0x8 +#define QUARK_NC_MEMORY_MANAGER_IMR0 0x40 +#define QUARK_NC_MEMORY_MANAGER_IMR1 0x44 +#define QUARK_NC_MEMORY_MANAGER_IMR2 0x48 +#define QUARK_NC_MEMORY_MANAGER_IMR3 0x4C +#define QUARK_NC_MEMORY_MANAGER_IMR4 0x50 +#define QUARK_NC_MEMORY_MANAGER_IMR5 0x54 +#define QUARK_NC_MEMORY_MANAGER_IMR6 0x58 +#define QUARK_NC_MEMORY_MANAGER_IMR7 0x5C + #define QUARK_NC_MEMORY_MANAGER_IMRXL 0x00 + #define IMR_LOCK BIT31 + #define IMR_EN BIT30 + #define IMRL_MASK 0x00FFFFFC + #define IMRL_RESET 0x00000000 + #define QUARK_NC_MEMORY_MANAGER_IMRXH 0x01 + #define IMRH_MASK 0x00FFFFFC + #define IMRH_RESET 0x00000000 + #define QUARK_NC_MEMORY_MANAGER_IMRXRM 0x02 + #define QUARK_NC_MEMORY_MANAGER_IMRXWM 0x03 + #define IMRX_ALL_ACCESS 0xFFFFFFFF + #define CPU_SNOOP BIT30 + #define RMU BIT29 + #define CPU0_NON_SMM BIT0 + +// +// Quark Host Bridge Registers +// +#define QNC_MSG_FSBIC_REG_HMISC 0x03 // Host Misellaneous Controls +#define SMI_EN (BIT19) // SMI Global Enable (from Legacy Bridge) +#define QNC_MSG_FSBIC_REG_HSMMC 0x04 // Host SMM Control +#define NON_HOST_SMM_WR_OPEN (BIT18) // SMM Writes OPEN +#define NON_HOST_SMM_RD_OPEN (BIT17) // SMM Writes OPEN +#define SMM_CODE_RD_OPEN (BIT16) // SMM Code read OPEN +#define SMM_CTL_EN (BIT3) // SMM enable +#define SMM_WRITE_OPEN (BIT2) // SMM Writes OPEN +#define SMM_READ_OPEN (BIT1) // SMM Reads OPEN +#define SMM_LOCKED (BIT0) // SMM Locked +#define SMM_START_MASK 0x0000FFF0 +#define SMM_END_MASK 0xFFF00000 +#define QUARK_NC_HOST_BRIDGE_HMBOUND_REG 0x08 +#define HMBOUND_MASK 0x0FFFFF000 +#define HMBOUND_LOCK BIT0 +#define QUARK_NC_HOST_BRIDGE_HLEGACY_REG 0x0A +#define HLEGACY_SMI_PIN_VALUE BIT12 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP 0x40 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE 0x41 +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 0x42 +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000 0x44 +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_A0000 0x46 +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C0000 0x48 +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C8000 0x4A +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D0000 0x4C +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D8000 0x4E +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E0000 0x50 +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E8000 0x52 +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F0000 0x54 +#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000 0x56 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSBASE 0x58 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK 0x59 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 0x5A +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK0 0x5B +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE1 0x5C +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK1 0x5D +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE2 0x5E +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK2 0x5F +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE3 0x60 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK3 0x61 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE4 0x62 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK4 0x63 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE5 0x64 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK5 0x65 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE6 0x66 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK6 0x67 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE7 0x68 +#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK7 0x69 + +// +// System On Chip Unit (SOCUnit) Registers. +// +#define QUARK_SCSS_SOC_UNIT_STPDDRCFG 0x00 +#define B_STPDDRCFG_FORCE_RECOVERY BIT0 +#define QUARK_SCSS_SOC_UNIT_SPI_ROM_FUSE 0x25 +#define B_ROM_FUSE_IN_SECURE_SKU BIT6 + +#define QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG 0x31 +#define B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK (BIT5 | BIT4 | BIT3) +#define B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP 3 +#define B_TSCGF1_CONFIG_ISNSCHOPSEL_MASK (BIT12 | BIT11 | BIT10 | BIT9 | BIT8) +#define B_TSCGF1_CONFIG_ISNSCHOPSEL_BP 8 +#define B_TSCGF1_CONFIG_IBGEN BIT17 +#define B_TSCGF1_CONFIG_IBGEN_BP 17 +#define B_TSCGF1_CONFIG_IBGCHOPEN BIT18 +#define B_TSCGF1_CONFIG_IBGCHOPEN_BP 18 +#define B_TSCGF1_CONFIG_ISNSINTERNALVREFEN BIT14 +#define B_TSCGF1_CONFIG_ISNSINTERNALVREFEN_BP 14 + +#define QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG 0x32 +#define B_TSCGF2_CONFIG_IDSCONTROL_MASK 0x0000FFFF +#define B_TSCGF2_CONFIG_IDSCONTROL_BP 0 +#define B_TSCGF2_CONFIG_IDSTIMING_MASK 0xFFFF0000 +#define B_TSCGF2_CONFIG_IDSTIMING_BP 16 + +#define QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2 0x33 +#define B_TSCGF2_CONFIG2_ISPARECTRL_MASK 0xFF000000 +#define B_TSCGF2_CONFIG2_ISPARECTRL_BP 24 +#define B_TSCGF2_CONFIG2_ICALCONFIGSEL_MASK (BIT9 | BIT8) +#define B_TSCGF2_CONFIG2_ICALCONFIGSEL_BP 8 +#define B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK 0x000000FF +#define B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP 0 + +#define QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG 0x34 +#define B_TSCGF3_CONFIG_ITSRST BIT0 +#define B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP 11 +#define B_TSCGF3_CONFIG_ITSGAMMACOEFF_MASK (0xFFF << B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP) + +#define QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG 0x36 +#define SOCCLKEN_CONFIG_PHY_I_SIDE_RST_L BIT20 +#define SOCCLKEN_CONFIG_PHY_I_CMNRESET_L BIT19 +#define SOCCLKEN_CONFIG_SBI_BB_RST_B BIT18 +#define SOCCLKEN_CONFIG_SBI_RST_100_CORE_B BIT17 +#define SOCCLKEN_CONFIG_BB_RST_B BIT16 + +#define QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG 0x36 + +#define QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW 0x51 +#define B_CFG_STICKY_RW_SMM_VIOLATION BIT0 +#define B_CFG_STICKY_RW_HMB_VIOLATION BIT1 +#define B_CFG_STICKY_RW_IMR_VIOLATION BIT2 +#define B_CFG_STICKY_RW_DECC_VIOLATION BIT3 +#define B_CFG_STICKY_RW_WARM_RST BIT4 +#define B_CFG_STICKY_RW_FORCE_RECOVERY BIT9 +#define B_CFG_STICKY_RW_VIOLATION (B_CFG_STICKY_RW_SMM_VIOLATION | B_CFG_STICKY_RW_HMB_VIOLATION | B_CFG_STICKY_RW_IMR_VIOLATION | B_CFG_STICKY_RW_DECC_VIOLATION) +#define B_CFG_STICKY_RW_ALL (B_CFG_STICKY_RW_VIOLATION | B_CFG_STICKY_RW_WARM_RST) + +// +// iCLK Registers. +// +#define QUARK_ICLK_MUXTOP 0x0140 +#define B_MUXTOP_FLEX2_MASK (BIT25 | BIT24 | BIT23) +#define B_MUXTOP_FLEX2_BP 23 +#define B_MUXTOP_FLEX1_MASK (BIT22 | BIT21 | BIT20) +#define B_MUXTOP_FLEX1_BP 20 + +#define QUARK_ICLK_SSC1 0x0314 +#define QUARK_ICLK_SSC2 0x0414 +#define QUARK_ICLK_SSC3 0x0514 +#define QUARK_ICLK_REF2_DBUFF0 0x2000 + +// +// PCIe AFE Unit Registers (QUARK_SC_PCIE_AFE_SB_PORT_ID). +// +#define QUARK_PCIE_AFE_PCIE_RXPICTRL0_L0 0x2080 +#define QUARK_PCIE_AFE_PCIE_RXPICTRL0_L1 0x2180 +#define OCFGPIMIXLOAD_1_0 BIT6 +#define OCFGPIMIXLOAD_1_0_MASK 0xFFFFFF3F + +// +// QNC ICH Equates +// +#define V_INTEL_VENDOR_ID 0x8086 + +#define PCI_BUS_NUMBER_QNC 0x00 + +// +// PCI to LPC Bridge Registers (D31:F0) +// +#define PCI_DEVICE_NUMBER_QNC_LPC 31 +#define PCI_FUNCTION_NUMBER_QNC_LPC 0 + +#define R_QNC_LPC_VENDOR_ID 0x00 +#define V_LPC_VENDOR_ID V_INTEL_VENDOR_ID +#define R_QNC_LPC_DEVICE_ID 0x02 +#define QUARK_V_LPC_DEVICE_ID_0 0x095E +#define R_QNC_LPC_REV_ID 0x08 + +#define R_QNC_LPC_SMBUS_BASE 0x40 //~0x43 +#define B_QNC_LPC_SMBUS_BASE_EN (BIT31) +#define B_QNC_LPC_SMBUS_BASE_MASK 0x0000FFC0 //[15:6] +// +// SMBus register offsets from SMBA - "SMBA" (D31:F0:R40h) +// Suggested Value for SMBA = 0x1040 +// +#define R_QNC_SMBUS_HCTL 0x00 // Host Control Register R/W +#define B_QNC_SMBUS_START (BIT4) // Start/Stop +#define V_QNC_SMBUS_HCTL_CMD_QUICK 0 +#define V_QNC_SMBUS_HCTL_CMD_BYTE 1 +#define V_QNC_SMBUS_HCTL_CMD_BYTE_DATA 2 +#define V_QNC_SMBUS_HCTL_CMD_WORD_DATA 3 +#define V_QNC_SMBUS_HCTL_CMD_PROCESS_CALL 4 +#define V_QNC_SMBUS_HCTL_CMD_BLOCK 5 + +#define R_QNC_SMBUS_HSTS 0x01 // Host Status Register R/W +#define B_QNC_SMBUS_BERR (BIT2) // BUS Error +#define B_QNC_SMBUS_DERR (BIT1) // Device Error +#define B_QNC_SMBUS_BYTE_DONE_STS (BIT0) // Completion Status +#define B_QNC_SMBUS_HSTS_ALL 0x07 + +#define R_QNC_SMBUS_HCLK 0x02 // Host Clock Divider Register R/W +#define V_QNC_SMBUS_HCLK_100KHZ 0x0054 + +#define R_QNC_SMBUS_TSA 0x04 // Transmit Slave Address Register R/W +#define V_QNC_SMBUS_RW_SEL_READ 1 +#define V_QNC_SMBUS_RW_SEL_WRITE 0 + +#define R_QNC_SMBUS_HCMD 0x05 // Host Command Register R/W +#define R_QNC_SMBUS_HD0 0x06 // Data 0 Register R/W +#define R_QNC_SMBUS_HD1 0x07 // Data 1 Register R/W +#define R_QNC_SMBUS_HBD 0x20 // Host Block Data Register R/W [255:0] ~ 3Fh + +#define R_QNC_LPC_GBA_BASE 0x44 +#define B_QNC_LPC_GPA_BASE_MASK 0x0000FFC0 +// +// GPIO register offsets from GBA - "GPIO" (D31:F0:R44h) +// Suggested Value for GBA = 0x1080 +// +#define R_QNC_GPIO_CGEN_CORE_WELL 0x00 +#define R_QNC_GPIO_CGIO_CORE_WELL 0x04 +#define R_QNC_GPIO_CGLVL_CORE_WELL 0x08 +#define R_QNC_GPIO_CGTPE_CORE_WELL 0x0C // Core well GPIO Trigger Positive Edge Enable +#define R_QNC_GPIO_CGTNE_CORE_WELL 0x10 // Core well GPIO Trigger Negative Edge Enable +#define R_QNC_GPIO_CGGPE_CORE_WELL 0x14 // Core well GPIO GPE Enable +#define R_QNC_GPIO_CGSMI_CORE_WELL 0x18 // Core well GPIO SMI Enable +#define R_QNC_GPIO_CGTS_CORE_WELL 0x1C // Core well GPIO Trigger Status +#define R_QNC_GPIO_RGEN_RESUME_WELL 0x20 +#define R_QNC_GPIO_RGIO_RESUME_WELL 0x24 +#define R_QNC_GPIO_RGLVL_RESUME_WELL 0x28 +#define R_QNC_GPIO_RGTPE_RESUME_WELL 0x2C // Resume well GPIO Trigger Positive Edge Enable +#define R_QNC_GPIO_RGTNE_RESUME_WELL 0x30 // Resume well GPIO Trigger Negative Edge Enable +#define R_QNC_GPIO_RGGPE_RESUME_WELL 0x34 // Resume well GPIO GPE Enable +#define R_QNC_GPIO_RGSMI_RESUME_WELL 0x38 // Resume well GPIO SMI Enable +#define R_QNC_GPIO_RGTS_RESUME_WELL 0x3C // Resume well GPIO Trigger Status +#define R_QNC_GPIO_CNMIEN_CORE_WELL 0x40 // Core well GPIO NMI Enable +#define R_QNC_GPIO_RNMIEN_RESUME_WELL 0x44 // Resume well GPIO NMI Enable + +#define R_QNC_LPC_PM1BLK 0x48 +#define B_QNC_LPC_PM1BLK_MASK 0x0000FFF0 +// +// ACPI register offsets from PM1BLK - "ACPI PM1 Block" (D31:F0:R48h) +// Suggested Value for PM1BLK = 0x1000 +// +#define R_QNC_PM1BLK_PM1S 0x00 +#define S_QNC_PM1BLK_PM1S 2 +#define B_QNC_PM1BLK_PM1S_ALL (BIT15+BIT14+BIT10+BIT5+BIT0) +#define B_QNC_PM1BLK_PM1S_WAKE (BIT15) +#define B_QNC_PM1BLK_PM1S_PCIEWSTS (BIT14) +#define B_QNC_PM1BLK_PM1S_RTC (BIT10) +#define B_QNC_PM1BLK_PM1S_GLOB (BIT5) +#define B_QNC_PM1BLK_PM1S_TO (BIT0) +#define N_QNC_PM1BLK_PM1S_RTC 10 + + +#define R_QNC_PM1BLK_PM1E 0x02 +#define S_QNC_PM1BLK_PM1E 2 +#define B_QNC_PM1BLK_PM1E_PWAKED (BIT14) +#define B_QNC_PM1BLK_PM1E_RTC (BIT10) +#define B_QNC_PM1BLK_PM1E_GLOB (BIT5) +#define N_QNC_PM1BLK_PM1E_RTC 10 + +#define R_QNC_PM1BLK_PM1C 0x04 +#define B_QNC_PM1BLK_PM1C_SLPEN (BIT13) +#define B_QNC_PM1BLK_PM1C_SLPTP (BIT12+BIT11+BIT10) +#define V_S0 0x00000000 +#define V_S3 0x00001400 +#define V_S4 0x00001800 +#define V_S5 0x00001C00 +#define B_QNC_PM1BLK_PM1C_SCIEN (BIT0) + +#define R_QNC_PM1BLK_PM1T 0x08 + +#define R_QNC_LPC_GPE0BLK 0x4C +#define B_QNC_LPC_GPE0BLK_MASK 0x0000FFC0 +// Suggested Value for GPE0BLK = 0x10C0 +// +#define R_QNC_GPE0BLK_GPE0S 0x00 // General Purpose Event 0 Status +#define S_QNC_GPE0BLK_GPE0S 4 +#define B_QNC_GPE0BLK_GPE0S_ALL 0x00003F800 // used to clear the status reg +#define B_QNC_GPE0BLK_GPE0S_PCIE (BIT17) // PCIE +#define B_QNC_GPE0BLK_GPE0S_GPIO (BIT14) // GPIO +#define B_QNC_GPE0BLK_GPE0S_EGPE (BIT13) // External GPE +#define N_QNC_GPE0BLK_GPE0S_THRM 12 + +#define R_QNC_GPE0BLK_GPE0E 0x04 // General Purpose Event 0 Enable +#define S_QNC_GPE0BLK_GPE0E 4 +#define B_QNC_GPE0BLK_GPE0E_PCIE (BIT17) // PCIE +#define B_QNC_GPE0BLK_GPE0E_GPIO (BIT14) // GPIO +#define B_QNC_GPE0BLK_GPE0E_EGPE (BIT13) // External GPE +#define N_QNC_GPE0BLK_GPE0E_THRM 12 + +#define R_QNC_GPE0BLK_SMIE 0x10 // SMI_B Enable +#define S_QNC_GPE0BLK_SMIE 4 +#define B_QNC_GPE0BLK_SMIE_ALL 0x0003871F +#define B_QNC_GPE0BLK_SMIE_APM (BIT4) // APM +#define B_QNC_GPE0BLK_SMIE_SLP (BIT2) // Sleep +#define B_QNC_GPE0BLK_SMIE_SWT (BIT1) // Software Timer +#define N_QNC_GPE0BLK_SMIE_GPIO 9 +#define N_QNC_GPE0BLK_SMIE_ESMI 8 +#define N_QNC_GPE0BLK_SMIE_APM 4 +#define N_QNC_GPE0BLK_SMIE_SPI 3 +#define N_QNC_GPE0BLK_SMIE_SLP 2 +#define N_QNC_GPE0BLK_SMIE_SWT 1 + +#define R_QNC_GPE0BLK_SMIS 0x14 // SMI Status Register. +#define S_QNC_GPE0BLK_SMIS 4 +#define B_QNC_GPE0BLK_SMIS_ALL 0x0003871F +#define B_QNC_GPE0BLK_SMIS_EOS (BIT31) // End of SMI +#define B_QNC_GPE0BLK_SMIS_APM (BIT4) // APM +#define B_QNC_GPE0BLK_SMIS_SPI (BIT3) // SPI +#define B_QNC_GPE0BLK_SMIS_SLP (BIT2) // Sleep +#define B_QNC_GPE0BLK_SMIS_SWT (BIT1) // Software Timer +#define B_QNC_GPE0BLK_SMIS_BIOS (BIT0) // BIOS +#define N_QNC_GPE0BLK_SMIS_GPIO 9 +#define N_QNC_GPE0BLK_SMIS_APM 4 +#define N_QNC_GPE0BLK_SMIS_SPI 3 +#define N_QNC_GPE0BLK_SMIS_SLP 2 +#define N_QNC_GPE0BLK_SMIS_SWT 1 + +#define R_QNC_GPE0BLK_PMCW 0x28 // Power Management Configuration Core Well +#define B_QNC_GPE0BLK_PMCW_PSE (BIT31) // Periodic SMI Enable + +#define R_QNC_GPE0BLK_PMSW 0x2C // Power Management Configuration Suspend/Resume Well +#define B_QNC_GPE0BLK_PMSW_DRAM_INIT (BIT0) // Dram Initialization Sctrachpad + +#define R_QNC_LPC_ACTL 0x58 +#define V_QNC_LPC_ACTL_SCIS_IRQ9 0x00 + +// +// Number of PIRQs supported. PIRQA~PIRQH +// +#define QNC_NUMBER_PIRQS 8 +#define R_QNC_LPC_PIRQA_ROUT 0x60 +#define R_QNC_LPC_PIRQB_ROUT 0x61 +#define R_QNC_LPC_PIRQC_ROUT 0x62 +#define R_QNC_LPC_PIRQD_ROUT 0x63 +#define R_QNC_LPC_PIRQE_ROUT 0x64 +#define R_QNC_LPC_PIRQF_ROUT 0x65 +#define R_QNC_LPC_PIRQG_ROUT 0x66 +#define R_QNC_LPC_PIRQH_ROUT 0x67 + +// +// Bit values are the same for R_TNC_LPC_PIRQA_ROUT to +// R_TNC_LPC_PIRQH_ROUT +#define B_QNC_LPC_PIRQX_ROUT (BIT3+BIT2+BIT1+BIT0) + +#define R_QNC_LPC_WDTBA 0x84 +// Watchdog Timer register offsets from WDTBASE (in R_QNC_LPC_WDTBA)------------BEGIN +#define R_QNC_LPC_WDT_WDTCR 0x10 +#define R_QNC_LPC_WDT_WDTLR 0x18 +// Watchdog Timer register offsets from WDTBASE (in R_QNC_LPC_WDTBA)--------------END + +#define R_QNC_LPC_FWH_BIOS_DEC 0xD4 +#define B_QNC_LPC_FWH_BIOS_DEC_F8 (BIT31) +#define B_QNC_LPC_FWH_BIOS_DEC_F0 (BIT30) +#define B_QNC_LPC_FWH_BIOS_DEC_E8 (BIT29) +#define B_QNC_LPC_FWH_BIOS_DEC_E0 (BIT28) +#define B_QNC_LPC_FWH_BIOS_DEC_D8 (BIT27) +#define B_QNC_LPC_FWH_BIOS_DEC_D0 (BIT26) +#define B_QNC_LPC_FWH_BIOS_DEC_C8 (BIT25) +#define B_QNC_LPC_FWH_BIOS_DEC_C0 (BIT24) + +#define R_QNC_LPC_BIOS_CNTL 0xD8 +#define S_QNC_LPC_BIOS_CNTL 4 +#define B_QNC_LPC_BIOS_CNTL_PFE (BIT8) +#define B_QNC_LPC_BIOS_CNTL_SMM_BWP (BIT5) +#define B_QNC_LPC_BIOS_CNTL_BCD (BIT2) +#define B_QNC_LPC_BIOS_CNTL_BLE (BIT1) +#define B_QNC_LPC_BIOS_CNTL_BIOSWE (BIT0) +#define N_QNC_LPC_BIOS_CNTL_BLE 1 +#define N_QNC_LPC_BIOS_CNTL_BIOSWE 0 + +#define R_QNC_LPC_RCBA 0xF0 +#define B_QNC_LPC_RCBA_MASK 0xFFFFC000 +#define B_QNC_LPC_RCBA_EN (BIT0) + +//--------------------------------------------------------------------------- +// Fixed IO Decode on QuarkNcSocId +// +// 20h(2B) 24h(2B) 28h(2B) 2Ch(2B) 30h(2B) 34h(2B) 38h(2B) 3Ch(2B) : R/W 8259 master +// 40h(3B): R/W 8254 +// 43h(1B): W 8254 +// 50h(3B): R/W 8254 +// 53h(1B): W 8254 +// 61h(1B): R/W NMI Controller +// 63h(1B): R/W NMI Controller - can be disabled +// 65h(1B): R/W NMI Controller - can be disabled +// 67h(1B): R/W NMI Controller - can be disabled +// 70h(1B): W NMI & RTC +// 71h(1B): R/W RTC +// 72h(1B): R RTC; W NMI&RTC +// 73h(1B): R/W RTC +// 74h(1B): R RTC; W NMI&RTC +// 75h(1B): R/W RTC +// 76h(1B): R RTC; W NMI&RTC +// 77h(1B): R/W RTC +// 84h(3B): R/W Internal/LPC +// 88h(1B): R/W Internal/LPC +// 8Ch(3B): R/W Internal/LPC +// A0h(2B) A4h(2B) A8h(2B) ACh(2B) B0h(2B) B4h(2B) B8h(2B) BCh(2B): R/W 8259 slave +// B2h(1B) B3h(1B): R/W Power management +// 3B0h-3BBh: R/W VGA +// 3C0h-3DFh: R/W VGA +// CF8h(4B): R/W Internal +// CF9h(1B): R/W LPC +// CFCh(4B): R/W Internal +//--------------------------------------------------------------------------- + +#define R_APM_CNT 0xB2 + +// +// Reset Generator I/O Port +// +#define RST_CNT 0xCF9 +#define B_RST_CNT_COLD_RST (BIT3) // Cold reset +#define B_RST_CNT_WARM_RST (BIT1) // Warm reset + +// +// Processor interface registers (NMI) +// + +#define PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0 20 +#define PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1 21 +#define PCI_FUNCTION_NUMBER_QNC_IOSF2AHB 0 + +// +// Pci Express Root Ports (D23:F0/F1) +// +#define PCI_DEVICE_NUMBER_PCIE_ROOTPORT 23 +#define PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 0 +#define PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1 1 + +#define MAX_PCI_EXPRESS_ROOT_PORTS 2 + +#define R_QNC_PCIE_BNUM 0x18 +#define R_QNC_PCIE_CAP_PTR 0x34 + +#define PCIE_CAPID 0x10 //PCIE Capability ID +#define PCIE_CAP_EXT_HEARDER_OFFSET 0x100 //PCIE Capability ID +#define PCIE_DEV_CAP_OFFSET 0x04 //PCIE Device Capability reg offset +#define PCIE_LINK_CAP_OFFSET 0x0C //PCIE Link Capability reg offset +#define PCIE_LINK_CNT_OFFSET 0x10 //PCIE Link control reg offset +#define PCIE_LINK_STS_OFFSET 0x12 //PCIE Link status reg offset +#define PCIE_SLOT_CAP_OFFSET 0x14 //PCIE Link Capability reg offset + +#define R_QNC_PCIE_XCAP 0x42 //~ 43h +#define B_QNC_PCIE_XCAP_SI (BIT8) //slot implemented +#define R_QNC_PCIE_DCAP 0x44 //~ 47h +#define B_QNC_PCIE_DCAP_E1AL (BIT11 | BIT10 | BIT9) // L1 Acceptable exit latency +#define B_QNC_PCIE_DCAP_E0AL (BIT8 | BIT7 | BIT6) // L0 Acceptable exit latency +#define R_QNC_PCIE_DCTL 0x48 //~ 49h +#define B_QNC_PCIE_DCTL_URE (BIT3) //Unsupported Request Reporting Enable +#define B_QNC_PCIE_DCTL_FEE (BIT2) //Fatal error Reporting Enable +#define B_QNC_PCIE_DCTL_NFE (BIT1) //Non Fatal error Reporting Enable +#define B_QNC_PCIE_DCTL_CEE (BIT0) //Correctable error Reporting Enable +#define R_QNC_PCIE_LCAP 0x4C //~ 4Fh +#define B_QNC_PCIE_LCAP_CPM (BIT18) //clock power management supported +#define B_QNC_PCIE_LCAP_EL1_MASK (BIT17 | BIT16 | BIT15) //L1 Exit latency mask +#define B_QNC_PCIE_LCAP_EL0_MASK (BIT14 | BIT13 | BIT12) //L0 Exit latency mask +#define B_QNC_PCIE_LCAP_APMS_MASK (BIT11 | BIT10) //Active state link PM support mask +#define V_QNC_PCIE_LCAP_APMS_OFFSET 10 //Active state link PM support mask +#define R_QNC_PCIE_LCTL 0x50 //~ 51h +#define B_QNC_PCIE_LCTL_CCC (BIT6) // Clock clock configuration +#define B_QNC_PCIE_LCTL_RL (BIT5) // Retrain link +#define R_QNC_PCIE_LSTS 0x52 //~ 53h +#define B_QNC_PCIE_LSTS_SCC (BIT12) //Slot clock configuration +#define B_QNC_PCIE_LSTS_LT (BIT11) //Link training +#define R_QNC_PCIE_SLCAP 0x54 //~ 57h +#define B_QNC_PCIE_SLCAP_MASK_RSV_VALUE 0x0006007F +#define V_QNC_PCIE_SLCAP_SLV 0x0A //Slot power limit value [14:7] +#define V_QNC_PCIE_SLCAP_SLV_OFFSET 7 //Slot power limit value offset is 7 [14:7] +#define V_QNC_PCIE_SLCAP_PSN_OFFSET 19 //Slot number offset is 19 [31:19] +#define R_QNC_PCIE_SLCTL 0x58 //~ 59h +#define B_QNC_PCIE_SLCTL_HPE (BIT5) // Hot plug interrupt enable +#define B_QNC_PCIE_SLCTL_PDE (BIT3) // Presense detect change enable +#define B_QNC_PCIE_SLCTL_ABE (BIT0) // Attention Button Pressed Enable +#define R_QNC_PCIE_SLSTS 0x5A //~ 5Bh +#define B_QNC_PCIE_SLSTS_PDS (BIT6) // Present Detect State = 1b : has device connected +#define B_QNC_PCIE_SLSTS_PDC (BIT3) // Present Detect changed = 1b : PDS state has changed +#define B_QNC_PCIE_SLSTS_ABP (BIT0) // Attention Button Pressed +#define R_QNC_PCIE_RCTL 0x5C //~ 5Dh +#define B_QNC_PCIE_RCTL_PIE (BIT3) //Root PCI-E PME Interrupt Enable +#define B_QNC_PCIE_RCTL_SFE (BIT2) //Root PCI-E System Error on Fatal Error Enable +#define B_QNC_PCIE_RCTL_SNE (BIT1) //Root PCI-E System Error on Non-Fatal Error Enable +#define B_QNC_PCIE_RCTL_SCE (BIT0) //Root PCI-E System Error on Correctable Error Enable +#define R_QNC_PCIE_SVID 0x94 //~ 97h +#define R_QNC_PCIE_CCFG 0xD0 //~ D3h +#define B_QNC_PCIE_CCFG_UPSD (BIT24) // Upstream Posted Split Disable +#define B_QNC_PCIE_CCFG_UNRS (BIT15) // Upstream Non-Posted Request Size +#define B_QNC_PCIE_CCFG_UPRS (BIT14) // Upstream Posted Request Size +#define R_QNC_PCIE_MPC2 0xD4 //~ D7h +#define B_QNC_PCIE_MPC2_IPF (BIT11) // ISOF Packet Fast Transmit Mode +#define R_QNC_PCIE_MPC 0xD8 //~ DBh +#define B_QNC_PCIE_MPC_PMCE (BIT31) // PM SCI Enable +#define B_QNC_PCIE_MPC_HPCE (BIT30) // Hot plug SCI enable + +#define B_QNC_PCIE_MPC_HPME (BIT1) // Hot plug SMI enable +#define B_QNC_PCIE_MPC_PMME (BIT0) // PM SMI Enable +#define R_QNC_PCIE_IOSFSBCTL 0xF6 +#define B_QNC_PCIE_IOSFSBCTL_SBIC_MASK (BIT1 | BIT0) // IOSF Sideband ISM Idle Counter. +#define B_QNC_PCIE_IOSFSBCTL_SBIC_IDLE_NEVER (BIT1 | BIT0) // Never transition to IDLE. + +#define V_PCIE_MAX_TRY_TIMES 200 + +// +// Misc PCI register offsets and sizes +// +#define R_EFI_PCI_SVID 0x2C + +// +// IO_APIC +// +#define IOAPIC_BASE 0xFEC00000 +#define IOAPIC_SIZE 0x1000 + +// +// Chipset configuration registers RCBA - "Root Complex Base Address" (D31:F0:RF0h) +// Suggested Value for RCBA = 0xFED1C000 +// + +#define R_QNC_RCRB_SPIBASE 0x3020 // SPI (Serial Peripheral Interface) in RCRB +#define R_QNC_RCRB_SPIS (R_QNC_RCRB_SPIBASE + 0x00) // SPI Status +#define B_QNC_RCRB_SPIS_SCL (BIT15) // SPI Configuration Lockdown +#define B_QNC_RCRB_SPIS_BAS (BIT3) // Blocked Access Status +#define B_QNC_RCRB_SPIS_CDS (BIT2) // Cycle Done Status +#define B_QNC_RCRB_SPIS_SCIP (BIT0) // SPI Cycle in Progress + +#define R_QNC_RCRB_SPIC (R_QNC_RCRB_SPIBASE + 0x02) // SPI Control +#define B_QNC_RCRB_SPIC_DC (BIT14) // SPI Data Cycle Enable +#define B_QNC_RCRB_SPIC_DBC 0x3F00 // SPI Data Byte Count (1..8,16,24,32,40,48,56,64) +#define B_QNC_RCRB_SPIC_COP (BIT6+BIT5+BIT4) // SPI Cycle Opcode Pointer +#define B_QNC_RCRB_SPIC_SPOP (BIT3) // Sequence Prefix Opcode Pointer +#define B_QNC_RCRB_SPIC_ACS (BIT2) // SPI Atomic Cycle Sequence +#define B_QNC_RCRB_SPIC_SCGO (BIT1) // SPI Cycle Go + +#define R_QNC_RCRB_SPIA (R_QNC_RCRB_SPIBASE + 0x04) // SPI Address +#define B_QNC_RCRB_SPIA_MASK 0x00FFFFFF // SPI Address mask +#define R_QNC_RCRB_SPID0 (R_QNC_RCRB_SPIBASE + 0x08) // SPI Data 0 +#define R_QNC_RCRB_SPIPREOP (R_QNC_RCRB_SPIBASE + 0x54) // Prefix Opcode Configuration +#define R_QNC_RCRB_SPIOPTYPE (R_QNC_RCRB_SPIBASE + 0x56) // Opcode Type Configuration +#define B_QNC_RCRB_SPIOPTYPE_NOADD_READ 0 +#define B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE (BIT0) +#define B_QNC_RCRB_SPIOPTYPE_ADD_READ (BIT1) +#define B_QNC_RCRB_SPIOPTYPE_ADD_WRITE (BIT0 + BIT1) +#define R_QNC_RCRB_SPIOPMENU (R_QNC_RCRB_SPIBASE + 0x58) // Opcode Menu Configuration //R_OPMENU + +#define R_QNC_RCRB_SPIPBR0 (R_QNC_RCRB_SPIBASE + 0x60) // Protected BIOS Range 0. +#define R_QNC_RCRB_SPIPBR1 (R_QNC_RCRB_SPIBASE + 0x64) // Protected BIOS Range 1. +#define R_QNC_RCRB_SPIPBR2 (R_QNC_RCRB_SPIBASE + 0x68) // Protected BIOS Range 2. +#define B_QNC_RCRB_SPIPBRn_WPE (BIT31) // Write Protection Enable for above 3 registers. + +#define R_QNC_RCRB_AGENT0IR 0x3140 // AGENT0 interrupt route +#define R_QNC_RCRB_AGENT1IR 0x3142 // AGENT1 interrupt route +#define R_QNC_RCRB_AGENT2IR 0x3144 // AGENT2 interrupt route +#define R_QNC_RCRB_AGENT3IR 0x3146 // AGENT3 interrupt route + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h new file mode 100644 index 0000000000..0024218afc --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/CommonHeader.h @@ -0,0 +1,32 @@ +/** @file +Common header file shared by all source files. + +This file includes package header files, library classes and protocol, PPI & GUID definitions. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef __COMMON_HEADER_H_ +#define __COMMON_HEADER_H_ + + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c new file mode 100644 index 0000000000..fbb89f9904 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.c @@ -0,0 +1,771 @@ +/** @file +Lib function for Pei QNC. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "CommonHeader.h" + +/** + This function provides the necessary SOC initialization + before MRC running. It sets RCBA, GPIO, PMBASE + and some parts of SOC through SOC message method. + If the function cannot complete it'll ASSERT(). +**/ +VOID +EFIAPI +PeiQNCPreMemInit ( + VOID + ) +{ + UINT32 RegValue; + + // QNCPortWrite(Port#, Offset, Value) + + // + // Set the fixed PRI Status encodings config. + // + QNCPortWrite ( + QUARK_NC_MEMORY_ARBITER_SB_PORT_ID, + QUARK_NC_MEMORY_ARBITER_REG_ASTATUS, + QNC_FIXED_CONFIG_ASTATUS + ); + + // Sideband register write to Remote Management Unit + QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QNC_MSG_TMPM_REG_PMBA, (BIT31 | PcdGet16 (PcdPmbaIoBaseAddress))); + + // Configurable I/O address in iLB (legacy block) + + LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) = BIT31 | PcdGet16 (PcdSmbaIoBaseAddress); + LpcPciCfg32 (R_QNC_LPC_GBA_BASE) = BIT31 | PcdGet16 (PcdGbaIoBaseAddress); + LpcPciCfg32 (R_QNC_LPC_PM1BLK) = BIT31 | PcdGet16 (PcdPm1blkIoBaseAddress); + LpcPciCfg32 (R_QNC_LPC_GPE0BLK) = BIT31 | PcdGet16 (PcdGpe0blkIoBaseAddress); + LpcPciCfg32 (R_QNC_LPC_WDTBA) = BIT31 | PcdGet16 (PcdWdtbaIoBaseAddress); + + // + // Program RCBA Base Address + // + LpcPciCfg32AndThenOr (R_QNC_LPC_RCBA, (~B_QNC_LPC_RCBA_MASK), (((UINT32)(PcdGet64 (PcdRcbaMmioBaseAddress))) | B_QNC_LPC_RCBA_EN)); + + // + // Program Memory Manager fixed config values. + // + + RegValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL); + RegValue &= ~(DRAM_NON_HOST_RQ_LIMIT_MASK); + RegValue |= (V_DRAM_NON_HOST_RQ_LIMIT << DRAM_NON_HOST_RQ_LIMIT_BP); + QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL, RegValue); + + // + // Program iCLK fixed config values. + // + QncIClkAndThenOr ( + QUARK_ICLK_MUXTOP, + (UINT32) ~(B_MUXTOP_FLEX2_MASK | B_MUXTOP_FLEX1_MASK), + (V_MUXTOP_FLEX2 << B_MUXTOP_FLEX2_BP) | (V_MUXTOP_FLEX1 << B_MUXTOP_FLEX1_BP) + ); + QncIClkAndThenOr ( + QUARK_ICLK_REF2_DBUFF0, + (UINT32) ~(BIT0), // bit[0] cleared + 0 + ); + QncIClkOr ( + QUARK_ICLK_SSC1, + BIT0 // bit[0] set + ); + QncIClkOr ( + QUARK_ICLK_SSC2, + BIT0 // bit[0] set + ); + QncIClkOr ( + QUARK_ICLK_SSC3, + BIT0 // bit[0] set + ); + + // + // Set RMU DMA disable bit post boot. + // + RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1); + RegValue |= OPTIONS_1_DMA_DISABLE; + QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1, RegValue); +} + +/** + Do north cluster init which needs to be done AFTER MRC init. + + @param VOID + + @retval VOID +**/ + +VOID +EFIAPI +PeiQNCPostMemInit ( + VOID + ) +{ + // + // Program SVID/SID the same as VID/DID for all devices except root ports. + // + QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, R_EFI_PCI_SVID) = QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, PCI_VENDOR_ID_OFFSET); + QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, PCI_VENDOR_ID_OFFSET); + QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, PCI_VENDOR_ID_OFFSET); + QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, PCI_VENDOR_ID_OFFSET); + return; +} + +/** + Used to check QNC if it's S3 state. Clear the register state after query. + + @retval TRUE if it's S3 state. + @retval FALSE if it's not S3 state. + +**/ +BOOLEAN +EFIAPI +QNCCheckS3AndClearState ( + VOID + ) +{ + BOOLEAN S3WakeEventFound; + UINT16 Pm1Sts; + UINT16 Pm1En; + UINT16 Pm1Cnt; + UINT32 Gpe0Sts; + UINT32 Gpe0En; + UINT32 NewValue; + CHAR8 *EventDescStr; + + S3WakeEventFound = FALSE; + EventDescStr = NULL; + + // + // Read the ACPI registers, + // + Pm1Sts = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S); + Pm1En = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E); + Pm1Cnt = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); + Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S); + Gpe0En = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E); + + // + // Clear Power Management 1 Enable Register and + // General Purpost Event 0 Enables Register + // + IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0); + IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0); + + if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S3) { + + // + // Detect the actual WAKE event + // + if ((Pm1Sts & B_QNC_PM1BLK_PM1S_RTC) && (Pm1En & B_QNC_PM1BLK_PM1E_RTC)) { + EventDescStr = "RTC Alarm"; + S3WakeEventFound = TRUE; + } + if ((Pm1Sts & B_QNC_PM1BLK_PM1S_PCIEWSTS) && !(Pm1En & B_QNC_PM1BLK_PM1E_PWAKED)) { + EventDescStr = "PCIe WAKE"; + S3WakeEventFound = TRUE; + } + if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_PCIE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_PCIE)) { + EventDescStr = "PCIe"; + S3WakeEventFound = TRUE; + } + if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_GPIO) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_GPIO)) { + EventDescStr = "GPIO"; + S3WakeEventFound = TRUE; + } + if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_EGPE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_EGPE)) { + EventDescStr = "Ext. GPE"; + S3WakeEventFound = TRUE; + } + if (S3WakeEventFound == FALSE) { + EventDescStr = "Unknown"; + } + DEBUG ((EFI_D_INFO, "S3 Wake Event - %a\n", EventDescStr)); + + // + // If no Power Button Override event occurs and one enabled wake event occurs, + // just do S3 resume and clear the state. + // + IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP))); + + // + // Set EOS to de Assert SMI + // + IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS); + + // + // Enable SMI globally + // + NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); + NewValue |= SMI_EN; + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue); + + return TRUE; + } + + return FALSE; +} + +/** + Used to check QNC if system wakes up from power on reset. Clear the register state after query. + + @retval TRUE if system wakes up from power on reset + @retval FALSE if system does not wake up from power on reset + +**/ +BOOLEAN +EFIAPI +QNCCheckPowerOnResetAndClearState ( + VOID + ) +{ + UINT16 Pm1Sts; + UINT16 Pm1Cnt; + + // + // Read the ACPI registers, + // PM1_STS information cannot be lost after power down, unless CMOS is cleared. + // + Pm1Sts = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S); + Pm1Cnt = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); + + // + // If B_SLP_TYP is S5 + // + if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S5) { + IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP))); + return TRUE; + } + + return FALSE; +} + +/** + This function is used to clear SMI and wake status. + +**/ +VOID +EFIAPI +QNCClearSmiAndWake ( + VOID + ) +{ + UINT32 Gpe0Sts; + UINT32 SmiSts; + + // + // Read the ACPI registers + // + Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S); + SmiSts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS); + + // + // Clear any SMI or wake state from the boot + // + Gpe0Sts |= B_QNC_GPE0BLK_GPE0S_ALL; + SmiSts |= B_QNC_GPE0BLK_SMIS_ALL; + + // + // Write them back + // + IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S, Gpe0Sts); + IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, SmiSts); +} + +/** Send DRAM Ready opcode. + + @param[in] OpcodeParam Parameter to DRAM ready opcode. + + @retval VOID +**/ +VOID +EFIAPI +QNCSendOpcodeDramReady ( + IN UINT32 OpcodeParam + ) +{ + + // + // Before sending DRAM ready place invalid value in Scrub Config. + // + QNCPortWrite ( + QUARK_NC_RMU_SB_PORT_ID, + QUARK_NC_ECC_SCRUB_CONFIG_REG, + SCRUB_CFG_INVALID + ); + + // + // Send opcode and use param to notify HW of new RMU firmware location. + // + McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = OpcodeParam; + McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_SHADOW_DW (QUARK_NC_RMU_SB_PORT_ID, 0); + + // + // HW completed tasks on DRAM ready when scrub config read back as zero. + // + while (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG) != 0) { + MicroSecondDelay (10); + } +} + +/** + + Relocate RMU Main binary to memory after MRC to improve performance. + + @param[in] DestBaseAddress - Specify the new memory address for the RMU Main binary. + @param[in] SrcBaseAddress - Specify the current memory address for the RMU Main binary. + @param[in] Size - Specify size of the RMU Main binary. + + @retval VOID + +**/ +VOID +EFIAPI +RmuMainRelocation ( + IN CONST UINT32 DestBaseAddress, + IN CONST UINT32 SrcBaseAddress, + IN CONST UINTN Size + ) +{ + // + // Shadow RMU Main binary into main memory. + // + CopyMem ((VOID *)(UINTN)DestBaseAddress,(VOID *)(UINTN) SrcBaseAddress, Size); +} + + +/** + Get the total memory size + +**/ +UINT32 +EFIAPI +QNCGetTotalMemorysize ( + VOID + ) +{ + return QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG) & HMBOUND_MASK; +} + + +/** + Get the memory range of TSEG. + The TSEG's memory is below TOLM. + + @param[out] BaseAddress The base address of TSEG's memory range + @param[out] MemorySize The size of TSEG's memory range + +**/ +VOID +EFIAPI +QNCGetTSEGMemoryRange ( + OUT UINT64 *BaseAddress, + OUT UINT64 *MemorySize + ) +{ + UINT64 Register = 0; + UINT64 SMMAddress = 0; + + Register = QncHsmmcRead (); + + // + // Get the SMRAM Base address + // + SMMAddress = Register & SMM_START_MASK; + *BaseAddress = LShift16 (SMMAddress); + + // + // Get the SMRAM size + // + SMMAddress = ((Register & SMM_END_MASK) | (~SMM_END_MASK)) + 1; + *MemorySize = SMMAddress - (*BaseAddress); + + DEBUG (( + EFI_D_INFO, + "TSEG's memory range: BaseAddress = 0x%x, Size = 0x%x\n", + (UINT32)*BaseAddress, + (UINT32)*MemorySize + )); +} + +/** + Updates the PAM registers in the MCH for the requested range and mode. + + @param Start The start address of the memory region + @param Length The length, in bytes, of the memory region + @param ReadEnable Pointer to the boolean variable on whether to enable read for legacy memory section. + If NULL, then read attribute will not be touched by this call. + @param ReadEnable Pointer to the boolean variable on whether to enable write for legacy memory section. + If NULL, then write attribute will not be touched by this call. + @param Granularity A pointer to granularity, in bytes, that the PAM registers support + + @retval RETURN_SUCCESS The PAM registers in the MCH were updated + @retval RETURN_INVALID_PARAMETER The memory range is not valid in legacy region. + +**/ +EFI_STATUS +EFIAPI +QNCLegacyRegionManipulation ( + IN UINT32 Start, + IN UINT32 Length, + IN BOOLEAN *ReadEnable, + IN BOOLEAN *WriteEnable, + OUT UINT32 *Granularity + ) +{ + // + // Do nothing cos no such support on QNC + // + return RETURN_SUCCESS; +} + +/** + Determine if QNC is supported. + + @retval FALSE QNC is not supported. + @retval TRUE QNC is supported. +**/ +BOOLEAN +EFIAPI +IsQncSupported ( + VOID + ) +{ + UINT16 SocVendorId; + UINT16 SocDeviceId; + + SocVendorId = MmioRead16 ( + PciDeviceMmBase (MC_BUS, + MC_DEV, + MC_FUN) + PCI_VENDOR_ID_OFFSET + ); + + SocDeviceId = QncGetSocDeviceId(); + + // + // Verify that this is a supported chipset + // + if ((SocVendorId != QUARK_MC_VENDOR_ID) || ((SocDeviceId != QUARK_MC_DEVICE_ID) && (SocDeviceId != QUARK2_MC_DEVICE_ID))) { + DEBUG ((DEBUG_ERROR, "QNC code doesn't support the Soc VendorId:0x%04x Soc DeviceId:0x%04x!\n", SocVendorId, SocDeviceId)); + return FALSE; + } + return TRUE; +} + +/** + Get the DeviceId of the SoC + + @retval PCI DeviceId of the SoC +**/ +UINT16 +EFIAPI +QncGetSocDeviceId ( + VOID + ) +{ + UINT16 SocDeviceId; + + SocDeviceId = MmioRead16 ( + PciDeviceMmBase ( + MC_BUS, + MC_DEV, + MC_FUN + ) + PCI_DEVICE_ID_OFFSET + ); + + return SocDeviceId; +} + +/** + Enable SMI detection of legacy flash access violations. +**/ +VOID +EFIAPI +QncEnableLegacyFlashAccessViolationSmi ( + VOID + ) +{ + UINT32 BcValue; + + BcValue = LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL); + + // + // Clear BIOSWE & set BLE. + // + BcValue &= (~B_QNC_LPC_BIOS_CNTL_BIOSWE); + BcValue |= (B_QNC_LPC_BIOS_CNTL_BLE); + + LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL) = BcValue; + + DEBUG ((EFI_D_INFO, "BIOS Control Lock Enabled!\n")); +} + +/** + Setup RMU Thermal sensor registers for Vref mode. +**/ +VOID +EFIAPI +QNCThermalSensorSetVRefMode ( + VOID + ) +{ + UINT32 Tscgf1Config; + UINT32 Tscgf2Config; + UINT32 Tscgf2Config2; + + Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG); + Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG); + Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2); + + Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK); + Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_VREF_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP); + + Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN); + Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_VREF_MODE << B_TSCGF1_CONFIG_IBGEN_BP); + + Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK); + Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_VREF_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP); + + Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK); + Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_VREF_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP); + + Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK); + Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_VREF_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP); + + QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config); + QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config); + QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2); +} + +/** + Setup RMU Thermal sensor registers for Ratiometric mode. +**/ +VOID +EFIAPI +QNCThermalSensorSetRatiometricMode ( + VOID + ) +{ + UINT32 Tscgf1Config; + UINT32 Tscgf2Config; + UINT32 Tscgf2Config2; + UINT32 Tscgf3Config; + + Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG); + Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG); + Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2); + Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG); + + Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK); + Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_RATIO_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP); + + Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCHOPSEL_MASK); + Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCHOPSEL_RATIO_MODE << B_TSCGF1_CONFIG_ISNSCHOPSEL_BP); + + Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSINTERNALVREFEN); + Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSINTERNALVREFEN_RATIO_MODE << B_TSCGF1_CONFIG_ISNSINTERNALVREFEN_BP); + + Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN); + Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGEN_BP); + + Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGCHOPEN); + Tscgf1Config |= (V_TSCGF1_CONFIG_IBGCHOPEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGCHOPEN_BP); + + Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCONFIGSEL_MASK); + Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCONFIGSEL_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCONFIGSEL_BP); + + Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK); + Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_RATIO_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP); + + Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK); + Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP); + + Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK); + Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_RATIO_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP); + + Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSTIMING_MASK); + Tscgf2Config |= (V_TSCGF2_CONFIG_IDSTIMING_RATIO_MODE << B_TSCGF2_CONFIG_IDSTIMING_BP); + + Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSGAMMACOEFF_MASK); + Tscgf3Config |= (V_TSCGF3_CONFIG_ITSGAMMACOEFF_RATIO_MODE << B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP); + + QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config); + QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config); + QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2); + QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config); +} + +/** + Setup RMU Thermal sensor trip point values. + + @param[in] CatastrophicTripOnDegreesCelsius - Catastrophic set trip point threshold. + @param[in] HotTripOnDegreesCelsius - Hot set trip point threshold. + @param[in] HotTripOffDegreesCelsius - Hot clear trip point threshold. + + @retval EFI_SUCCESS Trip points setup. + @retval EFI_INVALID_PARAMETER Invalid trip point value. + +**/ +EFI_STATUS +EFIAPI +QNCThermalSensorSetTripValues ( + IN CONST UINTN CatastrophicTripOnDegreesCelsius, + IN CONST UINTN HotTripOnDegreesCelsius, + IN CONST UINTN HotTripOffDegreesCelsius + ) +{ + UINT32 RegisterValue; + + // + // Register fields are 8-bit temperature values of granularity 1 degree C + // where 0x00 corresponds to -50 degrees C + // and 0xFF corresponds to 205 degrees C. + // + // User passes unsigned values in degrees Celsius so trips < 0 not supported. + // + // Add 50 to user values to get values for register fields. + // + + if ((CatastrophicTripOnDegreesCelsius > 205) || (HotTripOnDegreesCelsius > 205) || (HotTripOffDegreesCelsius > 205)) { + return EFI_INVALID_PARAMETER; + } + + // + // Set new values. + // + RegisterValue = + ((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP) | // Cat Trip Clear value must be less than Cat Trip Set Value. + ((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP) | + ((HotTripOnDegreesCelsius + 50) << TS_HOT_TRIP_SET_THOLD_BP) | + ((HotTripOffDegreesCelsius + 50) << TS_HOT_TRIP_CLEAR_THOLD_BP) + ; + + QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, RegisterValue); + + return EFI_SUCCESS; +} + +/** + Enable RMU Thermal sensor with a Catastrophic Trip point. + + @retval EFI_SUCCESS Trip points setup. + @retval EFI_INVALID_PARAMETER Invalid trip point value. + +**/ +EFI_STATUS +EFIAPI +QNCThermalSensorEnableWithCatastrophicTrip ( + IN CONST UINTN CatastrophicTripOnDegreesCelsius + ) +{ + UINT32 Tscgf3Config; + UINT32 TsModeReg; + UINT32 TsTripReg; + + // + // Trip Register fields are 8-bit temperature values of granularity 1 degree C + // where 0x00 corresponds to -50 degrees C + // and 0xFF corresponds to 205 degrees C. + // + // User passes unsigned values in degrees Celsius so trips < 0 not supported. + // + // Add 50 to user values to get values for register fields. + // + + if (CatastrophicTripOnDegreesCelsius > 205) { + return EFI_INVALID_PARAMETER; + } + + Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG); + TsModeReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE); + TsTripReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP); + + // + // Setup Catastrophic Trip point. + // + TsTripReg &= ~(TS_CAT_TRIP_SET_THOLD_MASK); + TsTripReg |= ((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP); + TsTripReg &= ~(TS_CAT_TRIP_CLEAR_THOLD_MASK); + TsTripReg |= ((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP); // Cat Trip Clear value must be less than Cat Trip Set Value. + QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, TsTripReg); + + // + // To enable the TS do the following: + // 1) Take the TS out of reset by setting itsrst to 0x0. + // 2) Enable the TS using RMU Thermal sensor mode register. + // + + Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSRST); + TsModeReg |= TS_ENABLE; + + QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config); + QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE, TsModeReg); + + return EFI_SUCCESS; +} + +/** + Lock all RMU Thermal sensor control & trip point registers. + +**/ +VOID +EFIAPI +QNCThermalSensorLockAllRegisters ( + VOID + ) +{ + UINT32 RegValue; + UINT32 LockMask; + + LockMask = TS_LOCK_THRM_CTRL_REGS_ENABLE | TS_LOCK_AUX_TRIP_PT_REGS_ENABLE; + + RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG); + RegValue |= LockMask; + QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG, RegValue); + + ASSERT ((LockMask == (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG) & LockMask))); +} + +/** + Set chipset policy for double bit ECC error. + + @param[in] PolicyValue Policy to config on double bit ECC error. + +**/ +VOID +EFIAPI +QNCPolicyDblEccBitErr ( + IN CONST UINT32 PolicyValue + ) +{ + UINT32 Register; + Register = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_WDT_CONTROL); + Register &= ~(B_WDT_CONTROL_DBL_ECC_BIT_ERR_MASK); + Register |= PolicyValue; + QNCPortWrite ( + QUARK_NC_RMU_SB_PORT_ID, + QUARK_NC_RMU_REG_WDT_CONTROL, + Register + ); +} + +/** + Determine if running on secure Quark hardware Sku. + + @retval FALSE Base Quark Sku or unprovisioned Secure Sku running. + @retval TRUE Provisioned SecureSku hardware running. +**/ +BOOLEAN +EFIAPI +QncIsSecureProvisionedSku ( + VOID + ) +{ + // Read QUARK Secure SKU Fuse + return ((QNCAltPortRead (QUARK_SCSS_FUSE_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_SPI_ROM_FUSE) & BIT6) == BIT6); +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf new file mode 100644 index 0000000000..b3e8fbf2d2 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf @@ -0,0 +1,57 @@ +## @file +# Intel QNC Library Instance +# +# Intel QNC Library Instance +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = IntelQNCLib + FILE_GUID = F5B2EA6C-8148-4a4e-88EA-38A4A51F389F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = IntelQNCLib + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + PciExpress.c + IntelQNCLib.c + CommonHeader.h + +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + TimerLib + DebugLib + PcdLib + PciLib + IoLib + PciCf8Lib + BaseLib + CpuLib + QNCAccessLib + +[Pcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdWdtbaIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPcieRootPortConfiguration + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c new file mode 100644 index 0000000000..ac00572ce4 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/PciExpress.c @@ -0,0 +1,932 @@ +/** @file +QNC PCI Express initialization entry + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CommonHeader.h" + +#define PCIEXP_ROOT_PORT_URE_ENABLE BIT0 // unsupported request reporting enable +#define PCIEXP_ROOT_PORT_FEE_ENABLE BIT1 // Fatal Error Reporting Enable +#define PCIEXP_ROOT_PORT_NFE_ENABLE BIT2 // Non-Fatal Error Reporting Enable +#define PCIEXP_ROOT_PORT_CEE_ENABLE BIT3 // Correctable Error Reporting Enable +#define PCIEXP_ROOT_PORT_SFE_ENABLE BIT4 // System Error on Fatal Error Enable +#define PCIEXP_ROOT_PORT_SNE_ENABLE BIT5 // System Error on Non-Fatal Error Enable +#define PCIEXP_ROOT_PORT_SCE_ENABLE BIT6 // System Error on Correctable Error Enable + +EFI_STATUS +PcieStall ( + IN UINTN Microseconds + ) +{ + MicroSecondDelay (Microseconds); + return EFI_SUCCESS; +} + +/** + + Find the Offset to a given Capabilities ID + CAPID list: + 0x01 = PCI Power Management Interface + 0x04 = Slot Identification + 0x05 = MSI Capability + 0x10 = PCI Express Capability + + @param[in] Bus Bus number of the interested device + @param[in] Device Device number of the interested device + @param[in] Function Function number of the interested device + @param[in] CapId Capability ID to be scanned + + @retval Offset of desired CAPID + +**/ +UINT32 +PcieFindCapId ( + UINT8 Bus, + UINT8 Device, + UINT8 Function, + UINT8 CapId + ) +{ + UINT8 CapHeader; + + // + // Always start at Offset 0x34 + // + CapHeader = QNCMmPci8 (0, Bus, Device, Function, R_QNC_PCIE_CAP_PTR); + + if (CapHeader == 0xFF) { + return 0; + } + + while (CapHeader != 0) { + if (QNCMmPci8 (0, Bus, Device, Function, CapHeader) == CapId) { + return CapHeader; + } + CapHeader = QNCMmPci8 (0, Bus, Device, Function, CapHeader + 1); + } + return 0; +} + +/** + + Search and return the offset of desired Pci Express Capability ID + CAPID list: + 0x0001 = Advanced Error Rreporting Capability + 0x0002 = Virtual Channel Capability + 0x0003 = Device Serial Number Capability + 0x0004 = Power Budgeting Capability + + @param[in] Bus Bus number of the interested device + @param[in] Device Device number of the interested device + @param[in] Function Function number of the interested device + @param[in] CapId Capability ID to be scanned + + @retval Offset of desired CAPID + +**/ +UINT32 +PcieFindExtendedCapId ( + UINT8 Bus, + UINT8 Device, + UINT8 Function, + UINT16 CapId + ) +{ + UINT16 CapHeaderOffset; + UINT16 CapHeaderId; + + // Start to search at Offset 0x100 + // Get Capability Header + CapHeaderId = 0; + CapHeaderOffset = PCIE_CAP_EXT_HEARDER_OFFSET; + + while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) { + CapHeaderId = QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset); + if (CapHeaderId == CapId) { + return CapHeaderOffset; + } + CapHeaderOffset = (QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset + 2) >> 4); + } + return 0; +} + +/** + + Map Vc on both root port and downstream device + + @param[in] Bus1 Bus number of the root port + @param[in] Device1 Device number of the root port + @param[in] Function1 Function number of the root port + @param[in] Bus2 Bus number of the downstream device + @param[in] Device2 Device number of the downstream device + @param[in] Function2 Function number of the downstream device + + @retval EFI_SUCCESS Map Vc successful + +**/ +EFI_STATUS +PcieInitTcxVc0 ( + IN UINT8 Bus1, + IN UINT8 Device1, + IN UINT8 Function1, + IN UINT8 Bus2, + IN UINT8 Device2, + IN UINT8 Function2 + ) +{ + UINT32 Offset; + + // + // Initialize TCx-VC0 value on the port to only use TC0 + // + Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2); + if (Offset == 0) { + return EFI_UNSUPPORTED; + } + QNCMmPci8AndThenOr (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1); + + // Set TCx-VC0 value on the Endpoint + + Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2); + if (Offset == 0) { + return EFI_UNSUPPORTED; + } + QNCMmPci8AndThenOr (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1); + + return EFI_SUCCESS; +} + +/** + + Map Traffic Class x to Vc0 on both root port and downstream device + + @param[in] Bus1 Bus number of the root port + @param[in] Device1 Device number of the root port + @param[in] Function1 Function number of the root port + @param[in] Bus2 Bus number of the downstream device + @param[in] Device2 Device number of the downstream device + @param[in] Function2 Function number of the downstream device + @param[in] TCx Traffic Class to be mapped to vc0 + + @retval EFI_SUCCESS Map Tcx to Vc0 successful + +**/ +EFI_STATUS +PcieMapTcxVc0 ( + IN UINT8 Bus1, + IN UINT8 Device1, + IN UINT8 Function1, + IN UINT8 Bus2, + IN UINT8 Device2, + IN UINT8 Function2, + IN UINT8 TCx + ) +{ + UINT32 Offset; + + // + // Set TCx-VC0 value on the port + // + + Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2); + if (Offset == 0) { + return EFI_UNSUPPORTED; + } + QNCMmPci8 (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx); + + // Set TCx-VC0 value on the Endpoint + + Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2); + if (Offset == 0) { + return EFI_UNSUPPORTED; + } + QNCMmPci8 (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx); + + return EFI_SUCCESS; +} + +/** + + Set common clock for both root port and downstream device. + + @param[in] Bus1 Bus number of the root port + @param[in] Device1 Device number of the root port + @param[in] Function1 Function number of the root port + @param[in] Bus2 Device number of the downstream device + @param[in] Device2 Function number of the downstream device + + @retval EFI_SUCCESS Set common clock successful + +**/ +EFI_STATUS +PcieSetCommonClock ( + IN UINT8 Bus1, + IN UINT8 Device1, + IN UINT8 Function1, + IN UINT8 Bus2, + IN UINT8 Device2 + ) +{ + UINT32 CapOffset1; + UINT32 CapOffset2; + UINT8 Function2; + UINT8 CommonClock; + EFI_STATUS Status; + + // + // Get the pointer to the Port PCI Express Capability Structure. + // + CommonClock = 0; + CapOffset1 = PcieFindCapId (Bus1, Device1, Function1, PCIE_CAPID); + if (CapOffset1 == 0) { + return EFI_UNSUPPORTED; + } + + // + // Step 1 + // Read the Slot Clock Configuration bit of the Link status register of the root port and the endpoint device connected to the port + // If both components have this bit set to 1, then System BIOS should set the "Common Clock Configuration" bit in the Link Control Registers + // for both components at both sides of the link to indicate that components at both ends + // of the link use a common clock source + // + + // + // Check the Port Slot Clock Configuration Bit. + // + if ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) == 0) { + return EFI_UNSUPPORTED; + } + + for (Function2 = 0; Function2 < 8; Function2++) { + // + // Check the Endpoint Slot Clock Configuration Bit. + // + CapOffset2 = PcieFindCapId (Bus2, Device2, Function2, PCIE_CAPID); + if ((CapOffset2 != 0) && + ((QNCMmPci16 (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) != 0)) { + + // + // Common clock is supported, set common clock bit on root port + // and the endpoint + // + if (CommonClock == 0) { + QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC); + CommonClock++; + } + QNCMmPci8Or (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC); + } + } + + // + // Step 2 If the Common Clock Configuration bit was changed by BIOS in step 1, + // System BIOS should initiate a link training by setting the Retrain Link bit + // in the Link Control register of the root port (D28:F0/F1 offset + // 50h [5]) to "1b" and then poll the Link Training bit in the Link Status + // register of the root port (D28:F0/F1/F2/F3/F4/F5 offset 52h [11]) until it is + // "0b". + // + if (CommonClock == 0) { + Status = EFI_UNSUPPORTED; + } else { + // + // Retrain the Link per PCI Express Specification. + // + QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_RL); + + // + // Wait until Re-Training has completed. + // + while ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_LT) != 0); + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + + Enables the CLKREQ# PM on all the end point functions + + @param[in] Bus Bus number of the downstream device + @param[in] Device Device number of the downstream device + + @retval None + +**/ +VOID +PcieSetClkreq ( + IN UINT8 Bus, + IN UINT8 Device + ) +{ + UINT8 Function; + UINT32 CapOffset; + + // + // Parse thro all the functions of the endpoint and find the PCIe Cap ID (offset 10h) and if + // exists then enable the CLKREQ# bit (BIT8) on that function + // + for (Function = 0; Function < 8; Function++) { + // + // Find the PCIe Cap Id (offset 10h) + // + CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID); + if (CapOffset == 0) { + continue; + } + + // + // Check if CLKREQ# is supported by the endpoints + // + if ((QNCMmPci32 (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CAP_OFFSET)) + & B_QNC_PCIE_LCAP_CPM) != B_QNC_PCIE_LCAP_CPM) { + // + // CLKREQ# is not supported so dont do anything + // + return; + } + } + + // + // Now enable the CLKREQ# + // + for (Function = 0; Function < 8; Function++) { + // + // Find the PCIe Cap Id (offset 10h) + // + CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID); + if (CapOffset == 0) { + continue; + } + + QNCMmPci16Or (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CNT_OFFSET), BIT8); + } +} + +/** + + Configure ASPM automatically for both root port and downstream device. + + @param[in] RootBus Bus number of the root port + @param[in] RootDevice Device number of the root port + @param[in] RootFunction Function number of the root port + @param[in] EndpointBus Bus number of the downstream device + @param[in] EndpointDevice Device number of the downstream device + @param[in] EndpointFunction Function number of the downstream device + @param[in] LinkAspmVal Currently used ASPM setting + + @retval EFI_SUCCESS Configure ASPM successful + +**/ +EFI_STATUS +PcieSetAspmAuto ( + IN UINT8 RootBus, + IN UINT8 RootDevice, + IN UINT8 RootFunction, + IN UINT8 EndpointBus, + IN UINT8 EndpointDevice, + IN UINT8 EndpointFunction, + OUT UINT16 *LinkAspmVal + ) +{ + UINT32 RootPcieCapOffset; + UINT32 EndpointPcieCapOffset; + UINT16 RootPortAspm; + UINT16 EndPointAspm; + UINT16 AspmVal; + UINT32 PortLxLat; + UINT32 EndPointLxLat; + UINT32 LxLat; + + // + // Get the pointer to the Port PCI Express Capability Structure. + // + RootPcieCapOffset = PcieFindCapId (RootBus, RootDevice, RootFunction, PCIE_CAPID); + if (RootPcieCapOffset == 0) { + return EFI_UNSUPPORTED; + } + + // + // Get the pointer to the Endpoint PCI Express Capability Structure. + // + EndpointPcieCapOffset = PcieFindCapId (EndpointBus, EndpointDevice, EndpointFunction, PCIE_CAPID); + if (EndpointPcieCapOffset == 0) { + return EFI_UNSUPPORTED; + } + + // + // Obtain initial ASPM settings from respective port capability registers. + // + RootPortAspm = (QNCMmPci16 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET; + + // + // Configure downstream device if present. + // + EndPointAspm = (QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET; + + // + // TODO: Mask APMC with values from lookup table. + // RevID of 0xFF applies to all steppings. + // + + // TODO: Mask with latency/acceptable latency comparison results. + + AspmVal = RootPortAspm; + if (RootPortAspm > EndPointAspm) { + AspmVal = EndPointAspm; + } + + // + // Check if L1 should be enabled based on port and endpoint L1 exit latency. + // + if(AspmVal & BIT1) { + PortLxLat = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK; + EndPointLxLat = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK; + + LxLat = PortLxLat; + if(PortLxLat < EndPointLxLat) { + LxLat = EndPointLxLat; + } + + // + // check if the value is bigger than endpoint L1 acceptable exit latency, if it is + // larger than accepted value, then we should disable L1 + // + LxLat >>= 6; + if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E1AL)) { + AspmVal &= ~BIT1; + } + } + + // + // Check if L0s should be enabled based on port and endpoint L0s exit latency. + // + if(AspmVal & BIT0) { + PortLxLat = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset+ PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK; + EndPointLxLat = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK; + + LxLat = PortLxLat; + if(PortLxLat < EndPointLxLat) { + LxLat = EndPointLxLat; + } + + // + // check if the value is bigger than endpoint L0s acceptable exit latency, if it is + // larger than accepted value, then we should disable L0s + // + LxLat >>= 6; + if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E0AL)) { + AspmVal &= ~BIT0; + } + } + + RootPortAspm = AspmVal; + + *LinkAspmVal = AspmVal; + // + // Set Endpoint Aspm + // + QNCMmPci16AndThenOr (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, AspmVal); + + + // + // Set Root Port Aspm + // + QNCMmPci16AndThenOr (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, RootPortAspm); + + return EFI_SUCCESS; +} + +/** + + Configure ASPM based on the given setting for the interested device. + + @param[in] Bus Bus number of the interested device + @param[in] Device Device number of the interested device + @param[in] Function Function number of the interested device + @param[in] AspmSetting Aspm setting + @param[in] LinkAspmVal Currently used ASPM setting + + @retval EFI_SUCCESS Configure ASPM successful + +**/ +EFI_STATUS +PcieSetAspmManual ( + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Function, + IN UINT8 AspmSetting, + OUT UINT16 *LinkAspmVal + ) +{ + UINT32 PcieCapOffset; + UINT16 PortAspm; + + // + // Get the pointer to the Port PCI Express Capability Structure. + // + PcieCapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID); + if (PcieCapOffset == 0) { + return EFI_UNSUPPORTED; + } + + // Read the Link Capability register's ASPM setting + PortAspm = (QNCMmPci16 (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET; + // Mask it with the Setup selection + PortAspm &= AspmSetting; + + *LinkAspmVal = PortAspm; + // Write it to the Link Control register + QNCMmPci16AndThenOr (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, PortAspm); + + return EFI_SUCCESS; +} + +/** + + Perform Initialization on one PCI Express root port. + + @param[in] RootPortIndex Index of PCI Express root port + @param[in] RootPortConfig Pointer to the given pcie root port configuration + @param[in] PciExpressBar Base address of pcie space + @param[in] QNCRootComplexBar Base address of root complex + @param[in] QNCPmioBase Base address of PM IO space + @param[in] QNCGpeBase Base address of gpe IO space + + @retval EFI_SUCCESS Initialization successful + +**/ +EFI_STATUS +QNCRootPortInit ( + IN UINT32 RootPortIndex, + IN PCIEXP_ROOT_PORT_CONFIGURATION *RootPortConfig, + IN UINT64 PciExpressBar, + IN UINT32 QNCRootComplexBar, + IN UINT32 QNCPmioBase, + IN UINT32 QNCGpeBase + ) +{ + UINT64 RPBase; + UINT64 EndPointBase; + UINT16 AspmVal; + UINT16 SlotStatus; + UINTN Index; + UINT32 CapOffset; + UINT32 DwordReg; + + RPBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + ((PCI_DEVICE_NUMBER_PCIE_ROOTPORT) << 3) + ((PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex) << 0)) << 12); + CapOffset = PcieFindCapId (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), PCIE_CAPID); + + if (CapOffset == 0) { + return EFI_UNSUPPORTED; + } + + // + // Initialize "Slot Implmemented Bit" for this root port + // + if (RootPortConfig[RootPortIndex].Bits.SlotImplemented) { + QNCMmio16Or (RPBase, R_QNC_PCIE_XCAP, B_QNC_PCIE_XCAP_SI); + } + + // + // For Root Port Slots Numbering on the CRBs. + // Root Port 0 = Slot 1 + // Root Port 1 = Slot 2 + // Root Port 2 = Slot 3 + // Root Port 3 = Slot 4 + // + DwordReg = QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP); + DwordReg &= B_QNC_PCIE_SLCAP_MASK_RSV_VALUE; + DwordReg |= (V_QNC_PCIE_SLCAP_SLV << V_QNC_PCIE_SLCAP_SLV_OFFSET); + DwordReg |= ((RootPortConfig[RootPortIndex].Bits.PhysicalSlotNumber) << V_QNC_PCIE_SLCAP_PSN_OFFSET) ; + QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP) = DwordReg; + + // + // Check for a Presence Detect Change. + // + SlotStatus = QNCMmio16 (RPBase, R_QNC_PCIE_SLSTS); + if ((SlotStatus & (B_QNC_PCIE_SLSTS_PDS + B_QNC_PCIE_SLSTS_PDC)) == 0) { + return EFI_NOT_FOUND; + } + + // + // Temporarily Hardcode the Root Port Bridge Number to 2. + // + // This Endpoint check should immediately pass. Howerver, a 900ms delay + // has been added to match the timing requirements of the PCI Express Base + // Specification, Revision 1.0A, Section 6.6 ("...software must allow 1.0s + // after a reset of a device, before it may determine that a device which + // fails to return a Successful Completion status for a valid Configuration + // Request is a broken device"). Note that a 100ms delay was already added + // after the Root Ports were first taken out of reset. + // + QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF, 0x00020200); + // + // Only do this when a downstream device is present + // + EndPointBase = PciExpressBar + (((2 << 8) + (0 << 3) + (0 << 0)) << 12); + if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) { + for (Index = 0; Index < V_PCIE_MAX_TRY_TIMES; Index++){ + if (QNCMmio16 (EndPointBase, 0x0) != 0xFFFF) { + break; + } + PcieStall (15); + } + if (Index >= V_PCIE_MAX_TRY_TIMES) { + // + // Clear Bus Numbers. + // + QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF); + return EFI_NOT_FOUND; + } + } + + // + // PCI Express* Virtual Channels + // Clear TC1-7 Traffic classes. + // Map TC0-VC0 + // + PcieInitTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0); + PcieMapTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, 0x0); + + // + // Set Common Clock for inserted cards + // + if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) { + PcieSetCommonClock (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0); + } + + // + // Flow for Enabling ASPM + // + if (RootPortConfig[RootPortIndex].Bits.AspmEnable) { + if (RootPortConfig[RootPortIndex].Bits.AspmAutoEnable) { + PcieSetAspmAuto (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, &AspmVal); + } else { + // + // Set ASPM values according to setup selections, masked by capabilities + // + PcieSetAspmManual ( + PCI_BUS_NUMBER_QNC, + (UINT8) (PCI_DEVICE_NUMBER_PCIE_ROOTPORT), + (UINT8) (PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), + (UINT8) ((RootPortConfig[RootPortIndex].Bits.AspmL0sEnable & 0x01) | (RootPortConfig[RootPortIndex].Bits.AspmL1Enable << 1)), + &AspmVal + ); + } + } + + // + // Enable the PCIe CLKREQ# + // + if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) { + PcieSetClkreq (2, 0); + } + + // + // Clear Bus Numbers + // + QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF); + + // + // Additional configurations + // + + // + // PCI-E Unsupported Request Reporting Enable + // + if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_URE_ENABLE) { + QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_URE); + } + + // + // Device Fatal Error Reporting Enable + // + if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_FEE_ENABLE) { + QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_FEE); + } + + // + // Device Non Fatal Error Reporting Enable + // + if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_NFE_ENABLE) { + QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_NFE); + } + + // + // Device Correctable Error Reporting Enable + // + if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_CEE_ENABLE) { + QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_CEE); + } + // + // Root PCI-E PME Interrupt Enable + // + if (RootPortConfig[RootPortIndex].Bits.PmeInterruptEnable) { + QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_PIE); + } + // + // Root PCI-E System Error on Fatal Error Enable + // + if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SFE_ENABLE) { + QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SFE); + } + + // + // Root PCI-E System Error on Non-Fatal Error Enable + // + if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SNE_ENABLE) { + QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SNE); + } + + // + // Root PCI-E System Error on Correctable Error Enable + // + if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SCE_ENABLE) { + QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SCE); + } + + // + // Root PCI-E Powermanagement SCI Enabled + // + if (RootPortConfig[RootPortIndex].Bits.PmSciEnable) { + // + // Make sure that PME Interrupt Enable bit of Root Control register + // of PCI Express Capability struceture is cleared + // + QNCMmio32And (RPBase, R_QNC_PCIE_RCTL, (~B_QNC_PCIE_RCTL_PIE)); + QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_PMME), B_QNC_PCIE_MPC_PMCE); + + // + // Make sure GPE0 Stutus RW1C Bit is clear. + // + DwordReg = IoRead32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S); + if ((DwordReg & B_QNC_GPE0BLK_GPE0S_PCIE) != 0) { + IoWrite32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S, B_QNC_GPE0BLK_GPE0S_PCIE); + } + } + + // + // PCIe Hot Plug SCI Enable + // + if (RootPortConfig[RootPortIndex].Bits.HotplugSciEnable) { + // + // Write clear for : + // Attention Button Pressed (bit0) + // Presence Detect Changed (bit3) + // + QNCMmio32Or (RPBase, R_QNC_PCIE_SLSTS, (B_QNC_PCIE_SLSTS_PDC | B_QNC_PCIE_SLSTS_ABP)); + + // + // Sequence 2: Program the following bits in Slot Control register at offset 18h + // of PCI Express* Capability structure: + // Attention Button Pressed Enable (bit0) = 1b + // Presence Detect Changed Enable (bit3) = 1b + // Hot Plug Interrupt Enable (bit5) = 0b + // + QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_SLCTL, (~B_QNC_PCIE_SLCTL_HPE), (B_QNC_PCIE_SLCTL_PDE | B_QNC_PCIE_SLCTL_ABE)); + + // + // Sequence 3: Program Misc Port Config (MPC) register at PCI config space offset + // D8h as follows: + // Hot Plug SCI Enable (HPCE, bit30) = 1b + // Hot Plug SMI Enable (HPME, bit1) = 0b + // + QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_HPME), B_QNC_PCIE_MPC_HPCE); + } + + + return EFI_SUCCESS; +} + + +/** + Perform Initialization of the Downstream Root Ports +**/ +VOID +QNCDownStreamPortsInit ( + IN PCIEXP_ROOT_PORT_CONFIGURATION *RootPortConfig, + IN QNC_DEVICE_ENABLES *QNCDeviceEnables, + IN UINT64 PciExpressBar, + IN UINT32 QNCRootComplexBar, + IN UINT32 QNCPmioBase, + IN UINT32 QNCGpeBase, + OUT UINTN *RpEnableMask + ) +{ + EFI_STATUS Status; + UINT32 Index; + + // + // Initialize every root port and downstream device + // + for (Index = 0;Index < MAX_PCI_EXPRESS_ROOT_PORTS;Index++) { + if ((QNCDeviceEnables->Uint32 & (1 << Index)) != 0) { + Status = QNCRootPortInit ( + Index, + RootPortConfig, + PciExpressBar, + QNCRootComplexBar, + QNCPmioBase, + QNCGpeBase + ); + + if (!EFI_ERROR (Status)) { + (*RpEnableMask) |= LShiftU64(1, Index); + DEBUG ((EFI_D_INFO, " Root Port %x device found, enabled. RpEnableMask: 0x%x\n", Index + 1, *RpEnableMask)); + } + } + } +} + +/** + Do early init of pci express rootports on Soc. + +**/ + +VOID +EFIAPI +PciExpressEarlyInit ( + VOID + ) +{ + // + // Setup Message Bus Idle Counter (SBIC) values. + // + QNCMmPci8(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_IOSFSBCTL) = QNCMmPci8AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_IOSFSBCTL, (~B_QNC_PCIE_IOSFSBCTL_SBIC_MASK), V_PCIE_ROOT_PORT_SBIC_VALUE); + QNCMmPci8(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_IOSFSBCTL) = QNCMmPci8AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_IOSFSBCTL, (~B_QNC_PCIE_IOSFSBCTL_SBIC_MASK), V_PCIE_ROOT_PORT_SBIC_VALUE); + + // + // Program SVID/SID the same as VID/DID for Root ports. + // + QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, PCI_VENDOR_ID_OFFSET); + QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, PCI_VENDOR_ID_OFFSET); + + // + // Set the IPF bit in MCR2 + // + QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_MPC2) = QNCMmPci32Or(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_MPC2, B_QNC_PCIE_MPC2_IPF); + QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_MPC2) = QNCMmPci32Or(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_MPC2, B_QNC_PCIE_MPC2_IPF); + + // + // Set up the Posted and Non Posted Request sizes for PCIe + // + QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_CCFG) = QNCMmPci32AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_CCFG, ~B_QNC_PCIE_CCFG_UPSD, (B_QNC_PCIE_CCFG_UNRS | B_QNC_PCIE_CCFG_UPRS)); + + return; +} + + +/** + Complete initialization all the pci express rootports on Soc. +**/ +EFI_STATUS +EFIAPI +PciExpressInit ( + ) +{ + UINT64 PciExpressBar; + UINT32 QNCRootComplexBar; + UINT32 QNCPmioBase; + UINT32 QNCGpeBase; + UINTN RpEnableMask; + PCIEXP_ROOT_PORT_CONFIGURATION *mRootPortConfig; + QNC_DEVICE_ENABLES mQNCDeviceEnables; + + // + // Get BAR registers + // + QNCRootComplexBar = QNC_RCRB_BASE; + QNCPmioBase = LpcPciCfg32 (R_QNC_LPC_PM1BLK) & B_QNC_LPC_PM1BLK_MASK; + QNCGpeBase = LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & B_QNC_LPC_GPE0BLK_MASK; + RpEnableMask = 0; // assume all root ports are disabled + + PciExpressBar = PcdGet64 (PcdPciExpressBaseAddress); + + // + // Get platform information from PCD entries + // + mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables); + mRootPortConfig = (PCIEXP_ROOT_PORT_CONFIGURATION*) PcdGetPtr (PcdPcieRootPortConfiguration); + + DEBUG ((EFI_D_INFO, " mRootPortConfig: 0x%x, value1: 0x%x, value2: 0x%x, value3: 0x%x, value4: 0x%x\n", + mRootPortConfig, mRootPortConfig[0].Uint32, mRootPortConfig[1].Uint32, + mRootPortConfig[2].Uint32, mRootPortConfig[3].Uint32)); + + QNCDownStreamPortsInit ( + mRootPortConfig, + &mQNCDeviceEnables, + PciExpressBar, + QNCRootComplexBar, + QNCPmioBase, + QNCGpeBase, + &RpEnableMask + ); + + return EFI_SUCCESS; +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c new file mode 100644 index 0000000000..7df1c15f5b --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c @@ -0,0 +1,2112 @@ +/** @file +MTRR setting library + +Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include + +#define QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING 0x590 + +#define CACHE_MTRR_ENABLED 0x800 +#define CACHE_FIXED_MTRR_ENABLED 0x400 +#define IA32_MTRR_CAP_VCNT_MASK 0xFF + +// +// Context to save and restore when MTRRs are programmed +// +typedef struct { + UINTN Cr4; + BOOLEAN InterruptState; +} MTRR_CONTEXT; + +// +// This table defines the offset, base and length of the fixed MTRRs +// +CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = { + { QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000, 0, SIZE_64KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000, 0x80000, SIZE_16KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_A0000, 0xA0000, SIZE_16KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C0000, 0xC0000, SIZE_4KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C8000, 0xC8000, SIZE_4KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D0000, 0xD0000, SIZE_4KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D8000, 0xD8000, SIZE_4KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E0000, 0xE0000, SIZE_4KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E8000, 0xE8000, SIZE_4KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F0000, 0xF0000, SIZE_4KB }, + { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000, 0xF8000, SIZE_4KB } +}; + +// +// Lookup table used to print MTRRs +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = { + "UC", // CacheUncacheable + "WC", // CacheWriteCombining + "R*", // Invalid + "R*", // Invalid + "WT", // CacheWriteThrough + "WP", // CacheWriteProtected + "WB", // CacheWriteBack + "R*" // Invalid +}; + +UINT64 +MtrrRegisterRead ( + IN UINT32 MtrrRegister + ) +{ + UINT64 Result; + + Result = (UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister); + if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) { + Result = Result | LShiftU64 ((UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1), 32); + } + return Result; +} + +UINT64 +MtrrRegisterWrite ( + IN UINT32 MtrrRegister, + IN UINT64 Value + ) +{ + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister, (UINT32)Value); + if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) { + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1, (UINT32)RShiftU64 (Value, 32)); + } + return Value; +} + +UINT64 +MtrrRegisterBitFieldWrite ( + IN UINT32 MtrrRegister, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT64 Value + ) +{ + return MtrrRegisterWrite ( + MtrrRegister, + BitFieldWrite64 ( + MtrrRegisterRead (MtrrRegister), + StartBit, + EndBit, + Value + ) + ); +} + +/** + Worker function returns the variable MTRR count for the CPU. + + @return Variable MTRR count + +**/ +UINT32 +GetVariableMtrrCountWorker ( + VOID + ) +{ + UINT32 VariableMtrrCount; + + VariableMtrrCount = (UINT32)(MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP) & IA32_MTRR_CAP_VCNT_MASK); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + return VariableMtrrCount; +} + +/** + Returns the variable MTRR count for the CPU. + + @return Variable MTRR count + +**/ +UINT32 +EFIAPI +GetVariableMtrrCount ( + VOID + ) +{ + if (!IsMtrrSupported ()) { + return 0; + } + return GetVariableMtrrCountWorker (); +} + +/** + Worker function returns the firmware usable variable MTRR count for the CPU. + + @return Firmware usable variable MTRR count + +**/ +UINT32 +GetFirmwareVariableMtrrCountWorker ( + VOID + ) +{ + UINT32 VariableMtrrCount; + UINT32 ReservedMtrrNumber; + + VariableMtrrCount = GetVariableMtrrCountWorker (); + ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs); + if (VariableMtrrCount < ReservedMtrrNumber) { + return 0; + } + + return VariableMtrrCount - ReservedMtrrNumber; +} + +/** + Returns the firmware usable variable MTRR count for the CPU. + + @return Firmware usable variable MTRR count + +**/ +UINT32 +EFIAPI +GetFirmwareVariableMtrrCount ( + VOID + ) +{ + if (!IsMtrrSupported ()) { + return 0; + } + return GetFirmwareVariableMtrrCountWorker (); +} + +/** + Worker function returns the default MTRR cache type for the system. + + If MtrrSetting is not NULL, returns the default MTRR cache type from input + MTRR settings buffer. + If MtrrSetting is NULL, returns the default MTRR cache type from MSR. + + @param[in] MtrrSetting A buffer holding all MTRRs content. + + @return The default MTRR cache type. + +**/ +MTRR_MEMORY_CACHE_TYPE +MtrrGetDefaultMemoryTypeWorker ( + IN MTRR_SETTINGS *MtrrSetting + ) +{ + if (MtrrSetting == NULL) { + return (MTRR_MEMORY_CACHE_TYPE) (MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE) & 0x7); + } else { + return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7); + } +} + + +/** + Returns the default MTRR cache type for the system. + + @return The default MTRR cache type. + +**/ +MTRR_MEMORY_CACHE_TYPE +EFIAPI +MtrrGetDefaultMemoryType ( + VOID + ) +{ + if (!IsMtrrSupported ()) { + return CacheUncacheable; + } + return MtrrGetDefaultMemoryTypeWorker (NULL); +} + +/** + Preparation before programming MTRR. + + This function will do some preparation for programming MTRRs: + disable cache, invalid cache and disable MTRR caching functionality + + @param[out] MtrrContext Pointer to context to save + +**/ +VOID +PreMtrrChange ( + OUT MTRR_CONTEXT *MtrrContext + ) +{ + // + // Disable interrupts and save current interrupt state + // + MtrrContext->InterruptState = SaveAndDisableInterrupts(); + + // + // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29) + // + AsmDisableCache (); + + // + // Save original CR4 value and clear PGE flag (Bit 7) + // + MtrrContext->Cr4 = AsmReadCr4 (); + AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7)); + + // + // Flush all TLBs + // + CpuFlushTlb (); + + // + // Disable MTRRs + // + MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 0); +} + +/** + Cleaning up after programming MTRRs. + + This function will do some clean up after programming MTRRs: + Flush all TLBs, re-enable caching, restore CR4. + + @param[in] MtrrContext Pointer to context to restore + +**/ +VOID +PostMtrrChangeEnableCache ( + IN MTRR_CONTEXT *MtrrContext + ) +{ + // + // Flush all TLBs + // + CpuFlushTlb (); + + // + // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29) + // + AsmEnableCache (); + + // + // Restore original CR4 value + // + AsmWriteCr4 (MtrrContext->Cr4); + + // + // Restore original interrupt state + // + SetInterruptState (MtrrContext->InterruptState); +} + +/** + Cleaning up after programming MTRRs. + + This function will do some clean up after programming MTRRs: + enable MTRR caching functionality, and enable cache + + @param[in] MtrrContext Pointer to context to restore + +**/ +VOID +PostMtrrChange ( + IN MTRR_CONTEXT *MtrrContext + ) +{ + // + // Enable Cache MTRR + // + MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 3); + + PostMtrrChangeEnableCache (MtrrContext); +} + +/** + Worker function gets the content in fixed MTRRs + + @param[out] FixedSettings A buffer to hold fixed MTRRs content. + + @retval The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +MtrrGetFixedMtrrWorker ( + OUT MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + UINT32 Index; + + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + FixedSettings->Mtrr[Index] = + MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr); + } + + return FixedSettings; +} + + +/** + This function gets the content in fixed MTRRs + + @param[out] FixedSettings A buffer to hold fixed MTRRs content. + + @retval The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +EFIAPI +MtrrGetFixedMtrr ( + OUT MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + if (!IsMtrrSupported ()) { + return FixedSettings; + } + + return MtrrGetFixedMtrrWorker (FixedSettings); +} + + +/** + Worker function will get the raw value in variable MTRRs + + If MtrrSetting is not NULL, gets the variable MTRRs raw value from input + MTRR settings buffer. + If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs. + + @param[in] MtrrSetting A buffer holding all MTRRs content. + @param[in] VariableMtrrCount Number of variable MTRRs. + @param[out] VariableSettings A buffer to hold variable MTRRs content. + + @return The VariableSettings input pointer + +**/ +MTRR_VARIABLE_SETTINGS* +MtrrGetVariableMtrrWorker ( + IN MTRR_SETTINGS *MtrrSetting, + IN UINT32 VariableMtrrCount, + OUT MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + UINT32 Index; + + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + for (Index = 0; Index < VariableMtrrCount; Index++) { + if (MtrrSetting == NULL) { + VariableSettings->Mtrr[Index].Base = + MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1)); + VariableSettings->Mtrr[Index].Mask = + MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1); + } else { + VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base; + VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask; + } + } + + return VariableSettings; +} + +/** + This function will get the raw value in variable MTRRs + + @param[out] VariableSettings A buffer to hold variable MTRRs content. + + @return The VariableSettings input pointer + +**/ +MTRR_VARIABLE_SETTINGS* +EFIAPI +MtrrGetVariableMtrr ( + OUT MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + if (!IsMtrrSupported ()) { + return VariableSettings; + } + + return MtrrGetVariableMtrrWorker ( + NULL, + GetVariableMtrrCountWorker (), + VariableSettings + ); +} + +/** + Programs fixed MTRRs registers. + + @param[in] MemoryCacheType The memory type to set. + @param[in, out] Base The base address of memory range. + @param[in, out] Length The length of memory range. + @param[out] ReturnMsrNum The index of the fixed MTRR MSR to program. + @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR. + @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR. + + @retval RETURN_SUCCESS The cache type was updated successfully + @retval RETURN_UNSUPPORTED The requested range or cache type was invalid + for the fixed MTRRs. + +**/ +RETURN_STATUS +ProgramFixedMtrr ( + IN UINT64 MemoryCacheType, + IN OUT UINT64 *Base, + IN OUT UINT64 *Length, + OUT UINT32 *ReturnMsrNum, + OUT UINT64 *ReturnClearMask, + OUT UINT64 *ReturnOrMask + ) +{ + UINT32 MsrNum; + UINT32 ByteShift; + UINT64 OrMask; + UINT64 ClearMask; + + OrMask = 0; + ClearMask = 0; + + for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) { + if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) && + (*Base < + ( + mMtrrLibFixedMtrrTable[MsrNum].BaseAddress + + (8 * mMtrrLibFixedMtrrTable[MsrNum].Length) + ) + ) + ) { + break; + } + } + + if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) { + return RETURN_UNSUPPORTED; + } + + // + // We found the fixed MTRR to be programmed + // + for (ByteShift = 0; ByteShift < 8; ByteShift++) { + if (*Base == + ( + mMtrrLibFixedMtrrTable[MsrNum].BaseAddress + + (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length) + ) + ) { + break; + } + } + + if (ByteShift == 8) { + return RETURN_UNSUPPORTED; + } + + for ( + ; + ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length)); + ByteShift++ + ) { + OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8)); + ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8)); + *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length; + *Base += mMtrrLibFixedMtrrTable[MsrNum].Length; + } + + if (ByteShift < 8 && (*Length != 0)) { + return RETURN_UNSUPPORTED; + } + + *ReturnMsrNum = MsrNum; + *ReturnClearMask = ClearMask; + *ReturnOrMask = OrMask; + + return RETURN_SUCCESS; +} + + +/** + Worker function gets the attribute of variable MTRRs. + + This function shadows the content of variable MTRRs into an + internal array: VariableMtrr. + + @param[in] VariableSettings The variable MTRR values to shadow + @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware + @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR + @param[in] MtrrValidAddressMask The valid address mask for MTRR + @param[out] VariableMtrr The array to shadow variable MTRRs content + + @return The return value of this parameter indicates the + number of MTRRs which has been used. + +**/ +UINT32 +MtrrGetMemoryAttributeInVariableMtrrWorker ( + IN MTRR_VARIABLE_SETTINGS *VariableSettings, + IN UINTN FirmwareVariableMtrrCount, + IN UINT64 MtrrValidBitsMask, + IN UINT64 MtrrValidAddressMask, + OUT VARIABLE_MTRR *VariableMtrr + ) +{ + UINTN Index; + UINT32 UsedMtrr; + + ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR); + for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) { + if ((VariableSettings->Mtrr[Index].Mask & CACHE_MTRR_ENABLED) != 0) { + VariableMtrr[Index].Msr = (UINT32)Index; + VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask); + VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1; + VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff); + VariableMtrr[Index].Valid = TRUE; + VariableMtrr[Index].Used = TRUE; + UsedMtrr++; + } + } + return UsedMtrr; +} + + +/** + Gets the attribute of variable MTRRs. + + This function shadows the content of variable MTRRs into an + internal array: VariableMtrr. + + @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR + @param[in] MtrrValidAddressMask The valid address mask for MTRR + @param[out] VariableMtrr The array to shadow variable MTRRs content + + @return The return value of this parameter indicates the + number of MTRRs which has been used. + +**/ +UINT32 +EFIAPI +MtrrGetMemoryAttributeInVariableMtrr ( + IN UINT64 MtrrValidBitsMask, + IN UINT64 MtrrValidAddressMask, + OUT VARIABLE_MTRR *VariableMtrr + ) +{ + MTRR_VARIABLE_SETTINGS VariableSettings; + + if (!IsMtrrSupported ()) { + return 0; + } + + MtrrGetVariableMtrrWorker ( + NULL, + GetVariableMtrrCountWorker (), + &VariableSettings + ); + + return MtrrGetMemoryAttributeInVariableMtrrWorker ( + &VariableSettings, + GetFirmwareVariableMtrrCountWorker (), + MtrrValidBitsMask, + MtrrValidAddressMask, + VariableMtrr + ); +} + + +/** + Checks overlap between given memory range and MTRRs. + + @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available + to firmware. + @param[in] Start The start address of memory range. + @param[in] End The end address of memory range. + @param[in] VariableMtrr The array to shadow variable MTRRs content + + @retval TRUE Overlap exists. + @retval FALSE No overlap. + +**/ +BOOLEAN +CheckMemoryAttributeOverlap ( + IN UINTN FirmwareVariableMtrrCount, + IN PHYSICAL_ADDRESS Start, + IN PHYSICAL_ADDRESS End, + IN VARIABLE_MTRR *VariableMtrr + ) +{ + UINT32 Index; + + for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) { + if ( + VariableMtrr[Index].Valid && + !( + (Start > (VariableMtrr[Index].BaseAddress + + VariableMtrr[Index].Length - 1) + ) || + (End < VariableMtrr[Index].BaseAddress) + ) + ) { + return TRUE; + } + } + + return FALSE; +} + + +/** + Marks a variable MTRR as non-valid. + + @param[in] Index The index of the array VariableMtrr to be invalidated + @param[in] VariableMtrr The array to shadow variable MTRRs content + @param[out] UsedMtrr The number of MTRRs which has already been used + +**/ +VOID +InvalidateShadowMtrr ( + IN UINTN Index, + IN VARIABLE_MTRR *VariableMtrr, + OUT UINT32 *UsedMtrr + ) +{ + VariableMtrr[Index].Valid = FALSE; + *UsedMtrr = *UsedMtrr - 1; +} + + +/** + Combines memory attributes. + + If overlap exists between given memory range and MTRRs, try to combine them. + + @param[in] FirmwareVariableMtrrCount The number of variable MTRRs + available to firmware. + @param[in] Attributes The memory type to set. + @param[in, out] Base The base address of memory range. + @param[in, out] Length The length of memory range. + @param[in] VariableMtrr The array to shadow variable MTRRs content + @param[in, out] UsedMtrr The number of MTRRs which has already been used + @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used + + @retval EFI_SUCCESS Memory region successfully combined. + @retval EFI_ACCESS_DENIED Memory region cannot be combined. + +**/ +RETURN_STATUS +CombineMemoryAttribute ( + IN UINT32 FirmwareVariableMtrrCount, + IN UINT64 Attributes, + IN OUT UINT64 *Base, + IN OUT UINT64 *Length, + IN VARIABLE_MTRR *VariableMtrr, + IN OUT UINT32 *UsedMtrr, + OUT BOOLEAN *OverwriteExistingMtrr + ) +{ + UINT32 Index; + UINT64 CombineStart; + UINT64 CombineEnd; + UINT64 MtrrEnd; + UINT64 EndAddress; + BOOLEAN CoveredByExistingMtrr; + + *OverwriteExistingMtrr = FALSE; + CoveredByExistingMtrr = FALSE; + EndAddress = *Base +*Length - 1; + + for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) { + + MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1; + if ( + !VariableMtrr[Index].Valid || + ( + *Base > (MtrrEnd) || + (EndAddress < VariableMtrr[Index].BaseAddress) + ) + ) { + continue; + } + + // + // Combine same attribute MTRR range + // + if (Attributes == VariableMtrr[Index].Type) { + // + // if the MTRR range contain the request range, set a flag, then continue to + // invalidate any MTRR of the same request range with higher priority cache type. + // + if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) { + CoveredByExistingMtrr = TRUE; + continue; + } + // + // invalid this MTRR, and program the combine range + // + CombineStart = + (*Base) < VariableMtrr[Index].BaseAddress ? + (*Base) : + VariableMtrr[Index].BaseAddress; + CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd; + + // + // Record the MTRR usage status in VariableMtrr array. + // + InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr); + *Base = CombineStart; + *Length = CombineEnd - CombineStart + 1; + EndAddress = CombineEnd; + *OverwriteExistingMtrr = TRUE; + continue; + } else { + // + // The cache type is different, but the range is convered by one MTRR + // + if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) { + InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr); + continue; + } + + } + + if ((Attributes== MTRR_CACHE_WRITE_THROUGH && + VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) || + (Attributes == MTRR_CACHE_WRITE_BACK && + VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) || + (Attributes == MTRR_CACHE_UNCACHEABLE) || + (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) + ) { + *OverwriteExistingMtrr = TRUE; + continue; + } + // + // Other type memory overlap is invalid + // + return RETURN_ACCESS_DENIED; + } + + if (CoveredByExistingMtrr) { + *Length = 0; + } + + return RETURN_SUCCESS; +} + + +/** + Calculates the maximum value which is a power of 2, but less the MemoryLength. + + @param[in] MemoryLength The number to pass in. + + @return The maximum value which is align to power of 2 and less the MemoryLength + +**/ +UINT64 +Power2MaxMemory ( + IN UINT64 MemoryLength + ) +{ + UINT64 Result; + + if (RShiftU64 (MemoryLength, 32) != 0) { + Result = LShiftU64 ( + (UINT64) GetPowerOfTwo32 ( + (UINT32) RShiftU64 (MemoryLength, 32) + ), + 32 + ); + } else { + Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength); + } + + return Result; +} + + +/** + Determines the MTRR numbers used to program a memory range. + + This function first checks the alignment of the base address. + If the alignment of the base address <= Length, cover the memory range + (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and + Length -= alignment. Repeat the step until alignment > Length. + + Then this function determines which direction of programming the variable + MTRRs for the remaining length will use fewer MTRRs. + + @param[in] BaseAddress Length of Memory to program MTRR + @param[in] Length Length of Memory to program MTRR + @param[in] MtrrNumber Pointer to the number of necessary MTRRs + + @retval TRUE Positive direction is better. + FALSE Negative direction is better. + +**/ +BOOLEAN +GetMtrrNumberAndDirection ( + IN UINT64 BaseAddress, + IN UINT64 Length, + IN UINTN *MtrrNumber + ) +{ + UINT64 TempQword; + UINT64 Alignment; + UINT32 Positive; + UINT32 Subtractive; + + *MtrrNumber = 0; + + if (BaseAddress != 0) { + do { + // + // Calculate the alignment of the base address. + // + Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress)); + + if (Alignment > Length) { + break; + } + + (*MtrrNumber)++; + BaseAddress += Alignment; + Length -= Alignment; + } while (TRUE); + + if (Length == 0) { + return TRUE; + } + } + + TempQword = Length; + Positive = 0; + Subtractive = 0; + + do { + TempQword -= Power2MaxMemory (TempQword); + Positive++; + } while (TempQword != 0); + + TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length; + Subtractive++; + do { + TempQword -= Power2MaxMemory (TempQword); + Subtractive++; + } while (TempQword != 0); + + if (Positive <= Subtractive) { + *MtrrNumber += Positive; + return TRUE; + } else { + *MtrrNumber += Subtractive; + return FALSE; + } +} + +/** + Invalid variable MTRRs according to the value in the shadow array. + + This function programs MTRRs according to the values specified + in the shadow array. + + @param[in, out] VariableSettings Variable MTRR settings + @param[in] VariableMtrrCount Number of variable MTRRs + @param[in, out] VariableMtrr Shadow of variable MTRR contents + +**/ +VOID +InvalidateMtrr ( + IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings, + IN UINTN VariableMtrrCount, + IN OUT VARIABLE_MTRR *VariableMtrr + ) +{ + UINTN Index; + + for (Index = 0; Index < VariableMtrrCount; Index++) { + if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) { + VariableSettings->Mtrr[Index].Base = 0; + VariableSettings->Mtrr[Index].Mask = 0; + VariableMtrr[Index].Used = FALSE; + } + } +} + + +/** + Programs variable MTRRs + + This function programs variable MTRRs + + @param[in, out] VariableSettings Variable MTRR settings. + @param[in] MtrrNumber Index of MTRR to program. + @param[in] BaseAddress Base address of memory region. + @param[in] Length Length of memory region. + @param[in] MemoryCacheType Memory type to set. + @param[in] MtrrValidAddressMask The valid address mask for MTRR + +**/ +VOID +ProgramVariableMtrr ( + IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings, + IN UINTN MtrrNumber, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 MemoryCacheType, + IN UINT64 MtrrValidAddressMask + ) +{ + UINT64 TempQword; + + // + // MTRR Physical Base + // + TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType; + VariableSettings->Mtrr[MtrrNumber].Base = TempQword; + + // + // MTRR Physical Mask + // + TempQword = ~(Length - 1); + VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | CACHE_MTRR_ENABLED; +} + + +/** + Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE. + + If MtrrSetting is not NULL, gets the default memory attribute from input + MTRR settings buffer. + If MtrrSetting is NULL, gets the default memory attribute from MSR. + + @param[in] MtrrSetting A buffer holding all MTRRs content. + @param[in] MtrrType MTRR memory type + + @return The enum item in MTRR_MEMORY_CACHE_TYPE + +**/ +MTRR_MEMORY_CACHE_TYPE +GetMemoryCacheTypeFromMtrrType ( + IN MTRR_SETTINGS *MtrrSetting, + IN UINT64 MtrrType + ) +{ + switch (MtrrType) { + case MTRR_CACHE_UNCACHEABLE: + return CacheUncacheable; + case MTRR_CACHE_WRITE_COMBINING: + return CacheWriteCombining; + case MTRR_CACHE_WRITE_THROUGH: + return CacheWriteThrough; + case MTRR_CACHE_WRITE_PROTECTED: + return CacheWriteProtected; + case MTRR_CACHE_WRITE_BACK: + return CacheWriteBack; + default: + // + // MtrrType is MTRR_CACHE_INVALID_TYPE, that means + // no MTRR covers the range + // + return MtrrGetDefaultMemoryTypeWorker (MtrrSetting); + } +} + +/** + Initializes the valid bits mask and valid address mask for MTRRs. + + This function initializes the valid bits mask and valid address mask for MTRRs. + + @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR + @param[out] MtrrValidAddressMask The valid address mask for the MTRR + +**/ +VOID +MtrrLibInitializeMtrrMask ( + OUT UINT64 *MtrrValidBitsMask, + OUT UINT64 *MtrrValidAddressMask + ) +{ + UINT32 RegEax; + UINT8 PhysicalAddressBits; + + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + + PhysicalAddressBits = (UINT8) RegEax; + } else { + PhysicalAddressBits = 36; + } + + *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1; + *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL; +} + + +/** + Determines the real attribute of a memory range. + + This function is to arbitrate the real attribute of the memory when + there are 2 MTRRs covers the same memory range. For further details, + please refer the IA32 Software Developer's Manual, Volume 3, + Section 10.11.4.1. + + @param[in] MtrrType1 The first kind of Memory type + @param[in] MtrrType2 The second kind of memory type + +**/ +UINT64 +MtrrPrecedence ( + IN UINT64 MtrrType1, + IN UINT64 MtrrType2 + ) +{ + UINT64 MtrrType; + + MtrrType = MTRR_CACHE_INVALID_TYPE; + switch (MtrrType1) { + case MTRR_CACHE_UNCACHEABLE: + MtrrType = MTRR_CACHE_UNCACHEABLE; + break; + case MTRR_CACHE_WRITE_COMBINING: + if ( + MtrrType2==MTRR_CACHE_WRITE_COMBINING || + MtrrType2==MTRR_CACHE_UNCACHEABLE + ) { + MtrrType = MtrrType2; + } + break; + case MTRR_CACHE_WRITE_THROUGH: + if ( + MtrrType2==MTRR_CACHE_WRITE_THROUGH || + MtrrType2==MTRR_CACHE_WRITE_BACK + ) { + MtrrType = MTRR_CACHE_WRITE_THROUGH; + } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) { + MtrrType = MTRR_CACHE_UNCACHEABLE; + } + break; + case MTRR_CACHE_WRITE_PROTECTED: + if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED || + MtrrType2 == MTRR_CACHE_UNCACHEABLE) { + MtrrType = MtrrType2; + } + break; + case MTRR_CACHE_WRITE_BACK: + if ( + MtrrType2== MTRR_CACHE_UNCACHEABLE || + MtrrType2==MTRR_CACHE_WRITE_THROUGH || + MtrrType2== MTRR_CACHE_WRITE_BACK + ) { + MtrrType = MtrrType2; + } + break; + case MTRR_CACHE_INVALID_TYPE: + MtrrType = MtrrType2; + break; + default: + break; + } + + if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) { + MtrrType = MtrrType1; + } + return MtrrType; +} + +/** + Worker function will get the memory cache type of the specific address. + + If MtrrSetting is not NULL, gets the memory cache type from input + MTRR settings buffer. + If MtrrSetting is NULL, gets the memory cache type from MTRRs. + + @param[in] MtrrSetting A buffer holding all MTRRs content. + @param[in] Address The specific address + + @return Memory cache type of the specific address + +**/ +MTRR_MEMORY_CACHE_TYPE +MtrrGetMemoryAttributeByAddressWorker ( + IN MTRR_SETTINGS *MtrrSetting, + IN PHYSICAL_ADDRESS Address + ) +{ + UINT64 TempQword; + UINTN Index; + UINTN SubIndex; + UINT64 MtrrType; + UINT64 TempMtrrType; + MTRR_MEMORY_CACHE_TYPE CacheType; + VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + UINTN VariableMtrrCount; + MTRR_VARIABLE_SETTINGS VariableSettings; + + // + // Check if MTRR is enabled, if not, return UC as attribute + // + if (MtrrSetting == NULL) { + TempQword = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE); + } else { + TempQword = MtrrSetting->MtrrDefType; + } + MtrrType = MTRR_CACHE_INVALID_TYPE; + + if ((TempQword & CACHE_MTRR_ENABLED) == 0) { + return CacheUncacheable; + } + + // + // If address is less than 1M, then try to go through the fixed MTRR + // + if (Address < BASE_1MB) { + if ((TempQword & CACHE_FIXED_MTRR_ENABLED) != 0) { + // + // Go through the fixed MTRR + // + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress && + Address < ( + mMtrrLibFixedMtrrTable[Index].BaseAddress + + (mMtrrLibFixedMtrrTable[Index].Length * 8) + ) + ) { + SubIndex = + ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) / + mMtrrLibFixedMtrrTable[Index].Length; + if (MtrrSetting == NULL) { + TempQword = MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr); + } else { + TempQword = MtrrSetting->Fixed.Mtrr[Index]; + } + MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF; + return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType); + } + } + } + } + MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); + + MtrrGetVariableMtrrWorker ( + MtrrSetting, + GetVariableMtrrCountWorker (), + &VariableSettings + ); + + MtrrGetMemoryAttributeInVariableMtrrWorker ( + &VariableSettings, + GetFirmwareVariableMtrrCountWorker (), + MtrrValidBitsMask, + MtrrValidAddressMask, + VariableMtrr + ); + + // + // Go through the variable MTRR + // + VariableMtrrCount = GetVariableMtrrCountWorker (); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + for (Index = 0; Index < VariableMtrrCount; Index++) { + if (VariableMtrr[Index].Valid) { + if (Address >= VariableMtrr[Index].BaseAddress && + Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) { + TempMtrrType = VariableMtrr[Index].Type; + MtrrType = MtrrPrecedence (MtrrType, TempMtrrType); + } + } + } + CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType); + + return CacheType; +} + + +/** + This function will get the memory cache type of the specific address. + + This function is mainly for debug purpose. + + @param[in] Address The specific address + + @return Memory cache type of the specific address + +**/ +MTRR_MEMORY_CACHE_TYPE +EFIAPI +MtrrGetMemoryAttribute ( + IN PHYSICAL_ADDRESS Address + ) +{ + if (!IsMtrrSupported ()) { + return CacheUncacheable; + } + + return MtrrGetMemoryAttributeByAddressWorker (NULL, Address); +} + +/** + Worker function prints all MTRRs for debugging. + + If MtrrSetting is not NULL, print MTRR settings from from input MTRR + settings buffer. + If MtrrSetting is NULL, print MTRR settings from MTRRs. + + @param MtrrSetting A buffer holding all MTRRs content. +**/ +VOID +MtrrDebugPrintAllMtrrsWorker ( + IN MTRR_SETTINGS *MtrrSetting + ) +{ + DEBUG_CODE ( + MTRR_SETTINGS LocalMtrrs; + MTRR_SETTINGS *Mtrrs; + UINTN Index; + UINTN Index1; + UINTN VariableMtrrCount; + UINT64 Base; + UINT64 Limit; + UINT64 MtrrBase; + UINT64 MtrrLimit; + UINT64 RangeBase; + UINT64 RangeLimit; + UINT64 NoRangeBase; + UINT64 NoRangeLimit; + UINT32 RegEax; + UINTN MemoryType; + UINTN PreviousMemoryType; + BOOLEAN Found; + + if (!IsMtrrSupported ()) { + return; + } + + DEBUG((DEBUG_CACHE, "MTRR Settings\n")); + DEBUG((DEBUG_CACHE, "=============\n")); + + if (MtrrSetting != NULL) { + Mtrrs = MtrrSetting; + } else { + MtrrGetAllMtrrs (&LocalMtrrs); + Mtrrs = &LocalMtrrs; + } + + DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType)); + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index])); + } + + VariableMtrrCount = GetVariableMtrrCount (); + for (Index = 0; Index < VariableMtrrCount; Index++) { + DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n", + Index, + Mtrrs->Variables.Mtrr[Index].Base, + Mtrrs->Variables.Mtrr[Index].Mask + )); + } + DEBUG((DEBUG_CACHE, "\n")); + DEBUG((DEBUG_CACHE, "MTRR Ranges\n")); + DEBUG((DEBUG_CACHE, "====================================\n")); + + Base = 0; + PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + Base = mMtrrLibFixedMtrrTable[Index].BaseAddress; + for (Index1 = 0; Index1 < 8; Index1++) { + MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff); + if (MemoryType > CacheWriteBack) { + MemoryType = MTRR_CACHE_INVALID_TYPE; + } + if (MemoryType != PreviousMemoryType) { + if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { + DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); + } + PreviousMemoryType = MemoryType; + DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); + } + Base += mMtrrLibFixedMtrrTable[Index].Length; + } + } + DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); + + VariableMtrrCount = GetVariableMtrrCount (); + + Limit = BIT36 - 1; + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + Limit = LShiftU64 (1, RegEax & 0xff) - 1; + } + Base = BASE_1MB; + PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; + do { + MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base); + if (MemoryType > CacheWriteBack) { + MemoryType = MTRR_CACHE_INVALID_TYPE; + } + + if (MemoryType != PreviousMemoryType) { + if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { + DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); + } + PreviousMemoryType = MemoryType; + DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); + } + + RangeBase = BASE_1MB; + NoRangeBase = BASE_1MB; + RangeLimit = Limit; + NoRangeLimit = Limit; + + for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) { + if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) { + // + // If mask is not valid, then do not display range + // + continue; + } + MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1))); + MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit); + + if (Base >= MtrrBase && Base < MtrrLimit) { + Found = TRUE; + } + + if (Base >= MtrrBase && MtrrBase > RangeBase) { + RangeBase = MtrrBase; + } + if (Base > MtrrLimit && MtrrLimit > RangeBase) { + RangeBase = MtrrLimit + 1; + } + if (Base < MtrrBase && MtrrBase < RangeLimit) { + RangeLimit = MtrrBase - 1; + } + if (Base < MtrrLimit && MtrrLimit <= RangeLimit) { + RangeLimit = MtrrLimit; + } + + if (Base > MtrrLimit && NoRangeBase < MtrrLimit) { + NoRangeBase = MtrrLimit + 1; + } + if (Base < MtrrBase && NoRangeLimit > MtrrBase) { + NoRangeLimit = MtrrBase - 1; + } + } + + if (Found) { + Base = RangeLimit + 1; + } else { + Base = NoRangeLimit + 1; + } + } while (Base < Limit); + DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1)); + ); +} + + +/** + This function prints all MTRRs for debugging. +**/ +VOID +EFIAPI +MtrrDebugPrintAllMtrrs ( + VOID + ) +{ + MtrrDebugPrintAllMtrrsWorker (NULL); +} + + +/** + Worker function attempts to set the attributes for a memory range. + + If MtrrSettings is not NULL, set the attributes into the input MTRR + settings buffer. + If MtrrSettings is NULL, set the attributes into MTRRs registers. + + @param[in, out] MtrrSetting A buffer holding all MTRRs content. + @param[in] BaseAddress The physical address that is the start + address of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attribute The bit mask of attributes to set for the + memory region. + + @retval RETURN_SUCCESS The attributes were set for the memory + region. + @retval RETURN_INVALID_PARAMETER Length is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or + more bytes of the memory resource range + specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support + for the memory resource range specified + by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource + range specified by BaseAddress and Length + cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to + modify the attributes of the memory + resource range. + +**/ +RETURN_STATUS +MtrrSetMemoryAttributeWorker ( + IN OUT MTRR_SETTINGS *MtrrSetting, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ) +{ + UINT64 TempQword; + RETURN_STATUS Status; + UINT64 MemoryType; + UINT64 Alignment; + BOOLEAN OverLap; + BOOLEAN Positive; + UINT32 MsrNum; + UINTN MtrrNumber; + VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; + UINT32 UsedMtrr; + UINT64 MtrrValidBitsMask; + UINT64 MtrrValidAddressMask; + BOOLEAN OverwriteExistingMtrr; + UINT32 FirmwareVariableMtrrCount; + MTRR_CONTEXT MtrrContext; + BOOLEAN MtrrContextValid; + BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR]; + BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR]; + MTRR_FIXED_SETTINGS WorkingFixedSettings; + UINT32 VariableMtrrCount; + MTRR_VARIABLE_SETTINGS OriginalVariableSettings; + BOOLEAN ProgramVariableSettings; + MTRR_VARIABLE_SETTINGS WorkingVariableSettings; + UINT32 Index; + UINT64 ClearMask; + UINT64 OrMask; + UINT64 NewValue; + MTRR_VARIABLE_SETTINGS *VariableSettings; + + MtrrContextValid = FALSE; + VariableMtrrCount = 0; + ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings)); + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + FixedSettingsValid[Index] = FALSE; + FixedSettingsModified[Index] = FALSE; + } + ProgramVariableSettings = FALSE; + + if (!IsMtrrSupported ()) { + Status = RETURN_UNSUPPORTED; + goto Done; + } + + MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask); + + TempQword = 0; + MemoryType = (UINT64)Attribute; + OverwriteExistingMtrr = FALSE; + + // + // Check for an invalid parameter + // + if (Length == 0) { + Status = RETURN_INVALID_PARAMETER; + goto Done; + } + + if ( + (BaseAddress & ~MtrrValidAddressMask) != 0 || + (Length & ~MtrrValidAddressMask) != 0 + ) { + Status = RETURN_UNSUPPORTED; + goto Done; + } + + // + // Check if Fixed MTRR + // + Status = RETURN_SUCCESS; + if (BaseAddress < BASE_1MB) { + while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { + Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask); + if (RETURN_ERROR (Status)) { + goto Done; + } + if (MtrrSetting != NULL) { + MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask; + MtrrSetting->MtrrDefType |= CACHE_FIXED_MTRR_ENABLED; + } else { + if (!FixedSettingsValid[MsrNum]) { + WorkingFixedSettings.Mtrr[MsrNum] = MtrrRegisterRead (mMtrrLibFixedMtrrTable[MsrNum].Msr); + FixedSettingsValid[MsrNum] = TRUE; + } + NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask; + if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) { + WorkingFixedSettings.Mtrr[MsrNum] = NewValue; + FixedSettingsModified[MsrNum] = TRUE; + } + } + } + + if (Length == 0) { + // + // A Length of 0 can only make sense for fixed MTTR ranges. + // Since we just handled the fixed MTRRs, we can skip the + // variable MTRR section. + // + goto Done; + } + } + + // + // Since memory ranges below 1MB will be overridden by the fixed MTRRs, + // we can set the base to 0 to save variable MTRRs. + // + if (BaseAddress == BASE_1MB) { + BaseAddress = 0; + Length += SIZE_1MB; + } + + // + // Read all variable MTRRs + // + VariableMtrrCount = GetVariableMtrrCountWorker (); + FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker (); + if (MtrrSetting != NULL) { + VariableSettings = &MtrrSetting->Variables; + } else { + MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings); + CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings)); + ProgramVariableSettings = TRUE; + VariableSettings = &WorkingVariableSettings; + } + + // + // Check for overlap + // + UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker ( + VariableSettings, + FirmwareVariableMtrrCount, + MtrrValidBitsMask, + MtrrValidAddressMask, + VariableMtrr + ); + OverLap = CheckMemoryAttributeOverlap ( + FirmwareVariableMtrrCount, + BaseAddress, + BaseAddress + Length - 1, + VariableMtrr + ); + if (OverLap) { + Status = CombineMemoryAttribute ( + FirmwareVariableMtrrCount, + MemoryType, + &BaseAddress, + &Length, + VariableMtrr, + &UsedMtrr, + &OverwriteExistingMtrr + ); + if (RETURN_ERROR (Status)) { + goto Done; + } + + if (Length == 0) { + // + // Combined successfully, invalidate the now-unused MTRRs + // + InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr); + Status = RETURN_SUCCESS; + goto Done; + } + } + + // + // The memory type is the same with the type specified by + // MTRR_LIB_IA32_MTRR_DEF_TYPE. + // + if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) { + // + // Invalidate the now-unused MTRRs + // + InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr); + goto Done; + } + + Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber); + + if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) { + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + + // + // Invalidate the now-unused MTRRs + // + InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr); + + // + // Find first unused MTRR + // + for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) { + if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) { + break; + } + } + + if (BaseAddress != 0) { + do { + // + // Calculate the alignment of the base address. + // + Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress)); + + if (Alignment > Length) { + break; + } + + // + // Find unused MTRR + // + for (; MsrNum < VariableMtrrCount; MsrNum++) { + if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) { + break; + } + } + + ProgramVariableMtrr ( + VariableSettings, + MsrNum, + BaseAddress, + Alignment, + MemoryType, + MtrrValidAddressMask + ); + BaseAddress += Alignment; + Length -= Alignment; + } while (TRUE); + + if (Length == 0) { + goto Done; + } + } + + TempQword = Length; + + if (!Positive) { + Length = Power2MaxMemory (LShiftU64 (TempQword, 1)); + + // + // Find unused MTRR + // + for (; MsrNum < VariableMtrrCount; MsrNum++) { + if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) { + break; + } + } + + ProgramVariableMtrr ( + VariableSettings, + MsrNum, + BaseAddress, + Length, + MemoryType, + MtrrValidAddressMask + ); + BaseAddress += Length; + TempQword = Length - TempQword; + MemoryType = MTRR_CACHE_UNCACHEABLE; + } + + do { + // + // Find unused MTRR + // + for (; MsrNum < VariableMtrrCount; MsrNum++) { + if ((VariableSettings->Mtrr[MsrNum].Mask & CACHE_MTRR_ENABLED) == 0) { + break; + } + } + + Length = Power2MaxMemory (TempQword); + if (!Positive) { + BaseAddress -= Length; + } + + ProgramVariableMtrr ( + VariableSettings, + MsrNum, + BaseAddress, + Length, + MemoryType, + MtrrValidAddressMask + ); + + if (Positive) { + BaseAddress += Length; + } + TempQword -= Length; + + } while (TempQword > 0); + +Done: + + // + // Write fixed MTRRs that have been modified + // + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + if (FixedSettingsModified[Index]) { + if (!MtrrContextValid) { + PreMtrrChange (&MtrrContext); + MtrrContextValid = TRUE; + } + MtrrRegisterWrite ( + mMtrrLibFixedMtrrTable[Index].Msr, + WorkingFixedSettings.Mtrr[Index] + ); + } + } + + // + // Write variable MTRRs + // + if (ProgramVariableSettings) { + for (Index = 0; Index < VariableMtrrCount; Index++) { + if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base || + WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) { + if (!MtrrContextValid) { + PreMtrrChange (&MtrrContext); + MtrrContextValid = TRUE; + } + MtrrRegisterWrite ( + QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1), + WorkingVariableSettings.Mtrr[Index].Base + ); + MtrrRegisterWrite ( + QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1, + WorkingVariableSettings.Mtrr[Index].Mask + ); + } + } + } + if (MtrrContextValid) { + PostMtrrChange (&MtrrContext); + } + + DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); + if (!RETURN_ERROR (Status)) { + if (MtrrSetting != NULL) { + MtrrSetting->MtrrDefType |= CACHE_MTRR_ENABLED; + } + MtrrDebugPrintAllMtrrsWorker (MtrrSetting); + } + + return Status; +} + +/** + This function attempts to set the attributes for a memory range. + + @param[in] BaseAddress The physical address that is the start + address of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attributes The bit mask of attributes to set for the + memory region. + + @retval RETURN_SUCCESS The attributes were set for the memory + region. + @retval RETURN_INVALID_PARAMETER Length is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or + more bytes of the memory resource range + specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support + for the memory resource range specified + by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource + range specified by BaseAddress and Length + cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to + modify the attributes of the memory + resource range. + +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttribute ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ) +{ + DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); + return MtrrSetMemoryAttributeWorker ( + NULL, + BaseAddress, + Length, + Attribute + ); +} + +/** + This function attempts to set the attributes into MTRR setting buffer for a memory range. + + @param[in, out] MtrrSetting MTRR setting buffer to be set. + @param[in] BaseAddress The physical address that is the start address + of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attribute The bit mask of attributes to set for the + memory region. + + @retval RETURN_SUCCESS The attributes were set for the memory region. + @retval RETURN_INVALID_PARAMETER Length is zero. + @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the + memory resource range specified by BaseAddress and Length. + @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + +**/ +RETURN_STATUS +EFIAPI +MtrrSetMemoryAttributeInMtrrSettings ( + IN OUT MTRR_SETTINGS *MtrrSetting, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN MTRR_MEMORY_CACHE_TYPE Attribute + ) +{ + DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); + return MtrrSetMemoryAttributeWorker ( + MtrrSetting, + BaseAddress, + Length, + Attribute + ); +} + +/** + Worker function setting variable MTRRs + + @param[in] VariableSettings A buffer to hold variable MTRRs content. + +**/ +VOID +MtrrSetVariableMtrrWorker ( + IN MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + UINT32 Index; + UINT32 VariableMtrrCount; + + VariableMtrrCount = GetVariableMtrrCountWorker (); + ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); + + for (Index = 0; Index < VariableMtrrCount; Index++) { + MtrrRegisterWrite ( + QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1), + VariableSettings->Mtrr[Index].Base + ); + MtrrRegisterWrite ( + QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1, + VariableSettings->Mtrr[Index].Mask + ); + } +} + + +/** + This function sets variable MTRRs + + @param[in] VariableSettings A buffer to hold variable MTRRs content. + + @return The pointer of VariableSettings + +**/ +MTRR_VARIABLE_SETTINGS* +EFIAPI +MtrrSetVariableMtrr ( + IN MTRR_VARIABLE_SETTINGS *VariableSettings + ) +{ + MTRR_CONTEXT MtrrContext; + + if (!IsMtrrSupported ()) { + return VariableSettings; + } + + PreMtrrChange (&MtrrContext); + MtrrSetVariableMtrrWorker (VariableSettings); + PostMtrrChange (&MtrrContext); + MtrrDebugPrintAllMtrrs (); + + return VariableSettings; +} + +/** + Worker function setting fixed MTRRs + + @param[in] FixedSettings A buffer to hold fixed MTRRs content. + +**/ +VOID +MtrrSetFixedMtrrWorker ( + IN MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + UINT32 Index; + + for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { + MtrrRegisterWrite ( + mMtrrLibFixedMtrrTable[Index].Msr, + FixedSettings->Mtrr[Index] + ); + } +} + + +/** + This function sets fixed MTRRs + + @param[in] FixedSettings A buffer to hold fixed MTRRs content. + + @retval The pointer of FixedSettings + +**/ +MTRR_FIXED_SETTINGS* +EFIAPI +MtrrSetFixedMtrr ( + IN MTRR_FIXED_SETTINGS *FixedSettings + ) +{ + MTRR_CONTEXT MtrrContext; + + if (!IsMtrrSupported ()) { + return FixedSettings; + } + + PreMtrrChange (&MtrrContext); + MtrrSetFixedMtrrWorker (FixedSettings); + PostMtrrChange (&MtrrContext); + MtrrDebugPrintAllMtrrs (); + + return FixedSettings; +} + + +/** + This function gets the content in all MTRRs (variable and fixed) + + @param[out] MtrrSetting A buffer to hold all MTRRs content. + + @retval the pointer of MtrrSetting + +**/ +MTRR_SETTINGS * +EFIAPI +MtrrGetAllMtrrs ( + OUT MTRR_SETTINGS *MtrrSetting + ) +{ + if (!IsMtrrSupported ()) { + return MtrrSetting; + } + + // + // Get fixed MTRRs + // + MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed); + + // + // Get variable MTRRs + // + MtrrGetVariableMtrrWorker ( + NULL, + GetVariableMtrrCountWorker (), + &MtrrSetting->Variables + ); + + // + // Get MTRR_DEF_TYPE value + // + MtrrSetting->MtrrDefType = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE); + + return MtrrSetting; +} + + +/** + This function sets all MTRRs (variable and fixed) + + @param[in] MtrrSetting A buffer holding all MTRRs content. + + @retval The pointer of MtrrSetting + +**/ +MTRR_SETTINGS * +EFIAPI +MtrrSetAllMtrrs ( + IN MTRR_SETTINGS *MtrrSetting + ) +{ + MTRR_CONTEXT MtrrContext; + + if (!IsMtrrSupported ()) { + return MtrrSetting; + } + + PreMtrrChange (&MtrrContext); + + // + // Set fixed MTRRs + // + MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed); + + // + // Set variable MTRRs + // + MtrrSetVariableMtrrWorker (&MtrrSetting->Variables); + + // + // Set MTRR_DEF_TYPE value + // + MtrrRegisterWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType); + + PostMtrrChangeEnableCache (&MtrrContext); + + MtrrDebugPrintAllMtrrs (); + + return MtrrSetting; +} + + +/** + Checks if MTRR is supported. + + @retval TRUE MTRR is supported. + @retval FALSE MTRR is not supported. + +**/ +BOOLEAN +EFIAPI +IsMtrrSupported ( + VOID + ) +{ + UINT32 RegEax; + + // + // Check CPUID(1).EAX[0..11] for Quark SoC + // + AsmCpuid (1, &RegEax, NULL, NULL, NULL); + if ((RegEax & 0xfff) == QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING) { + return TRUE; + } + + return FALSE; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf new file mode 100644 index 0000000000..72e83510d5 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf @@ -0,0 +1,42 @@ +## @file +# MTRR library provides APIs for MTRR operation. +# +# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MtrrLib + MODULE_UNI_FILE = MtrrLib.uni + FILE_GUID = 6826b408-f4f3-47ee-917f-af7047f9d937 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MtrrLib + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + MtrrLib.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + BaseMemoryLib + BaseLib + CpuLib + DebugLib + QNCAccessLib + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs ## SOMETIMES_CONSUMES + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni new file mode 100644 index 0000000000..b564c8af74 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.uni @@ -0,0 +1,18 @@ +// /** @file +// MtrrLib Module Localized Abstract and Description Content +// +// Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT +#language en-US +"MTRR library provides APIs for MTRR operation" + +#string STR_MODULE_DESCRIPTION +#language en-US +"MTRR library provides APIs for MTRR operation." + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c new file mode 100644 index 0000000000..da364c7b7c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/BaseAccess.c @@ -0,0 +1,28 @@ +/** @file +Base Lib function for QNC internal network access. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// The package level header files this module uses +// +#include + +/** + Gets the base address of PCI Express for Quark North Cluster. + + @return The base address of PCI Express for Quark North Cluster. + +**/ +UINTN +EFIAPI +QncGetPciExpressBaseAddress ( + VOID + ) +{ + return (UINTN) PcdGet64(PcdPciExpressBaseAddress); +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c new file mode 100644 index 0000000000..b9b1e258a0 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.c @@ -0,0 +1,327 @@ +/** @file +Common Lib function for QNC internal network access. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// The package level header files this module uses +// +#include + +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf new file mode 100644 index 0000000000..5489c1aa46 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf @@ -0,0 +1,37 @@ +## @file +# Base Intel QNC Library Instance +# +# Intel QNC internal network access Library Instance +# +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = QNCAccessLib + FILE_GUID = CC13B9FB-DAF5-4b42-907F-122216787C05 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = QNCAccessLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + QNCAccessLib.c + BaseAccess.c + +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + DebugLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c new file mode 100644 index 0000000000..65af27c305 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeAccess.c @@ -0,0 +1,142 @@ +/** @file +Runtime Lib function for QNC internal network access. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include + +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf new file mode 100644 index 0000000000..0e6aa4cd97 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/RuntimeQNCAccessLib.inf @@ -0,0 +1,43 @@ +## @file +# DXE Runtime Intel QNC Library Instance +# +# Intel QNC internal network access Library Instance. +# +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RuntimeQNCAccessLib + FILE_GUID = E6B51D93-E4C8-4425-9FA9-9DED814220F9 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = QNCAccessLib|DXE_RUNTIME_DRIVER + CONSTRUCTOR = DxeRuntimeQncAccessLibConstructor + DESTRUCTOR = DxeRuntimeQncAccessLibDestructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources] + QNCAccessLib.c + RuntimeAccess.c + +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + PcdLib + UefiBootServicesTableLib + UefiRuntimeLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c new file mode 100644 index 0000000000..d6bba0bc1c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.c @@ -0,0 +1,313 @@ +/** @file +QNC Smm Library Services that implements SMM Region access, S/W SMI generation and detection. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include +#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 GPE0BLK_Base; + UINT32 NewValue; + + // + // Get GPE0BLK_Base + // + GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF); + + + // + // Enable APM SMI + // + IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM); + + // + // Enable SMI globally + // + NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); + NewValue |= SMI_EN; + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue); + + // + // Set APM_STS + // + IoWrite8 (PcdGet16 (PcdSmmDataPort), Data); + + // + // Generate the APM SMI + // + IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData)); + + // + // Clear the APM SMI Status Bit + // + IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM); + + // + // Set the EOS Bit + // + IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS); +} + + +/** + Triggers an SMI at boot time. + + This function triggers a software SMM interrupt at boot time. + +**/ +VOID +EFIAPI +TriggerBootServiceSoftwareSmi ( + VOID + ) +{ + InternalTriggerSmi (BOOT_SERVICE_SOFTWARE_SMI_DATA); +} + + +/** + Triggers an SMI at run time. + + This function triggers a software SMM interrupt at run time. + +**/ +VOID +EFIAPI +TriggerRuntimeSoftwareSmi ( + VOID + ) +{ + InternalTriggerSmi (RUNTIME_SOFTWARE_SMI_DATA); +} + + +/** + Gets the software SMI data. + + This function tests if a software SMM interrupt happens. If a software SMI happens, + it retrieves the SMM data and returns it as a non-negative value; otherwise a negative + value is returned. + + @return Data The data retrieved from SMM data port in case of a software SMI; + otherwise a negative value. + +**/ +INTN +InternalGetSwSmiData ( + VOID + ) +{ + UINT8 SmiStatus; + UINT8 Data; + + SmiStatus = IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS); + if (((SmiStatus & B_QNC_GPE0BLK_SMIS_APM) != 0) && + (IoRead8 (PcdGet16 (PcdSmmActivationPort)) == PcdGet8 (PcdSmmActivationData))) { + Data = IoRead8 (PcdGet16 (PcdSmmDataPort)); + return (INTN)(UINTN)Data; + } + + return -1; +} + + +/** + Test if a boot time software SMI happened. + + This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and + it was triggered at boot time, it returns TRUE. Otherwise, it returns FALSE. + + @retval TRUE A software SMI triggered at boot time happened. + @retval FLASE No software SMI happened or the software SMI was triggered at run time. + +**/ +BOOLEAN +EFIAPI +IsBootServiceSoftwareSmi ( + VOID + ) +{ + return (BOOLEAN) (InternalGetSwSmiData () == BOOT_SERVICE_SOFTWARE_SMI_DATA); +} + + +/** + Test if a run time software SMI happened. + + This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and + it was triggered at run time, it returns TRUE. Otherwise, it returns FALSE. + + @retval TRUE A software SMI triggered at run time happened. + @retval FLASE No software SMI happened or the software SMI was triggered at boot time. + +**/ +BOOLEAN +EFIAPI +IsRuntimeSoftwareSmi ( + VOID + ) +{ + return (BOOLEAN) (InternalGetSwSmiData () == RUNTIME_SOFTWARE_SMI_DATA); +} + + + +/** + + Clear APM SMI Status Bit; Set the EOS bit. + +**/ +VOID +EFIAPI +ClearSmi ( + VOID + ) +{ + + UINT16 GPE0BLK_Base; + + // + // Get GpeBase + // + GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF); + + // + // Clear the APM SMI Status Bit + // + IoOr16 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_APM); + + // + // Set the EOS Bit + // + IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS); +} + +/** + This routine is the chipset code that accepts a request to "open" a region of SMRAM. + The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory. + The use of "open" means that the memory is visible from all boot-service + and SMM agents. + + @retval FALSE Cannot open a locked SMRAM region + @retval TRUE Success to open SMRAM region. +**/ +BOOLEAN +EFIAPI +QNCOpenSmramRegion ( + VOID + ) +{ + UINT32 Smram; + + // Read the SMRAM register + Smram = QncHsmmcRead (); + + // + // Is the platform locked? + // + if (Smram & SMM_LOCKED) { + // Cannot Open a locked region + DEBUG ((EFI_D_WARN, "Cannot open a locked SMRAM region\n")); + return FALSE; + } + + // + // Open all SMRAM regions for Host access only + // + Smram |= (SMM_WRITE_OPEN | SMM_READ_OPEN); // Open for Host. + Smram &= ~(NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN); // Not for others. + + // + // Write the SMRAM register + // + QncHsmmcWrite (Smram); + + return TRUE; +} + +/** + This routine is the chipset code that accepts a request to "close" a region of SMRAM. + The region could be legacy AB or TSEG near top of physical memory. + The use of "close" means that the memory is only visible from SMM agents, + not from BS or RT code. + + @retval FALSE Cannot open a locked SMRAM region + @retval TRUE Success to open SMRAM region. +**/ +BOOLEAN +EFIAPI +QNCCloseSmramRegion ( + VOID + ) +{ + UINT32 Smram; + + // Read the SMRAM register. + Smram = QncHsmmcRead (); + + // + // Is the platform locked? + // + if(Smram & SMM_LOCKED) { + // Cannot Open a locked region + DEBUG ((EFI_D_WARN, "Cannot close a locked SMRAM region\n")); + return FALSE; + } + + Smram &= (~(SMM_WRITE_OPEN | SMM_READ_OPEN | NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN)); + + QncHsmmcWrite (Smram); + + return TRUE; +} + +/** + This routine is the chipset code that accepts a request to "lock" SMRAM. + The region could be legacy AB or TSEG near top of physical memory. + The use of "lock" means that the memory can no longer be opened + to BS state. +**/ +VOID +EFIAPI +QNCLockSmramRegion ( + VOID + ) +{ + UINT32 Smram; + + // Read the SMRAM register. + Smram = QncHsmmcRead (); + if(Smram & SMM_LOCKED) { + DEBUG ((EFI_D_WARN, "SMRAM region already locked!\n")); + } + Smram |= SMM_LOCKED; + + QncHsmmcWrite (Smram); + + return; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf new file mode 100644 index 0000000000..5383580f3b --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf @@ -0,0 +1,44 @@ +## @file +# Component description file for Intel QNC SMM Library. +# +# QNC SMM Library that layers on top of the I/O Library to directly +# access SMM power management registers. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = QNCSmmLib + FILE_GUID = 8A9A62F5-758B-4965-A28B-0AAC292FBD89 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SmmLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + QNCSmmLib.c + +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + PcdLib + IoLib + DebugLib + QNCAccessLib + +[Pcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationData diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c new file mode 100644 index 0000000000..d730f62ce0 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c @@ -0,0 +1,379 @@ +/** @file +System reset Library Services. This library class provides a set of +methods to reset whole system with manipulate QNC. + +Copyright (c) 2013-2019 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#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 (); + } +} + +/** + This function causes a systemwide reset. The exact type of the reset is + defined by the EFI_GUID that follows the Null-terminated Unicode string passed + into ResetData. If the platform does not recognize the EFI_GUID in ResetData + the platform must pick a supported reset type to perform.The platform may + optionally log the parameters from any non-normal reset that occurs. + + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData The data buffer starts with a Null-terminated string, + followed by the EFI_GUID. +**/ +VOID +EFIAPI +ResetPlatformSpecific ( + IN UINTN DataSize, + IN VOID *ResetData + ) +{ + ResetCold (); +} + +/** + The ResetSystem function resets the entire platform. + + @param[in] ResetType The type of reset to perform. + @param[in] ResetStatus The status code for the reset. + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown + the data buffer starts with a Null-terminated string, optionally + followed by additional binary data. The string is a description + that the caller may use to further indicate the reason for the + system reset. +**/ +VOID +EFIAPI +ResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + switch (ResetType) { + case EfiResetWarm: + ResetWarm (); + break; + + case EfiResetCold: + ResetCold (); + break; + + case EfiResetShutdown: + ResetShutdown (); + return; + + case EfiResetPlatformSpecific: + ResetPlatformSpecific (DataSize, ResetData); + return; + + default: + return; + } +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf new file mode 100644 index 0000000000..b849259b7f --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf @@ -0,0 +1,46 @@ +## @file +# Component description file for Intel QuarkNcSocId Reset System Library. +# +# Reset System Library implementation that bases on QNC. +# +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ResetSystemLib + FILE_GUID = AD33A56E-3AAD-40ac-91B1-FA861E8D9D85 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ResetSystemLib + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + ResetSystemLib.c + + +[Packages] + QuarkSocPkg/QuarkSocPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + PcdLib + IoLib + BaseLib + CpuLib + QNCAccessLib + +[Pcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h new file mode 100644 index 0000000000..8968aa8931 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/CommonHeader.h @@ -0,0 +1,25 @@ +/** @file +Common header file shared by all source files. + +This file includes package header files, library classes and protocol, PPI & GUID definitions. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef __COMMON_HEADER_H_ +#define __COMMON_HEADER_H_ + + +#include +#include + +#include +#include +#include +#include +#include +#include + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c new file mode 100644 index 0000000000..319e103cf4 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.c @@ -0,0 +1,797 @@ +/** @file +Intel QNC SMBUS library implementation built upon I/O library. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +/** + Gets Io port base address of Smbus Host Controller. + + This internal function depends on a feature flag named PcdIchSmbusFixedIoPortBaseAddress + to retrieve Smbus Io port base. If that feature flag is true, it will get Smbus Io port base + address from a preset Pcd entry named PcdIchSmbusIoPortBaseAddress; otherwise, it will always + read Pci configuration space to get that value in each Smbus bus transaction. + + @return The Io port base address of Smbus host controller. + +**/ +UINTN +InternalGetSmbusIoPortBaseAddress ( + VOID + ) +{ + UINTN IoPortBaseAddress; + + if (FeaturePcdGet (PcdSmbaIoBaseAddressFixed)) { + IoPortBaseAddress = (UINTN) PcdGet16 (PcdSmbaIoBaseAddress); + } else { + IoPortBaseAddress = (UINTN) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) & B_QNC_LPC_SMBUS_BASE_MASK; + } + + // + // Make sure that the IO port base address has been properly set. + // + ASSERT (IoPortBaseAddress != 0); + + return IoPortBaseAddress; +} + + +/** + Acquires the ownership of SMBUS. + + This internal function reads the host state register. + If the SMBUS is not available, RETURN_TIMEOUT is returned; + Otherwise, it performs some basic initializations and returns + RETURN_SUCCESS. + + @param IoPortBaseAddress The Io port base address of Smbus Host controller. + + @retval RETURN_SUCCESS The SMBUS command was executed successfully. + @retval RETURN_TIMEOUT A timeout occurred while executing the SMBUS command. + +**/ +RETURN_STATUS +InternalSmBusAcquire ( + UINTN IoPortBaseAddress + ) +{ + + // + // Clear host status register and exit. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL, 0); + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, 0); + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD1, 0); + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL); + + return RETURN_SUCCESS; +} + +/** + Starts the SMBUS transaction and waits until the end. + + This internal function start the SMBUS transaction and waits until the transaction + of SMBUS is over by polling the INTR bit of Host status register. + If the SMBUS is not available, RETURN_TIMEOUT is returned; + Otherwise, it performs some basic initializations and returns + RETURN_SUCCESS. + + @param IoPortBaseAddress The Io port base address of Smbus Host controller. + @param HostControl The Host control command to start SMBUS transaction. + + @retval RETURN_SUCCESS The SMBUS command was executed successfully. + @retval RETURN_CRC_ERROR The checksum is not correct (PEC is incorrect). + @retval RETURN_DEVICE_ERROR The request was not completed because a failure reflected + in the Host Status Register bit. Device errors are + a result of a transaction collision, illegal command field, + unclaimed cycle (host initiated), or bus errors (collisions). + +**/ +RETURN_STATUS +InternalSmBusStart ( + IN UINTN IoPortBaseAddress, + IN UINT8 HostControl + ) +{ + UINT8 HostStatus; + + // + // Set Host Control Register (Initiate Operation, Interrupt disabled). + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL, HostControl + B_QNC_SMBUS_START); + + do { + // + // Poll INTR bit of Host Status Register. + // + HostStatus = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS); + } while ((HostStatus & (B_QNC_SMBUS_BYTE_DONE_STS | B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR)) == 0); + + if ((HostStatus & (B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR)) == 0) { + return RETURN_SUCCESS; + } + // + // Clear error bits of Host Status Register. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, (B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR)); + + return RETURN_DEVICE_ERROR; +} + +/** + Executes an SMBUS quick, byte or word command. + + This internal function executes an SMBUS quick, byte or word commond. + If Status is not NULL, then the status of the executed command is returned in Status. + + @param HostControl The value of Host Control Register to set. + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Value The byte/word write to the SMBUS. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The byte/word read from the SMBUS. + +**/ +UINT16 +InternalSmBusNonBlock ( + IN UINT8 HostControl, + IN UINTN SmBusAddress, + IN UINT16 Value, + OUT RETURN_STATUS *Status + ) +{ + RETURN_STATUS ReturnStatus; + UINTN IoPortBaseAddress; + + IoPortBaseAddress = InternalGetSmbusIoPortBaseAddress (); + + // + // Try to acquire the ownership of QNC SMBUS. + // + ReturnStatus = InternalSmBusAcquire (IoPortBaseAddress); + if (RETURN_ERROR (ReturnStatus)) { + goto Done; + } + + // + // Set Host Commond Register. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCMD, (UINT8) SMBUS_LIB_COMMAND (SmBusAddress)); + // + // Write value to Host Data 0 and Host Data 1 Registers. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, (UINT8) Value); + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD1, (UINT8) (Value >> 8)); + + + // + // Set SMBUS slave address for the device to send/receive from. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_TSA, (UINT8) SmBusAddress); + // + // Start the SMBUS transaction and wait for the end. + // + ReturnStatus = InternalSmBusStart (IoPortBaseAddress, HostControl); + // + // Read value from Host Data 0 and Host Data 1 Registers. + // + Value = (UINT16)(IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD1) << 8); + Value = (UINT16)(Value | IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD0)); + + // + // Clear Host Status Register and Auxiliary Status Register. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL); + +Done: + if (Status != NULL) { + *Status = ReturnStatus; + } + + return Value; +} + +/** + Executes an SMBUS quick read command. + + Executes an SMBUS quick read command on the SMBUS device specified by SmBusAddress. + Only the SMBUS slave address field of SmBusAddress is required. + If Status is not NULL, then the status of the executed command is returned in Status. + If PEC is set in SmBusAddress, then ASSERT(). + If Command in SmBusAddress is not zero, then ASSERT(). + If Length in SmBusAddress is not zero, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + +**/ +VOID +EFIAPI +SmBusQuickRead ( + IN UINTN SmBusAddress, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (!SMBUS_LIB_PEC (SmBusAddress)); + ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + InternalSmBusNonBlock ( + V_QNC_SMBUS_HCTL_CMD_QUICK, + SmBusAddress | V_QNC_SMBUS_RW_SEL_READ, + 0, + Status + ); + +} + +/** + Executes an SMBUS quick write command. + + Executes an SMBUS quick write command on the SMBUS device specified by SmBusAddress. + Only the SMBUS slave address field of SmBusAddress is required. + If Status is not NULL, then the status of the executed command is returned in Status. + If PEC is set in SmBusAddress, then ASSERT(). + If Command in SmBusAddress is not zero, then ASSERT(). + If Length in SmBusAddress is not zero, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + +**/ +VOID +EFIAPI +SmBusQuickWrite ( + IN UINTN SmBusAddress, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (!SMBUS_LIB_PEC (SmBusAddress)); + ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + InternalSmBusNonBlock ( + V_QNC_SMBUS_HCTL_CMD_QUICK, + SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE, + 0, + Status + ); + +} + +/** + Executes an SMBUS receive byte command. + + Executes an SMBUS receive byte command on the SMBUS device specified by SmBusAddress. + Only the SMBUS slave address field of SmBusAddress is required. + The byte received from the SMBUS is returned. + If Status is not NULL, then the status of the executed command is returned in Status. + If Command in SmBusAddress is not zero, then ASSERT(). + If Length in SmBusAddress is not zero, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The byte received from the SMBUS. + +**/ +UINT8 +EFIAPI +SmBusReceiveByte ( + IN UINTN SmBusAddress, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + return (UINT8) InternalSmBusNonBlock ( + V_QNC_SMBUS_HCTL_CMD_BYTE, + SmBusAddress | V_QNC_SMBUS_RW_SEL_READ, + 0, + Status + ); + +} + +/** + Executes an SMBUS send byte command. + + Executes an SMBUS send byte command on the SMBUS device specified by SmBusAddress. + The byte specified by Value is sent. + Only the SMBUS slave address field of SmBusAddress is required. Value is returned. + If Status is not NULL, then the status of the executed command is returned in Status. + If Command in SmBusAddress is not zero, then ASSERT(). + If Length in SmBusAddress is not zero, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Value The 8-bit value to send. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The parameter of Value. + +**/ +UINT8 +EFIAPI +SmBusSendByte ( + IN UINTN SmBusAddress, + IN UINT8 Value, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + return (UINT8) InternalSmBusNonBlock ( + V_QNC_SMBUS_HCTL_CMD_BYTE, + SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE, + Value, + Status + ); + +} + +/** + Executes an SMBUS read data byte command. + + Executes an SMBUS read data byte command on the SMBUS device specified by SmBusAddress. + Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required. + The 8-bit value read from the SMBUS is returned. + If Status is not NULL, then the status of the executed command is returned in Status. + If Length in SmBusAddress is not zero, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The byte read from the SMBUS. + +**/ +UINT8 +EFIAPI +SmBusReadDataByte ( + IN UINTN SmBusAddress, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + return (UINT8) InternalSmBusNonBlock ( + V_QNC_SMBUS_HCTL_CMD_BYTE_DATA, + SmBusAddress | V_QNC_SMBUS_RW_SEL_READ, + 0, + Status + ); +} + +/** + Executes an SMBUS write data byte command. + + Executes an SMBUS write data byte command on the SMBUS device specified by SmBusAddress. + The 8-bit value specified by Value is written. + Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required. + Value is returned. + If Status is not NULL, then the status of the executed command is returned in Status. + If Length in SmBusAddress is not zero, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Value The 8-bit value to write. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The parameter of Value. + +**/ +UINT8 +EFIAPI +SmBusWriteDataByte ( + IN UINTN SmBusAddress, + IN UINT8 Value, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + return (UINT8) InternalSmBusNonBlock ( + V_QNC_SMBUS_HCTL_CMD_BYTE_DATA, + SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE, + Value, + Status + ); +} + +/** + Executes an SMBUS read data word command. + + Executes an SMBUS read data word command on the SMBUS device specified by SmBusAddress. + Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required. + The 16-bit value read from the SMBUS is returned. + If Status is not NULL, then the status of the executed command is returned in Status. + If Length in SmBusAddress is not zero, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The byte read from the SMBUS. + +**/ +UINT16 +EFIAPI +SmBusReadDataWord ( + IN UINTN SmBusAddress, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 2); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + return InternalSmBusNonBlock ( + V_QNC_SMBUS_HCTL_CMD_WORD_DATA, + SmBusAddress | V_QNC_SMBUS_RW_SEL_READ, + 0, + Status + ); + +} + +/** + Executes an SMBUS write data word command. + + Executes an SMBUS write data word command on the SMBUS device specified by SmBusAddress. + The 16-bit value specified by Value is written. + Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required. + Value is returned. + If Status is not NULL, then the status of the executed command is returned in Status. + If Length in SmBusAddress is not zero, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Value The 16-bit value to write. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The parameter of Value. + +**/ +UINT16 +EFIAPI +SmBusWriteDataWord ( + IN UINTN SmBusAddress, + IN UINT16 Value, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 2); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + return InternalSmBusNonBlock ( + V_QNC_SMBUS_HCTL_CMD_WORD_DATA, + SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE, + Value, + Status + ); +} + +/** + Executes an SMBUS process call command. + + Executes an SMBUS process call command on the SMBUS device specified by SmBusAddress. + The 16-bit value specified by Value is written. + Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required. + The 16-bit value returned by the process call command is returned. + If Status is not NULL, then the status of the executed command is returned in Status. + If Length in SmBusAddress is not zero, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Value The 16-bit value to write. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The 16-bit value returned by the process call command. + +**/ +UINT16 +EFIAPI +SmBusProcessCall ( + IN UINTN SmBusAddress, + IN UINT16 Value, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + return InternalSmBusNonBlock ( + V_QNC_SMBUS_HCTL_CMD_PROCESS_CALL, + SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE, + Value, + Status + ); + +} + +/** + Executes an SMBUS block command. + + Executes an SMBUS block read, block write and block write-block read command + on the SMBUS device specified by SmBusAddress. + Bytes are read from the SMBUS and stored in Buffer. + The number of bytes read is returned, and will never return a value larger than 32-bytes. + If Status is not NULL, then the status of the executed command is returned in Status. + It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read. + SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes. + + @param HostControl The value of Host Control Register to set. + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param WriteBuffer Pointer to the buffer of bytes to write to the SMBUS. + @param ReadBuffer Pointer to the buffer of bytes to read from the SMBUS. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The number of bytes read from the SMBUS. + +**/ +UINTN +InternalSmBusBlock ( + IN UINT8 HostControl, + IN UINTN SmBusAddress, + IN UINT8 *WriteBuffer, + OUT UINT8 *ReadBuffer, + OUT RETURN_STATUS *Status + ) +{ + RETURN_STATUS ReturnStatus; + UINTN Index; + UINTN BytesCount; + UINTN IoPortBaseAddress; + + IoPortBaseAddress = InternalGetSmbusIoPortBaseAddress (); + + BytesCount = SMBUS_LIB_LENGTH (SmBusAddress); + + // + // Try to acquire the ownership of ICH SMBUS. + // + ReturnStatus = InternalSmBusAcquire (IoPortBaseAddress); + if (RETURN_ERROR (ReturnStatus)) { + goto Done; + } + + // + // Set Host Command Register. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCMD, (UINT8) SMBUS_LIB_COMMAND (SmBusAddress)); + + // + // Clear byte pointer of 32-byte buffer. + // + IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL); + + if (WriteBuffer != NULL) { + // + // Write the number of block to Host Block Data Byte Register. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, (UINT8) BytesCount); + // + // Write data block to Host Block Data Register. + // + for (Index = 0; Index < BytesCount; Index++) { + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HBD + (UINT8)Index, WriteBuffer[Index]); + } + } + // + // Set SMBUS slave address for the device to send/receive from. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_TSA, (UINT8) SmBusAddress); + // + // Start the SMBUS transaction and wait for the end. + // + ReturnStatus = InternalSmBusStart (IoPortBaseAddress, HostControl); + if (RETURN_ERROR (ReturnStatus)) { + goto Done; + } + + if (ReadBuffer != NULL) { + // + // Read the number of block from host block data byte register. + // + BytesCount = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD0); + // + // Write data block from Host Block Data Register. + // + for (Index = 0; Index < BytesCount; Index++) { + ReadBuffer[Index] = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HBD + (UINT8)Index); + } + } + +Done: + // + // Clear Host Status Register and Auxiliary Status Register. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL); + + if (Status != NULL) { + *Status = ReturnStatus; + } + + return BytesCount; +} + +/** + Executes an SMBUS read block command. + + Executes an SMBUS read block command on the SMBUS device specified by SmBusAddress. + Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required. + Bytes are read from the SMBUS and stored in Buffer. + The number of bytes read is returned, and will never return a value larger than 32-bytes. + If Status is not NULL, then the status of the executed command is returned in Status. + It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read. + SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes. + If Length in SmBusAddress is not zero, then ASSERT(). + If Buffer is NULL, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Buffer Pointer to the buffer to store the bytes read from the SMBUS. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The number of bytes read. + +**/ +UINTN +EFIAPI +SmBusReadBlock ( + IN UINTN SmBusAddress, + OUT VOID *Buffer, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (Buffer != NULL); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + return InternalSmBusBlock ( + V_QNC_SMBUS_HCTL_CMD_BLOCK, + SmBusAddress | V_QNC_SMBUS_RW_SEL_READ, + NULL, + Buffer, + Status + ); +} + +/** + Executes an SMBUS write block command. + + Executes an SMBUS write block command on the SMBUS device specified by SmBusAddress. + The SMBUS slave address, SMBUS command, and SMBUS length fields of SmBusAddress are required. + Bytes are written to the SMBUS from Buffer. + The number of bytes written is returned, and will never return a value larger than 32-bytes. + If Status is not NULL, then the status of the executed command is returned in Status. + If Length in SmBusAddress is zero or greater than 32, then ASSERT(). + If Buffer is NULL, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param Buffer Pointer to the buffer to store the bytes read from the SMBUS. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + + @return The number of bytes written. + +**/ +UINTN +EFIAPI +SmBusWriteBlock ( + IN UINTN SmBusAddress, + OUT VOID *Buffer, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (Buffer != NULL); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + + return InternalSmBusBlock ( + V_QNC_SMBUS_HCTL_CMD_BLOCK, + SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE, + Buffer, + NULL, + Status + ); +} + +/** + Executes an SMBUS block process call command. + + Executes an SMBUS block process call command on the SMBUS device specified by SmBusAddress. + The SMBUS slave address, SMBUS command, and SMBUS length fields of SmBusAddress are required. + Bytes are written to the SMBUS from WriteBuffer. Bytes are then read from the SMBUS into ReadBuffer. + If Status is not NULL, then the status of the executed command is returned in Status. + It is the caller's responsibility to make sure ReadBuffer is large enough for the total number of bytes read. + SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes. + If Length in SmBusAddress is zero or greater than 32, then ASSERT(). + If WriteBuffer is NULL, then ASSERT(). + If ReadBuffer is NULL, then ASSERT(). + If any reserved bits of SmBusAddress are set, then ASSERT(). + + @param SmBusAddress Address that encodes the SMBUS Slave Address, + SMBUS Command, SMBUS Data Length, and PEC. + @param WriteBuffer Pointer to the buffer of bytes to write to the SMBUS. + @param ReadBuffer Pointer to the buffer of bytes to read from the SMBUS. + @param Status Return status for the executed command. + This is an optional parameter and may be NULL. + RETURN_TIMEOUT A timeout occurred while executing the SMBUS command. + RETURN_DEVICE_ERROR The request was not completed because a failure + reflected in the Host Status Register bit. Device errors are a result + of a transaction collision, illegal command field, unclaimed cycle + (host initiated), or bus errors (collisions). + RETURN_CRC_ERROR The checksum is not correct (PEC is incorrect) + RETURN_UNSUPPORTED The SMBus operation is not supported. + + @return The number of bytes written. + +**/ +UINTN +EFIAPI +SmBusBlockProcessCall ( + IN UINTN SmBusAddress, + IN VOID *WriteBuffer, + OUT VOID *ReadBuffer, + OUT RETURN_STATUS *Status OPTIONAL + ) +{ + ASSERT (WriteBuffer != NULL); + ASSERT (ReadBuffer != NULL); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1); + ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32); + ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0); + if (Status != NULL) { + *Status = RETURN_UNSUPPORTED; + } + return 0; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf new file mode 100644 index 0000000000..6cf4c569ed --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf @@ -0,0 +1,47 @@ +## @file +# Component description file for Intel QNC Smbus Library. +# +# SMBUS Library that layers on top of the I/O Library to directly +# access a standard SMBUS host controller. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmbusLib + FILE_GUID = 6F2F36B3-936B-4eb2-83C7-2987B4F9D4EB + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SmbusLib + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + SmbusLib.c + CommonHeader.h + +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + PcdLib + DebugLib + PciLib + IoLib + QNCAccessLib + +[FeaturePcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed + +[Pcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c new file mode 100644 index 0000000000..f9a7af0449 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c @@ -0,0 +1,446 @@ +/** @file +The Quark CPU specific programming for PiSmmCpuDxeSmm module. + +Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#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]; + + // + // SMRR size cannot be less than 4-KBytes + // SMRR size must be of length 2^n + // SMRR base alignment cannot be less than SMRR length + // + if ((CpuHotPlugData->SmrrSize < SIZE_4KB) || + (CpuHotPlugData->SmrrSize != GetPowerOfTwo32 (CpuHotPlugData->SmrrSize)) || + ((CpuHotPlugData->SmrrBase & ~(CpuHotPlugData->SmrrSize - 1)) != CpuHotPlugData->SmrrBase)) { + DEBUG ((EFI_D_ERROR, "SMM Base/Size does not meet alignment/size requirement!\n")); + CpuDeadLoop (); + } + + // + // Use QNC to initialize SMRR on Quark + // + QNCPortWrite(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSBASE, CpuHotPlugData->SmrrBase); + QNCPortWrite(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK, (~(CpuHotPlugData->SmrrSize - 1) & EFI_MSR_SMRR_MASK) | EFI_MSR_SMRR_PHYS_MASK_VALID); +} + +/** + This function updates the SMRAM save state on the currently executing CPU + to resume execution at a specific address after an RSM instruction. This + function must evaluate the SMRAM save state to determine the execution mode + the RSM instruction resumes and update the resume execution address with + either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart + flag in the SMRAM save state must always be cleared. This function returns + the value of the instruction pointer from the SMRAM save state that was + replaced. If this function returns 0, then the SMRAM save state was not + modified. + + This function is called during the very first SMI on each CPU after + SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode + to signal that the SMBASE of each CPU has been updated before the default + SMBASE address is used for the first SMI to the next CPU. + + @param[in] CpuIndex The index of the CPU to hook. The value + must be between 0 and the NumberOfCpus + field in the System Management System Table + (SMST). + @param[in] CpuState Pointer to SMRAM Save State Map for the + currently executing CPU. + @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to + 32-bit execution mode from 64-bit SMM. + @param[in] NewInstructionPointer Instruction pointer to use if resuming to + same execution mode as SMM. + + @retval 0 This function did modify the SMRAM save state. + @retval > 0 The original instruction pointer value from the SMRAM save state + before it was replaced. +**/ +UINT64 +EFIAPI +SmmCpuFeaturesHookReturnFromSmm ( + IN UINTN CpuIndex, + IN SMRAM_SAVE_STATE_MAP *CpuState, + IN UINT64 NewInstructionPointer32, + IN UINT64 NewInstructionPointer + ) +{ + return 0; +} + +/** + Hook point in normal execution mode that allows the one CPU that was elected + as monarch during System Management Mode initialization to perform additional + initialization actions immediately after all of the CPUs have processed their + first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE + into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm(). +**/ +VOID +EFIAPI +SmmCpuFeaturesSmmRelocationComplete ( + VOID + ) +{ +} + +/** + Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is + returned, then a custom SMI handler is not provided by this library, + and the default SMI handler must be used. + + @retval 0 Use the default SMI handler. + @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler() + The caller is required to allocate enough SMRAM for each CPU to + support the size of the custom SMI handler. +**/ +UINTN +EFIAPI +SmmCpuFeaturesGetSmiHandlerSize ( + VOID + ) +{ + return 0; +} + +/** + Install a custom SMI handler for the CPU specified by CpuIndex. This function + is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater + than zero and is called by the CPU that was elected as monarch during System + Management Mode initialization. + + @param[in] CpuIndex The index of the CPU to install the custom SMI handler. + The value must be between 0 and the NumberOfCpus field + in the System Management System Table (SMST). + @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex. + @param[in] SmiStack The stack to use when an SMI is processed by the + the CPU specified by CpuIndex. + @param[in] StackSize The size, in bytes, if the stack used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtBase The base address of the GDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtBase The base address of the IDT to use when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is + processed by the CPU specified by CpuIndex. + @param[in] Cr3 The base address of the page tables to use when an SMI + is processed by the CPU specified by CpuIndex. +**/ +VOID +EFIAPI +SmmCpuFeaturesInstallSmiHandler ( + IN UINTN CpuIndex, + IN UINT32 SmBase, + IN VOID *SmiStack, + IN UINTN StackSize, + IN UINTN GdtBase, + IN UINTN GdtSize, + IN UINTN IdtBase, + IN UINTN IdtSize, + IN UINT32 Cr3 + ) +{ +} + +/** + Determines if MTRR registers must be configured to set SMRAM cache-ability + when executing in System Management Mode. + + @retval TRUE MTRR registers must be configured to set SMRAM cache-ability. + @retval FALSE MTRR registers do not need to be configured to set SMRAM + cache-ability. +**/ +BOOLEAN +EFIAPI +SmmCpuFeaturesNeedConfigureMtrrs ( + VOID + ) +{ + return TRUE; +} + +/** + Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs() + returns TRUE. +**/ +VOID +EFIAPI +SmmCpuFeaturesDisableSmrr ( + VOID + ) +{ + // + // Use QNC to disable SMRR on Quark + // + QNCPortWrite( + QUARK_NC_HOST_BRIDGE_SB_PORT_ID, + QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK, + QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK) & ~EFI_MSR_SMRR_PHYS_MASK_VALID + ); +} + +/** + Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs() + returns TRUE. +**/ +VOID +EFIAPI +SmmCpuFeaturesReenableSmrr ( + VOID + ) +{ + // + // Use QNC to enable SMRR on Quark + // + QNCPortWrite( + QUARK_NC_HOST_BRIDGE_SB_PORT_ID, + QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK, + QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK) | EFI_MSR_SMRR_PHYS_MASK_VALID + ); +} + +/** + Processor specific hook point each time a CPU enters System Management Mode. + + @param[in] CpuIndex The index of the CPU that has entered SMM. The value + must be between 0 and the NumberOfCpus field in the + System Management System Table (SMST). +**/ +VOID +EFIAPI +SmmCpuFeaturesRendezvousEntry ( + IN UINTN CpuIndex + ) +{ +} + +/** + Processor specific hook point each time a CPU exits System Management Mode. + + @param[in] CpuIndex The index of the CPU that is exiting SMM. The value must + be between 0 and the NumberOfCpus field in the System + Management System Table (SMST). +**/ +VOID +EFIAPI +SmmCpuFeaturesRendezvousExit ( + IN UINTN CpuIndex + ) +{ +} + +/** + Check to see if an SMM register is supported by a specified CPU. + + @param[in] CpuIndex The index of the CPU to check for SMM register support. + The value must be between 0 and the NumberOfCpus field + in the System Management System Table (SMST). + @param[in] RegName Identifies the SMM register to check for support. + + @retval TRUE The SMM register specified by RegName is supported by the CPU + specified by CpuIndex. + @retval FALSE The SMM register specified by RegName is not supported by the + CPU specified by CpuIndex. +**/ +BOOLEAN +EFIAPI +SmmCpuFeaturesIsSmmRegisterSupported ( + IN UINTN CpuIndex, + IN SMM_REG_NAME RegName + ) +{ + return FALSE; +} + +/** + Returns the current value of the SMM register for the specified CPU. + If the SMM register is not supported, then 0 is returned. + + @param[in] CpuIndex The index of the CPU to read the SMM register. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] RegName Identifies the SMM register to read. + + @return The value of the SMM register specified by RegName from the CPU + specified by CpuIndex. +**/ +UINT64 +EFIAPI +SmmCpuFeaturesGetSmmRegister ( + IN UINTN CpuIndex, + IN SMM_REG_NAME RegName + ) +{ + return 0; +} + +/** + Sets the value of an SMM register on a specified CPU. + If the SMM register is not supported, then no action is performed. + + @param[in] CpuIndex The index of the CPU to write the SMM register. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] RegName Identifies the SMM register to write. + registers are read-only. + @param[in] Value The value to write to the SMM register. +**/ +VOID +EFIAPI +SmmCpuFeaturesSetSmmRegister ( + IN UINTN CpuIndex, + IN SMM_REG_NAME RegName, + IN UINT64 Value + ) +{ +} + +/** + Read an SMM Save State register on the target processor. If this function + returns EFI_UNSUPPORTED, then the caller is responsible for reading the + SMM Save Sate register. + + @param[in] CpuIndex The index of the CPU to read the SMM Save State. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] Register The SMM Save State register to read. + @param[in] Width The number of bytes to read from the CPU save state. + @param[out] Buffer Upon return, this holds the CPU register value read + from the save state. + + @retval EFI_SUCCESS The register was read from Save State. + @retval EFI_INVALID_PARAMTER Buffer is NULL. + @retval EFI_UNSUPPORTED This function does not support reading Register. + +**/ +EFI_STATUS +EFIAPI +SmmCpuFeaturesReadSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + OUT VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Writes an SMM Save State register on the target processor. If this function + returns EFI_UNSUPPORTED, then the caller is responsible for writing the + SMM Save Sate register. + + @param[in] CpuIndex The index of the CPU to write the SMM Save State. The + value must be between 0 and the NumberOfCpus field in + the System Management System Table (SMST). + @param[in] Register The SMM Save State register to write. + @param[in] Width The number of bytes to write to the CPU save state. + @param[in] Buffer Upon entry, this holds the new CPU register value. + + @retval EFI_SUCCESS The register was written to Save State. + @retval EFI_INVALID_PARAMTER Buffer is NULL. + @retval EFI_UNSUPPORTED This function does not support writing Register. +**/ +EFI_STATUS +EFIAPI +SmmCpuFeaturesWriteSaveStateRegister ( + IN UINTN CpuIndex, + IN EFI_SMM_SAVE_STATE_REGISTER Register, + IN UINTN Width, + IN CONST VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function is hook point called after the gEfiSmmReadyToLockProtocolGuid + notification is completely processed. +**/ +VOID +EFIAPI +SmmCpuFeaturesCompleteSmmReadyToLock ( + VOID + ) +{ +} + +/** + This API provides a method for a CPU to allocate a specific region for storing page tables. + + This API can be called more once to allocate memory for page tables. + + Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer for page tables. + @retval NULL Fail to allocate a specific region for storing page tables, + Or there is no preference on where the page tables are allocated in SMRAM. + +**/ +VOID * +EFIAPI +SmmCpuFeaturesAllocatePageTableMemory ( + IN UINTN Pages + ) +{ + return NULL; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf new file mode 100644 index 0000000000..a45c857910 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf @@ -0,0 +1,30 @@ +## @file +# The CPU specific programming for PiSmmCpuDxeSmm module. +# +# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmCpuFeaturesLib + MODULE_UNI_FILE = SmmCpuFeaturesLib.uni + FILE_GUID = 34001BF4-1E93-4e08-B90E-52F2418A5026 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = SmmCpuFeaturesLib + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[Sources] + SmmCpuFeaturesLib.c + +[LibraryClasses] + BaseLib + DebugLib + QNCAccessLib + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni new file mode 100644 index 0000000000..6ee54e9254 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni @@ -0,0 +1,12 @@ +// /** @file +// The CPU specific programming for PiSmmCpuDxeSmm module. +// +// Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module." + +#string STR_MODULE_DESCRIPTION #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module." diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c new file mode 100644 index 0000000000..1d91360ec3 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c @@ -0,0 +1,59 @@ +/** @file +Framework PEIM to initialize memory on a QuarkNcSocId Memory Controller. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// Include common header file for this module. +// +#include "MemoryInit.h" + +static PEI_QNC_MEMORY_INIT_PPI mPeiQNCMemoryInitPpi = +{ MrcStart }; + +static EFI_PEI_PPI_DESCRIPTOR PpiListPeiQNCMemoryInit = +{ + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gQNCMemoryInitPpiGuid, + &mPeiQNCMemoryInitPpi +}; + +void Mrc( MRCParams_t *MrcData); + +/** + + Do memory initialization for QuarkNcSocId DDR3 SDRAM Controller + + @param FfsHeader Not used. + @param PeiServices General purpose services available to every PEIM. + + @return EFI_SUCCESS Memory initialization completed successfully. + All other error conditions encountered result in an ASSERT. + + **/ +EFI_STATUS +PeimMemoryInit( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = (**PeiServices).InstallPpi(PeiServices, &PpiListPeiQNCMemoryInit); + + return Status; +} + +VOID +EFIAPI +MrcStart( + IN OUT MRCParams_t *MrcData + ) +{ + + Mrc(MrcData); +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h new file mode 100644 index 0000000000..0cea554e0e --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h @@ -0,0 +1,35 @@ +/** @file +Framework PEIM to initialize memory on an DDR2 SDRAM Memory Controller. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef _PEI_QNC_MEMORY_INIT_H_ +#define _PEI_QNC_MEMORY_INIT_H_ + +// +// The package level header files this module uses +// +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf new file mode 100644 index 0000000000..7a1ba522bf --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf @@ -0,0 +1,70 @@ +## @file +# This is the Memory Initialization Driver for Quark +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemoryInitPei + FILE_GUID = D2C69B26-82E1-4a1b-AD35-ED0261B9F347 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = PeimMemoryInit + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[BuildOptions] + GCC:DEBUG_*_*_CC_FLAGS = -DGCC -Wno-unused-function + GCC:RELEASE_*_*_CC_FLAGS = -DNDEBUG -DGCC -Wno-unused-function + INTEL:RELEASE_*_*_CC_FLAGS = /D NDEBUG + MSFT:RELEASE_*_*_CC_FLAGS = /D NDEBUG + +[Sources] + memory_options.h + platform.c + lprint.c + meminit.h + meminit.c + meminit_utils.h + meminit_utils.c + gen5_iosf_sb_definitions.h + general_definitions.h + io.h + core_types.h + prememinit.h + prememinit.c + mrc.h + mrc.c + hte.c + hte.h + MemoryInit.h + MemoryInit.c + +[Packages] + QuarkSocPkg/QuarkSocPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + PeimEntryPoint + DebugLib + BaseMemoryLib + +[Ppis] + gQNCMemoryInitPpiGuid # PPI ALWAYS_PRODUCED + +[Depex] + TRUE diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h new file mode 100644 index 0000000000..eef3c3f8ae --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h @@ -0,0 +1,43 @@ +/** @file +Core types used in Mrc. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef __MRC_CORE_TYPES_H +#define __MRC_CORE_TYPES_H + +typedef char char_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef unsigned char bool; +typedef unsigned int size_t; + +#ifdef ASM_INC +// Unfortunately h2inc has issue with long long +typedef struct uint64_s +{ + uint32_t lo; + uint32_t hi; +}uint64_t; +#else +typedef unsigned long long uint64_t; +#endif + +#ifdef SIM +// Native word length is 64bit in simulation environment +typedef uint64_t uintn_t; +#else +// Quark is 32bit +typedef uint32_t uintn_t; +#endif + +#define PTR32(a) ((volatile uint32_t*)(uintn_t)(a)) + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h new file mode 100644 index 0000000000..dea2a9ad05 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h @@ -0,0 +1,738 @@ +/************************************************************************ + * + * Copyright (c) 2013-2015 Intel Corporation. + * +* SPDX-License-Identifier: BSD-2-Clause-Patent + * + * MCU register definition + * + ************************************************************************/ +#ifndef __IOSF_DEFINITIONS_H +#define __IOSF_DEFINITIONS_H + +// Define each of the IOSF-SB register offsets used by MRC. + + +// MCU registers (DUNIT): +// ==== +#define DRP 0x0000 +#define DTR0 0x0001 +#define DTR1 0x0002 +#define DTR2 0x0003 +#define DTR3 0x0004 +#define DTR4 0x0005 +#define DPMC0 0x0006 +#define DPMC1 0x0007 +#define DRFC 0x0008 +#define DSCH 0x0009 +#define DCAL 0x000A +#define DRMC 0x000B +#define PMSTS 0x000C +#define DCO 0x000F +#define DSTAT 0x0020 +#define DECCCTRL 0x0060 +#define DFUSESTAT 0x0070 +#define SCRMSEED 0x0080 +#define SCRMLO 0x0081 +#define SCRMHI 0x0082 + +#define MCU_CH_OFFSET 0x0040 +#define MCU_RK_OFFSET 0x0020 + +//// +// +// BEGIN DUnit register definition +// +#pragma pack(1) +typedef union { + uint32_t raw; + struct { + uint32_t rank0Enabled :1; /**< BIT [0] Rank 0 Enable */ + uint32_t rank1Enabled :1; /**< BIT [1] Rank 1 Enable */ + uint32_t reserved0 :2; + uint32_t dimm0DevWidth :2; /**< BIT [5:4] DIMM 0 Device Width (Rank0&1) */ + uint32_t dimm0DevDensity :2; /**< BIT [7:6] DIMM 0 Device Density */ + uint32_t reserved1 :1; + uint32_t dimm1DevWidth :2; /**< BIT [10:9] DIMM 1 Device Width (Rank2&3) */ + uint32_t dimm1DevDensity :2; /**< BIT [12:11] DIMM 1 Device Density */ + uint32_t split64 :1; /**< BIT [13] split 64B transactions */ + uint32_t addressMap :2; /**< BIT [15:14] Address Map select */ + uint32_t reserved3 :14; + uint32_t mode32 :1; /**< BIT [30] Select 32bit data interface*/ + uint32_t reserved4 :1; + } field; +} RegDRP; /**< DRAM Rank Population and Interface Register */ +#pragma pack() + + +#pragma pack(1) +typedef union { + uint32_t raw; + struct { + uint32_t dramFrequency :2; /**< DRAM Frequency (000=800,001=1033,010=1333) */ + uint32_t reserved1 :2; + uint32_t tRP :4; /**< bit [7:4] Precharge to Activate Delay */ + uint32_t tRCD :4; /**< bit [11:8] Activate to CAS Delay */ + uint32_t tCL :3; /**< bit [14:12] CAS Latency */ + uint32_t reserved4 :1; + uint32_t tXS :1; /**< SRX Delay */ + uint32_t reserved5 :1; + uint32_t tXSDLL :1; /**< SRX To DLL Delay */ + uint32_t reserved6 :1; + uint32_t tZQCS :1; /**< bit [20] ZQTS recovery Latncy */ + uint32_t reserved7 :1; + uint32_t tZQCL :1; /**< bit [22] ZQCL recovery Latncy */ + uint32_t reserved8 :1; + uint32_t pmeDelay :2; /**< bit [25:24] Power mode entry delay */ + uint32_t reserved9 :2; + uint32_t CKEDLY :4; /**< bit [31:28] */ + } field; +} RegDTR0; /**< DRAM Timing Register 0 */ +#pragma pack() + +#pragma pack(1) +typedef union { + uint32_t raw; + struct { + uint32_t tWCL :3; /**< bit [2:0] CAS Write Latency */ + uint32_t reserved1 :1; + uint32_t tCMD :2; /**< bit [5:4] Command transport duration */ + uint32_t reserved2 :2; + uint32_t tWTP :4; /**< Write to Precharge */ + uint32_t tCCD :2; /**< CAS to CAS delay */ + uint32_t reserved4 :2; + uint32_t tFAW :4; /**< Four bank Activation Window*/ + uint32_t tRAS :4; /**< Row Activation Period: */ + uint32_t tRRD :2; /**mem_size >> 6) - 1); +#endif + + isbW32m(HTE, 0x00020063, 0xAAAAAAAA); + isbW32m(HTE, 0x00020064, 0xCCCCCCCC); + isbW32m(HTE, 0x00020065, 0xF0F0F0F0); + isbW32m(HTE, 0x00020066, 0x03000000); + + switch (MemInitFlag) + { + case MrcMemInit: + TestNum = 1; // Only 1 write pass through memory is needed to initialize ECC. + break; + case MrcMemTest: + TestNum = 4; // Write/read then write/read with inverted pattern. + break; + default: + DPF(D_INFO, "Unknown parameter for MemInitFlag: %d\n", MemInitFlag); + return 0xFFFFFFFF; + break; + } + + DPF(D_INFO, "HteMemInit"); + for (i = 0; i < TestNum; i++) + { + DPF(D_INFO, "."); + + if (i == 0) + { + isbW32m(HTE, 0x00020061, 0x00000000); + isbW32m(HTE, 0x00020020, 0x00110010); + } + else if (i == 1) + { + isbW32m(HTE, 0x00020061, 0x00000000); + isbW32m(HTE, 0x00020020, 0x00010010); + } + else if (i == 2) + { + isbW32m(HTE, 0x00020061, 0x00010100); + isbW32m(HTE, 0x00020020, 0x00110010); + } + else + { + isbW32m(HTE, 0x00020061, 0x00010100); + isbW32m(HTE, 0x00020020, 0x00010010); + } + + isbW32m(HTE, 0x00020011, 0x00111000); + isbW32m(HTE, 0x00020011, 0x00111100); + + WaitForHteComplete(); + + // + // If this is a READ pass, check for errors at the end. + // + if ((i % 2) == 1) + { + // + // Return immediately if error. + // + if (CheckHteErrors()) + { + break; + } + } + } + + DPF(D_INFO, "done\n", i); + return CheckHteErrors(); +} + +STATIC UINT16 BasicDataCompareHte( + MRC_PARAMS *CurrentMrcData, + UINT32 Address, + UINT8 FirstRun, + UINT8 Mode) +/*++ + + Routine Description: + + Execute basic single cache line memory write/read/verify test using simple constant + pattern (different for READ_RAIN and WRITE_TRAIN modes. + See BasicWriteReadHTE which is external visible wrapper. + + Arguments: + + CurrentMrcData: Host struture for all MRC global data. + Address: memory adress being tested (must hit specific channel/rank) + FirstRun: If set then hte registers are configured, otherwise + it is assumed configuration is done and just re-run the test. + Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern) + + Returns: + Returns byte lane failure on each bit (for Quark only bit0 and bit1) + + --*/ +{ + UINT32 Pattern; + UINT32 Offset; + + if (FirstRun) + { + isbW32m(HTE, 0x00020020, 0x01B10021); + isbW32m(HTE, 0x00020021, 0x06000000); + isbW32m(HTE, 0x00020022, Address >> 6); + isbW32m(HTE, 0x00020062, 0x00800015); + isbW32m(HTE, 0x00020063, 0xAAAAAAAA); + isbW32m(HTE, 0x00020064, 0xCCCCCCCC); + isbW32m(HTE, 0x00020065, 0xF0F0F0F0); + isbW32m(HTE, 0x00020061, 0x00030008); + + if (Mode == WRITE_TRAIN) + { + Pattern = 0xC33C0000; + } + else // READ_TRAIN + { + Pattern = 0xAA5555AA; + } + + for (Offset = 0x80; Offset <= 0x8F; Offset++) + { + isbW32m(HTE, Offset, Pattern); + } + } + + isbW32m(HTE, 0x000200A1, 0xFFFF1000); + + isbW32m(HTE, 0x00020011, 0x00011000); + isbW32m(HTE, 0x00020011, 0x00011100); + + WaitForHteComplete(); + + // + // Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for any bytelane errors. + // + return ((CheckHteErrors() >> 8) & 0xFF); +} + +STATIC UINT16 ReadWriteDataCompareHte( + MRC_PARAMS *CurrentMrcData, + UINT32 Address, + UINT8 LoopCount, + UINT32 LfsrSeedVictim, + UINT32 LfsrSeedAggressor, + UINT8 VictimBit, + UINT8 FirstRun) +/*++ + + Routine Description: + + Examines single cache line memory with write/read/verify test using + multiple data patterns (victim-aggressor algorithm). + See WriteStressBitLanesHTE which is external visible wrapper. + + Arguments: + + CurrentMrcData: host struture for all MRC global data. + Address: memory adress being tested (must hit specific channel/rank) + LoopCount: number of test iterations + LfsrSeedXxx: victim aggressor data pattern seed + VictimBit: should be 0 as auto rotate feature is in use. + FirstRun: If set then hte registers are configured, otherwise + it is assumed configuration is done and just re-run the test. + + Returns: + Returns byte lane failure on each bit (for Quark only bit0 and bit1) + + --*/ +{ + UINT32 Offset; + UINT32 Tmp; + + if (FirstRun) + { + isbW32m(HTE, 0x00020020, 0x00910024); + isbW32m(HTE, 0x00020023, 0x00810024); + isbW32m(HTE, 0x00020021, 0x06070000); + isbW32m(HTE, 0x00020024, 0x06070000); + isbW32m(HTE, 0x00020022, Address >> 6); + isbW32m(HTE, 0x00020025, Address >> 6); + isbW32m(HTE, 0x00020062, 0x0000002A); + isbW32m(HTE, 0x00020063, LfsrSeedVictim); + isbW32m(HTE, 0x00020064, LfsrSeedAggressor); + isbW32m(HTE, 0x00020065, LfsrSeedVictim); + + // + // Write the pattern buffers to select the victim bit. Start with bit0. + // + for (Offset = 0x80; Offset <= 0x8F; Offset++) + { + if ((Offset % 8) == VictimBit) + { + isbW32m(HTE, Offset, 0x55555555); + } + else + { + isbW32m(HTE, Offset, 0xCCCCCCCC); + } + } + + isbW32m(HTE, 0x00020061, 0x00000000); + isbW32m(HTE, 0x00020066, 0x03440000); + isbW32m(HTE, 0x000200A1, 0xFFFF1000); + } + + Tmp = 0x10001000 | (LoopCount << 16); + isbW32m(HTE, 0x00020011, Tmp); + isbW32m(HTE, 0x00020011, Tmp | BIT8); + + WaitForHteComplete(); + + return (CheckHteErrors() >> 8) & 0xFF; +} + +UINT16 BasicWriteReadHTE( + MRC_PARAMS *CurrentMrcData, + UINT32 Address, + UINT8 FirstRun, + UINT8 Mode) +/*++ + + Routine Description: + + Execute basic single cache line memory write/read/verify test using simple constant + pattern (different for READ_RAIN and WRITE_TRAIN modes. + + Arguments: + + CurrentMrcData: Host struture for all MRC global data. + Address: memory adress being tested (must hit specific channel/rank) + FirstRun: If set then hte registers are configured, otherwise + it is assumed configuration is done and just re-run the test. + Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern) + + Returns: + Returns byte lane failure on each bit (for Quark only bit0 and bit1) + + --*/ +{ + UINT16 ByteLaneErrors; + + ENTERFN(); + + // + // Enable all error reporting in preparation for HTE test. + // + EnableAllHteErrors(0xFF); + ClearHteErrorRegisters(); + + ByteLaneErrors = BasicDataCompareHte(CurrentMrcData, Address, FirstRun, + Mode); + + LEAVEFN(); + return ByteLaneErrors; +} + +UINT16 WriteStressBitLanesHTE( + MRC_PARAMS *CurrentMrcData, + UINT32 Address, + UINT8 FirstRun) +/*++ + + Routine Description: + + Examines single cache line memory with write/read/verify test using + multiple data patterns (victim-aggressor algorithm). + + Arguments: + + CurrentMrcData: host struture for all MRC global data. + Address: memory adress being tested (must hit specific channel/rank) + FirstRun: If set then hte registers are configured, otherwise + it is assumed configuration is done and just re-run the test. + + Returns: + Returns byte lane failure on each bit (for Quark only bit0 and bit1) + + --*/ +{ + UINT16 ByteLaneErrors; + UINT8 VictimBit = 0; + + ENTERFN(); + + // + // Enable all error reporting in preparation for HTE test. + // + EnableAllHteErrors(0xFF); + ClearHteErrorRegisters(); + + // + // Loop through each bit in the bytelane. Each pass creates a victim bit + // while keeping all other bits the same - as aggressors. + // AVN HTE adds an auto-rotate feature which allows us to program the entire victim/aggressor + // sequence in 1 step. The victim bit rotates on each pass so no need to have software implement + // a victim bit loop like on VLV. + // + ByteLaneErrors = ReadWriteDataCompareHte(CurrentMrcData, Address, + HTE_LOOP_CNT, HTE_LFSR_VICTIM_SEED, HTE_LFSR_AGRESSOR_SEED, VictimBit, + FirstRun); + + LEAVEFN(); + return ByteLaneErrors; +} + +VOID HteMemOp( + UINT32 Address, + UINT8 FirstRun, + UINT8 IsWrite) +/*++ + + Routine Description: + + Execute basic single cache line memory write or read. + This is just for receive enable / fine write levelling purpose. + + Arguments: + + CurrentMrcData: Host structure for all MRC global data. + Address: memory address used (must hit specific channel/rank) + FirstRun: If set then hte registers are configured, otherwise + it is assumed configuration is done and just re-run the test. + IsWrite: When non-zero memory write operation executed, otherwise read + + Returns: + None + + --*/ +{ + UINT32 Offset; + UINT32 Tmp; + + EnableAllHteErrors(0xFF); + ClearHteErrorRegisters(); + + if (FirstRun) + { + Tmp = IsWrite ? 0x01110021 : 0x01010021; + isbW32m(HTE, 0x00020020, Tmp); + + isbW32m(HTE, 0x00020021, 0x06000000); + isbW32m(HTE, 0x00020022, Address >> 6); + isbW32m(HTE, 0x00020062, 0x00800015); + isbW32m(HTE, 0x00020063, 0xAAAAAAAA); + isbW32m(HTE, 0x00020064, 0xCCCCCCCC); + isbW32m(HTE, 0x00020065, 0xF0F0F0F0); + isbW32m(HTE, 0x00020061, 0x00030008); + + for (Offset = 0x80; Offset <= 0x8F; Offset++) + { + isbW32m(HTE, Offset, 0xC33C0000); + } + } + + isbW32m(HTE, 0x000200A1, 0xFFFF1000); + isbW32m(HTE, 0x00020011, 0x00011000); + isbW32m(HTE, 0x00020011, 0x00011100); + + WaitForHteComplete(); +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h new file mode 100644 index 0000000000..1ad13342af --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h @@ -0,0 +1,66 @@ +/** @file +HTE handling routines for MRC use. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef __HTE_H +#define __HTE_H + +#define STATIC static +#define VOID void + +#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L) +typedef uint32_t UINT32; +typedef uint16_t UINT16; +typedef uint8_t UINT8; +#endif + +typedef enum +{ + MrcNoHaltSystemOnError, + MrcHaltSystemOnError, + MrcHaltHteEngineOnError, + MrcNoHaltHteEngineOnError +} HALT_TYPE; + +typedef enum +{ + MrcMemInit, MrcMemTest +} MEM_INIT_OR_TEST; + +#define READ_TRAIN 1 +#define WRITE_TRAIN 2 + +#define HTE_MEMTEST_NUM 2 +#define HTE_LOOP_CNT 5 // EXP_LOOP_CNT field of HTE_CMD_CTL. This CANNOT be less than 4 +#define HTE_LFSR_VICTIM_SEED 0xF294BA21 // Random seed for victim. +#define HTE_LFSR_AGRESSOR_SEED 0xEBA7492D // Random seed for aggressor. +UINT32 +HteMemInit( + MRC_PARAMS *CurrentMrcData, + UINT8 MemInitFlag, + UINT8 HaltHteEngineOnError); + +UINT16 +BasicWriteReadHTE( + MRC_PARAMS *CurrentMrcData, + UINT32 Address, + UINT8 FirstRun, + UINT8 Mode); + +UINT16 +WriteStressBitLanesHTE( + MRC_PARAMS *CurrentMrcData, + UINT32 Address, + UINT8 FirstRun); + +VOID +HteMemOp( + UINT32 Address, + UINT8 FirstRun, + UINT8 IsWrite); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h new file mode 100644 index 0000000000..e2f7916014 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h @@ -0,0 +1,132 @@ +/** @file +Declaration of IO handling routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef __IO_H +#define __IO_H + +#include "core_types.h" + +#include "general_definitions.h" +#include "gen5_iosf_sb_definitions.h" + +// Instruction not present on Quark +#define SFENCE() + +#define DEAD_LOOP() for(;;); + +//// +// Define each of the IOSF_SB ports used by MRC +// + +// +// Has to be 0 because of emulation static data +// initialisation: +// Space_t EmuSpace[ SPACE_COUNT] = {0}; +// +#define FREE 0x000 + +// Pseudo side-band ports for access abstraction +// See Wr32/Rd32 functions +#define MEM 0x101 +#define MMIO 0x102 +#define DCMD 0x0A0 + +// Real side-band ports +// See Wr32/Rd32 functions +#define MCU 0x001 +#define HOST_BRIDGE 0x003 +#define MEMORY_MANAGER 0x005 +#define HTE 0x011 +#define DDRPHY 0x012 +#define FUSE 0x033 + +// End of IOSF_SB ports +//// + +// Pciexbar address +#define EC_BASE 0xE0000000 + +#define PCIADDR(bus,dev,fn,reg) ( \ + (EC_BASE) + \ + ((bus) << 20) + \ + ((dev) << 15) + \ + ((fn) << 12) + \ + (reg)) + +// Various offsets used in the building sideband commands. +#define SB_OPCODE_OFFSET 24 +#define SB_PORT_OFFSET 16 +#define SB_REG_OFFEST 8 + +// Sideband opcodes +#define SB_REG_READ_OPCODE 0x10 +#define SB_REG_WRITE_OPCODE 0x11 + +#define SB_FUSE_REG_READ_OPCODE 0x06 +#define SB_FUSE_REG_WRITE_OPCODE 0x07 + +#define SB_DDRIO_REG_READ_OPCODE 0x06 +#define SB_DDRIO_REG_WRITE_OPCODE 0x07 + +#define SB_DRAM_CMND_OPCODE 0x68 +#define SB_WAKE_CMND_OPCODE 0xCA +#define SB_SUSPEND_CMND_OPCODE 0xCC + +// Register addresses for sideband command and data. +#define SB_PACKET_REG 0x00D0 +#define SB_DATA_REG 0x00D4 +#define SB_HADR_REG 0x00D8 + +// We always flag all 4 bytes in the register reads/writes as required. +#define SB_ALL_BYTES_ENABLED 0xF0 + +#define SB_COMMAND(Opcode, Port, Reg) \ + ((Opcode << SB_OPCODE_OFFSET) | \ + (Port << SB_PORT_OFFSET) | \ + (Reg << SB_REG_OFFEST) | \ + SB_ALL_BYTES_ENABLED) + +// iosf +#define isbM32m WrMask32 +#define isbW32m Wr32 +#define isbR32m Rd32 + +// pci + +void pciwrite32( + uint32_t bus, + uint32_t dev, + uint32_t fn, + uint32_t reg, + uint32_t data); + +uint32_t pciread32( + uint32_t bus, + uint32_t dev, + uint32_t fn, + uint32_t reg); + +// general + +uint32_t Rd32( + uint32_t unit, + uint32_t addr); + +void Wr32( + uint32_t unit, + uint32_t addr, + uint32_t data); + +void WrMask32( + uint32_t unit, + uint32_t addr, + uint32_t data, + uint32_t mask); + + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c new file mode 100644 index 0000000000..21d935bc65 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c @@ -0,0 +1,382 @@ +/** @file +Serial conole output and string formating. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "memory_options.h" +#include "general_definitions.h" + +// Resource programmed to PCI bridge, 1MB bound alignment is needed. +// The default value is overwritten by MRC parameter, assuming code +// relocated to eSRAM. +uint32_t UartMmioBase = 0; + +// Serial port registers based on SerialPortLib.c +#define R_UART_BAUD_THR 0 +#define R_UART_LSR 20 + +#define B_UART_LSR_RXRDY BIT0 +#define B_UART_LSR_TXRDY BIT5 +#define B_UART_LSR_TEMT BIT6 + +// Print mask see DPF and D_Xxxx +#define DPF_MASK DpfPrintMask + +// Select class of messages enabled for printing +uint32_t DpfPrintMask = + D_ERROR | + D_INFO | + // D_REGRD | + // D_REGWR | + // D_FCALL | + // D_TRN | + 0; + +#ifdef NDEBUG +// Don't generate debug code +void dpf( uint32_t mask, char_t* bla, ...) +{ + return; +} + +uint8_t mgetc(void) +{ + return 0; +} + +uint8_t mgetch(void) +{ + return 0; +} + +#else + +#ifdef SIM +// Use Vpi console in simulation environment +#include + +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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c new file mode 100644 index 0000000000..64f0a1130e --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c @@ -0,0 +1,2638 @@ +/************************************************************************ + * + * Copyright (c) 2013-2015 Intel Corporation. + * +* SPDX-License-Identifier: BSD-2-Clause-Patent + * + * This file contains all of the Cat Mountain Memory Reference Code (MRC). + * + * These functions are generic and should work for any Cat Mountain config. + * + * MRC requires two data structures to be passed in which are initialised by "PreMemInit()". + * + * The basic flow is as follows: + * 01) Check for supported DDR speed configuration + * 02) Set up MEMORY_MANAGER buffer as pass-through (POR) + * 03) Set Channel Interleaving Mode and Channel Stride to the most aggressive setting possible + * 04) Set up the MCU logic + * 05) Set up the DDR_PHY logic + * 06) Initialise the DRAMs (JEDEC) + * 07) Perform the Receive Enable Calibration algorithm + * 08) Perform the Write Leveling algorithm + * 09) Perform the Read Training algorithm (includes internal Vref) + * 10) Perform the Write Training algorithm + * 11) Set Channel Interleaving Mode and Channel Stride to the desired settings + * + * Dunit configuration based on Valleyview MRC. + * + ***************************************************************************/ + +#include "mrc.h" +#include "memory_options.h" + +#include "meminit.h" +#include "meminit_utils.h" +#include "hte.h" +#include "io.h" + +// Override ODT to off state if requested +#define DRMC_DEFAULT (mrc_params->rd_odt_value==0?BIT12:0) + + +// tRFC values (in picoseconds) per density +const uint32_t tRFC[5] = +{ + 90000, // 512Mb + 110000, // 1Gb + 160000, // 2Gb + 300000, // 4Gb + 350000, // 8Gb + }; + +// tCK clock period in picoseconds per speed index 800, 1066, 1333 +const uint32_t tCK[3] = +{ + 2500, + 1875, + 1500 +}; + +#ifdef SIM +// Select static timings specific to simulation environment +#define PLATFORM_ID 0 +#else +// Select static timings specific to ClantonPeek platform +#define PLATFORM_ID 1 +#endif + + +// Global variables +const uint16_t ddr_wclk[] = + {193, 158}; + +const uint16_t ddr_wctl[] = + { 1, 217}; + +const uint16_t ddr_wcmd[] = + { 1, 220}; + + +#ifdef BACKUP_RCVN +const uint16_t ddr_rcvn[] = + {129, 498}; +#endif // BACKUP_RCVN + +#ifdef BACKUP_WDQS +const uint16_t ddr_wdqs[] = + { 65, 289}; +#endif // BACKUP_WDQS + +#ifdef BACKUP_RDQS +const uint8_t ddr_rdqs[] = + { 32, 24}; +#endif // BACKUP_RDQS + +#ifdef BACKUP_WDQ +const uint16_t ddr_wdq[] = + { 32, 257}; +#endif // BACKUP_WDQ + + + +// Select MEMORY_MANAGER as the source for PRI interface +static void select_memory_manager( + MRCParams_t *mrc_params) +{ + RegDCO Dco; + + ENTERFN(); + + Dco.raw = isbR32m(MCU, DCO); + Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER + isbW32m(MCU, DCO, Dco.raw); + + LEAVEFN(); +} + +// Select HTE as the source for PRI interface +void select_hte( + MRCParams_t *mrc_params) +{ + RegDCO Dco; + + ENTERFN(); + + Dco.raw = isbR32m(MCU, DCO); + Dco.field.PMICTL = 1; //1 - PRI owned by HTE + isbW32m(MCU, DCO, Dco.raw); + + LEAVEFN(); +} + +// Send DRAM command, data should be formated +// using DCMD_Xxxx macro or emrsXCommand structure. +static void dram_init_command( + uint32_t data) +{ + Wr32(DCMD, 0, data); +} + +// Send DRAM wake command using special MCU side-band WAKE opcode +static void dram_wake_command( + void) +{ + ENTERFN(); + + Wr32(MMIO, PCIADDR(0,0,0,SB_PACKET_REG), + (uint32_t) SB_COMMAND(SB_WAKE_CMND_OPCODE, MCU, 0)); + + LEAVEFN(); +} + +// Stop self refresh driven by MCU +static void clear_self_refresh( + MRCParams_t *mrc_params) +{ + ENTERFN(); + + // clear the PMSTS Channel Self Refresh bits + isbM32m(MCU, PMSTS, BIT0, BIT0); + + LEAVEFN(); +} + +// Configure MCU before jedec init sequence +static void prog_decode_before_jedec( + MRCParams_t *mrc_params) +{ + RegDRP Drp; + RegDRCF Drfc; + RegDCAL Dcal; + RegDSCH Dsch; + RegDPMC0 Dpmc0; + + ENTERFN(); + + // Disable power saving features + Dpmc0.raw = isbR32m(MCU, DPMC0); + Dpmc0.field.CLKGTDIS = 1; + Dpmc0.field.DISPWRDN = 1; + Dpmc0.field.DYNSREN = 0; + Dpmc0.field.PCLSTO = 0; + isbW32m(MCU, DPMC0, Dpmc0.raw); + + // Disable out of order transactions + Dsch.raw = isbR32m(MCU, DSCH); + Dsch.field.OOODIS = 1; + Dsch.field.NEWBYPDIS = 1; + isbW32m(MCU, DSCH, Dsch.raw); + + // Disable issuing the REF command + Drfc.raw = isbR32m(MCU, DRFC); + Drfc.field.tREFI = 0; + isbW32m(MCU, DRFC, Drfc.raw); + + // Disable ZQ calibration short + Dcal.raw = isbR32m(MCU, DCAL); + Dcal.field.ZQCINT = 0; + Dcal.field.SRXZQCL = 0; + isbW32m(MCU, DCAL, Dcal.raw); + + // Training performed in address mode 0, rank population has limited impact, however + // simulator complains if enabled non-existing rank. + Drp.raw = 0; + if (mrc_params->rank_enables & 1) + Drp.field.rank0Enabled = 1; + if (mrc_params->rank_enables & 2) + Drp.field.rank1Enabled = 1; + isbW32m(MCU, DRP, Drp.raw); + + LEAVEFN(); +} + +// After Cold Reset, BIOS should set COLDWAKE bit to 1 before +// sending the WAKE message to the Dunit. +// For Standby Exit, or any other mode in which the DRAM is in +// SR, this bit must be set to 0. +static void perform_ddr_reset( + MRCParams_t *mrc_params) +{ + ENTERFN(); + + // Set COLDWAKE bit before sending the WAKE message + isbM32m(MCU, DRMC, BIT16, BIT16); + + // Send wake command to DUNIT (MUST be done before JEDEC) + dram_wake_command(); + + // Set default value + isbW32m(MCU, DRMC, DRMC_DEFAULT); + + LEAVEFN(); +} + +// Dunit Initialisation Complete. +// Indicates that initialisation of the Dunit has completed. +// Memory accesses are permitted and maintenance operation +// begins. Until this bit is set to a 1, the memory controller will +// not accept DRAM requests from the MEMORY_MANAGER or HTE. +static void set_ddr_init_complete( + MRCParams_t *mrc_params) +{ + RegDCO Dco; + + ENTERFN(); + + Dco.raw = isbR32m(MCU, DCO); + Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER + Dco.field.IC = 1; //1 - initialisation complete + isbW32m(MCU, DCO, Dco.raw); + + LEAVEFN(); +} + +static void prog_page_ctrl( + MRCParams_t *mrc_params) +{ + RegDPMC0 Dpmc0; + + ENTERFN(); + + Dpmc0.raw = isbR32m(MCU, DPMC0); + + Dpmc0.field.PCLSTO = 0x4; + Dpmc0.field.PREAPWDEN = 1; + + isbW32m(MCU, DPMC0, Dpmc0.raw); +} + +// Configure MCU Power Management Control Register +// and Scheduler Control Register. +static void prog_ddr_control( + MRCParams_t *mrc_params) +{ + RegDSCH Dsch; + RegDPMC0 Dpmc0; + + ENTERFN(); + + Dpmc0.raw = isbR32m(MCU, DPMC0); + Dsch.raw = isbR32m(MCU, DSCH); + + Dpmc0.field.DISPWRDN = mrc_params->power_down_disable; + Dpmc0.field.CLKGTDIS = 0; + Dpmc0.field.PCLSTO = 4; + Dpmc0.field.PREAPWDEN = 1; + + Dsch.field.OOODIS = 0; + Dsch.field.OOOST3DIS = 0; + Dsch.field.NEWBYPDIS = 0; + + isbW32m(MCU, DSCH, Dsch.raw); + isbW32m(MCU, DPMC0, Dpmc0.raw); + + // CMDTRIST = 2h - CMD/ADDR are tristated when no valid command + isbM32m(MCU, DPMC1, 2 << 4, BIT5|BIT4); + + LEAVEFN(); +} + +// After training complete configure MCU Rank Population Register +// specifying: ranks enabled, device width, density, address mode. +static void prog_dra_drb( + MRCParams_t *mrc_params) +{ + RegDRP Drp; + RegDCO Dco; + + ENTERFN(); + + Dco.raw = isbR32m(MCU, DCO); + Dco.field.IC = 0; + isbW32m(MCU, DCO, Dco.raw); + + Drp.raw = 0; + if (mrc_params->rank_enables & 1) + Drp.field.rank0Enabled = 1; + if (mrc_params->rank_enables & 2) + Drp.field.rank1Enabled = 1; + if (mrc_params->dram_width == x16) + { + Drp.field.dimm0DevWidth = 1; + Drp.field.dimm1DevWidth = 1; + } + // Density encoding in DRAMParams_t 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb + // has to be mapped RANKDENSx encoding (0=1Gb) + Drp.field.dimm0DevDensity = mrc_params->params.DENSITY - 1; + Drp.field.dimm1DevDensity = mrc_params->params.DENSITY - 1; + + // Address mode can be overwritten if ECC enabled + Drp.field.addressMap = mrc_params->address_mode; + + isbW32m(MCU, DRP, Drp.raw); + + Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER + Dco.field.IC = 1; //1 - initialisation complete + isbW32m(MCU, DCO, Dco.raw); + + LEAVEFN(); +} + +// Configure refresh rate and short ZQ calibration interval. +// Activate dynamic self refresh. +static void change_refresh_period( + MRCParams_t *mrc_params) +{ + RegDRCF Drfc; + RegDCAL Dcal; + RegDPMC0 Dpmc0; + + ENTERFN(); + + Drfc.raw = isbR32m(MCU, DRFC); + Drfc.field.tREFI = mrc_params->refresh_rate; + Drfc.field.REFDBTCLR = 1; + isbW32m(MCU, DRFC, Drfc.raw); + + Dcal.raw = isbR32m(MCU, DCAL); + Dcal.field.ZQCINT = 3; // 63ms + isbW32m(MCU, DCAL, Dcal.raw); + + Dpmc0.raw = isbR32m(MCU, DPMC0); + Dpmc0.field.ENPHYCLKGATE = 1; + Dpmc0.field.DYNSREN = 1; + isbW32m(MCU, DPMC0, Dpmc0.raw); + + LEAVEFN(); +} + +// Send DRAM wake command +static void perform_wake( + MRCParams_t *mrc_params) +{ + ENTERFN(); + + dram_wake_command(); + + LEAVEFN(); +} + +// prog_ddr_timing_control (aka mcu_init): +// POST_CODE[major] == 0x02 +// +// It will initialise timing registers in the MCU (DTR0..DTR4). +static void prog_ddr_timing_control( + MRCParams_t *mrc_params) +{ + uint8_t TCL, WL; + uint8_t TRP, TRCD, TRAS, TWR, TWTR, TRRD, TRTP, TFAW; + uint32_t TCK; + + RegDTR0 Dtr0; + RegDTR1 Dtr1; + RegDTR2 Dtr2; + RegDTR3 Dtr3; + RegDTR4 Dtr4; + + ENTERFN(); + + // mcu_init starts + post_code(0x02, 0x00); + + Dtr0.raw = isbR32m(MCU, DTR0); + Dtr1.raw = isbR32m(MCU, DTR1); + Dtr2.raw = isbR32m(MCU, DTR2); + Dtr3.raw = isbR32m(MCU, DTR3); + Dtr4.raw = isbR32m(MCU, DTR4); + + TCK = tCK[mrc_params->ddr_speed]; // Clock in picoseconds + TCL = mrc_params->params.tCL; // CAS latency in clocks + TRP = TCL; // Per CAT MRC + TRCD = TCL; // Per CAT MRC + TRAS = MCEIL(mrc_params->params.tRAS, TCK); + TWR = MCEIL(15000, TCK); // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 + + TWTR = MCEIL(mrc_params->params.tWTR, TCK); + TRRD = MCEIL(mrc_params->params.tRRD, TCK); + TRTP = 4; // Valid for 800 and 1066, use 5 for 1333 + TFAW = MCEIL(mrc_params->params.tFAW, TCK); + + WL = 5 + mrc_params->ddr_speed; + + Dtr0.field.dramFrequency = mrc_params->ddr_speed; + + Dtr0.field.tCL = TCL - 5; //Convert from TCL (DRAM clocks) to VLV indx + Dtr0.field.tRP = TRP - 5; //5 bit DRAM Clock + Dtr0.field.tRCD = TRCD - 5; //5 bit DRAM Clock + + Dtr1.field.tWCL = WL - 3; //Convert from WL (DRAM clocks) to VLV indx + Dtr1.field.tWTP = WL + 4 + TWR - 14; //Change to tWTP + Dtr1.field.tRTP = MMAX(TRTP, 4) - 3; //4 bit DRAM Clock + Dtr1.field.tRRD = TRRD - 4; //4 bit DRAM Clock + Dtr1.field.tCMD = 1; //2N + Dtr1.field.tRAS = TRAS - 14; //6 bit DRAM Clock + + Dtr1.field.tFAW = ((TFAW + 1) >> 1) - 5; //4 bit DRAM Clock + Dtr1.field.tCCD = 0; //Set 4 Clock CAS to CAS delay (multi-burst) + Dtr2.field.tRRDR = 1; + Dtr2.field.tWWDR = 2; + Dtr2.field.tRWDR = 2; + Dtr3.field.tWRDR = 2; + Dtr3.field.tWRDD = 2; + + if (mrc_params->ddr_speed == DDRFREQ_800) + { + // Extended RW delay (+1) + Dtr3.field.tRWSR = TCL - 5 + 1; + } + else if(mrc_params->ddr_speed == DDRFREQ_1066) + { + // Extended RW delay (+1) + Dtr3.field.tRWSR = TCL - 5 + 1; + } + + Dtr3.field.tWRSR = 4 + WL + TWTR - 11; + + if (mrc_params->ddr_speed == DDRFREQ_800) + { + Dtr3.field.tXP = MMAX(0, 1 - Dtr1.field.tCMD); + } + else + { + Dtr3.field.tXP = MMAX(0, 2 - Dtr1.field.tCMD); + } + + Dtr4.field.WRODTSTRT = Dtr1.field.tCMD; + Dtr4.field.WRODTSTOP = Dtr1.field.tCMD; + Dtr4.field.RDODTSTRT = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2; //Convert from WL (DRAM clocks) to VLV indx + Dtr4.field.RDODTSTOP = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2; + Dtr4.field.TRGSTRDIS = 0; + Dtr4.field.ODTDIS = 0; + + isbW32m(MCU, DTR0, Dtr0.raw); + isbW32m(MCU, DTR1, Dtr1.raw); + isbW32m(MCU, DTR2, Dtr2.raw); + isbW32m(MCU, DTR3, Dtr3.raw); + isbW32m(MCU, DTR4, Dtr4.raw); + + LEAVEFN(); +} + +// ddrphy_init: +// POST_CODE[major] == 0x03 +// +// This function performs some initialisation on the DDRIO unit. +// This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES. +static void ddrphy_init(MRCParams_t *mrc_params) +{ + uint32_t tempD; // temporary DWORD + uint8_t channel_i; // channel counter + uint8_t rank_i; // rank counter + uint8_t bl_grp_i; // byte lane group counter (2 BLs per module) + + uint8_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/1; // byte lane divisor + uint8_t speed = mrc_params->ddr_speed & (BIT1|BIT0); // For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333 + uint8_t tCAS; + uint8_t tCWL; + + ENTERFN(); + + tCAS = mrc_params->params.tCL; + tCWL = 5 + mrc_params->ddr_speed; + + // ddrphy_init starts + post_code(0x03, 0x00); + + // HSD#231531 + // Make sure IOBUFACT is deasserted before initialising the DDR PHY. + // HSD#234845 + // Make sure WRPTRENABLE is deasserted before initialising the DDR PHY. + for (channel_i=0; channel_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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h new file mode 100644 index 0000000000..961bbef9c7 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h @@ -0,0 +1,22 @@ +/************************************************************************ + * + * Copyright (c) 2013-2015 Intel Corporation. + * +* SPDX-License-Identifier: BSD-2-Clause-Patent + * + ************************************************************************/ +#ifndef _MEMINIT_H_ +#define _MEMINIT_H_ + +// function prototypes +void MemInit(MRCParams_t *mrc_params); + +typedef void (*MemInitFn_t)(MRCParams_t *mrc_params); + +typedef struct MemInit_s { + uint16_t post_code; + uint16_t boot_path; + MemInitFn_t init_fn; +} MemInit_t; + +#endif // _MEMINIT_H_ diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c new file mode 100644 index 0000000000..84de65955f --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c @@ -0,0 +1,1574 @@ +/************************************************************************ + * + * Copyright (c) 2013-2015 Intel Corporation. + * +* SPDX-License-Identifier: BSD-2-Clause-Patent + * + ***************************************************************************/ + +#include "mrc.h" +#include "memory_options.h" + +#include "meminit_utils.h" +#include "hte.h" +#include "io.h" + +void select_hte( + MRCParams_t *mrc_params); + +static uint8_t first_run = 0; + +const uint8_t vref_codes[64] = +{ // lowest to highest + 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, // 00 - 15 + 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, // 16 - 31 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 32 - 47 + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F // 48 - 63 +}; + +#ifdef EMU +// Track current post code for debugging purpose +uint32_t PostCode; +#endif + +// set_rcvn: +// +// This function will program the RCVEN delays. +// (currently doesn't comprehend rank) +void set_rcvn( + uint8_t channel, + uint8_t rank, + uint8_t byte_lane, + uint32_t pi_count) +{ + uint32_t reg; + uint32_t msk; + uint32_t tempD; + + ENTERFN(); + DPF(D_TRN, "Rcvn ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count); + + // RDPTR (1/2 MCLK, 64 PIs) + // BL0 -> B01PTRCTL0[11:08] (0x0-0xF) + // BL1 -> B01PTRCTL0[23:20] (0x0-0xF) + reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET); + msk = (byte_lane & BIT0) ? (BIT23 | BIT22 | BIT21 | BIT20) : (BIT11 | BIT10 | BIT9 | BIT8); + tempD = (byte_lane & BIT0) ? ((pi_count / HALF_CLK) << 20) : ((pi_count / HALF_CLK) << 8); + isbM32m(DDRPHY, reg, tempD, msk); + + // Adjust PI_COUNT + pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F) + // BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F) + reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0); + reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)); + msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24); + tempD = pi_count << 24; + isbM32m(DDRPHY, reg, tempD, msk); + + // DEADBAND + // BL0/1 -> B01DBCTL1[08/11] (+1 select) + // BL0/1 -> B01DBCTL1[02/05] (enable) + reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET); + msk = 0x00; + tempD = 0x00; + // enable + msk |= (byte_lane & BIT0) ? (BIT5) : (BIT2); + if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) + { + tempD |= msk; + } + // select + msk |= (byte_lane & BIT0) ? (BIT11) : (BIT8); + if (pi_count < EARLY_DB) + { + tempD |= msk; + } + isbM32m(DDRPHY, reg, tempD, msk); + + // error check + if (pi_count > 0x3F) + { + training_message(channel, rank, byte_lane); + post_code(0xEE, 0xE0); + } + + LEAVEFN(); + return; +} + +// get_rcvn: +// +// This function will return the current RCVEN delay on the given channel, rank, byte_lane as an absolute PI count. +// (currently doesn't comprehend rank) +uint32_t get_rcvn( + uint8_t channel, + uint8_t rank, + uint8_t byte_lane) +{ + uint32_t reg; + uint32_t tempD; + uint32_t pi_count; + + ENTERFN(); + + // RDPTR (1/2 MCLK, 64 PIs) + // BL0 -> B01PTRCTL0[11:08] (0x0-0xF) + // BL1 -> B01PTRCTL0[23:20] (0x0-0xF) + reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET); + tempD = isbR32m(DDRPHY, reg); + tempD >>= (byte_lane & BIT0) ? (20) : (8); + tempD &= 0xF; + + // Adjust PI_COUNT + pi_count = tempD * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F) + // BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F) + reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0); + reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)); + tempD = isbR32m(DDRPHY, reg); + tempD >>= 24; + tempD &= 0x3F; + + // Adjust PI_COUNT + pi_count += tempD; + + LEAVEFN(); + return pi_count; +} + +// set_rdqs: +// +// This function will program the RDQS delays based on an absolute amount of PIs. +// (currently doesn't comprehend rank) +void set_rdqs( + uint8_t channel, + uint8_t rank, + uint8_t byte_lane, + uint32_t pi_count) +{ + uint32_t reg; + uint32_t msk; + uint32_t tempD; + + ENTERFN(); + DPF(D_TRN, "Rdqs ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count); + + // PI (1/128 MCLK) + // BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47) + // BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47) + reg = (byte_lane & BIT0) ? (B1RXDQSPICODE) : (B0RXDQSPICODE); + reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)); + msk = (BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0); + tempD = pi_count << 0; + isbM32m(DDRPHY, reg, tempD, msk); + + // error check (shouldn't go above 0x3F) + if (pi_count > 0x47) + { + training_message(channel, rank, byte_lane); + post_code(0xEE, 0xE1); + } + + LEAVEFN(); + return; +} + +// get_rdqs: +// +// This function will return the current RDQS delay on the given channel, rank, byte_lane as an absolute PI count. +// (currently doesn't comprehend rank) +uint32_t get_rdqs( + uint8_t channel, + uint8_t rank, + uint8_t byte_lane) +{ + uint32_t reg; + uint32_t tempD; + uint32_t pi_count; + + ENTERFN(); + + // PI (1/128 MCLK) + // BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47) + // BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47) + reg = (byte_lane & BIT0) ? (B1RXDQSPICODE) : (B0RXDQSPICODE); + reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)); + tempD = isbR32m(DDRPHY, reg); + + // Adjust PI_COUNT + pi_count = tempD & 0x7F; + + LEAVEFN(); + return pi_count; +} + +// set_wdqs: +// +// This function will program the WDQS delays based on an absolute amount of PIs. +// (currently doesn't comprehend rank) +void set_wdqs( + uint8_t channel, + uint8_t rank, + uint8_t byte_lane, + uint32_t pi_count) +{ + uint32_t reg; + uint32_t msk; + uint32_t tempD; + + ENTERFN(); + DPF(D_TRN, "Wdqs ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count); + + // RDPTR (1/2 MCLK, 64 PIs) + // BL0 -> B01PTRCTL0[07:04] (0x0-0xF) + // BL1 -> B01PTRCTL0[19:16] (0x0-0xF) + reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET); + msk = (byte_lane & BIT0) ? (BIT19 | BIT18 | BIT17 | BIT16) : (BIT7 | BIT6 | BIT5 | BIT4); + tempD = pi_count / HALF_CLK; + tempD <<= (byte_lane & BIT0) ? (16) : (4); + isbM32m(DDRPHY, reg, tempD, msk); + + // Adjust PI_COUNT + pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F) + // BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F) + reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0); + reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)); + msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16); + tempD = pi_count << 16; + isbM32m(DDRPHY, reg, tempD, msk); + + // DEADBAND + // BL0/1 -> B01DBCTL1[07/10] (+1 select) + // BL0/1 -> B01DBCTL1[01/04] (enable) + reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET); + msk = 0x00; + tempD = 0x00; + // enable + msk |= (byte_lane & BIT0) ? (BIT4) : (BIT1); + if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) + { + tempD |= msk; + } + // select + msk |= (byte_lane & BIT0) ? (BIT10) : (BIT7); + if (pi_count < EARLY_DB) + { + tempD |= msk; + } + isbM32m(DDRPHY, reg, tempD, msk); + + // error check + if (pi_count > 0x3F) + { + training_message(channel, rank, byte_lane); + post_code(0xEE, 0xE2); + } + + LEAVEFN(); + return; +} + +// get_wdqs: +// +// This function will return the amount of WDQS delay on the given channel, rank, byte_lane as an absolute PI count. +// (currently doesn't comprehend rank) +uint32_t get_wdqs( + uint8_t channel, + uint8_t rank, + uint8_t byte_lane) +{ + uint32_t reg; + uint32_t tempD; + uint32_t pi_count; + + ENTERFN(); + + // RDPTR (1/2 MCLK, 64 PIs) + // BL0 -> B01PTRCTL0[07:04] (0x0-0xF) + // BL1 -> B01PTRCTL0[19:16] (0x0-0xF) + reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET); + tempD = isbR32m(DDRPHY, reg); + tempD >>= (byte_lane & BIT0) ? (16) : (4); + tempD &= 0xF; + + // Adjust PI_COUNT + pi_count = (tempD * HALF_CLK); + + // PI (1/64 MCLK, 1 PIs) + // BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F) + // BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F) + reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0); + reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)); + tempD = isbR32m(DDRPHY, reg); + tempD >>= 16; + tempD &= 0x3F; + + // Adjust PI_COUNT + pi_count += tempD; + + LEAVEFN(); + return pi_count; +} + +// set_wdq: +// +// This function will program the WDQ delays based on an absolute number of PIs. +// (currently doesn't comprehend rank) +void set_wdq( + uint8_t channel, + uint8_t rank, + uint8_t byte_lane, + uint32_t pi_count) +{ + uint32_t reg; + uint32_t msk; + uint32_t tempD; + + ENTERFN(); + DPF(D_TRN, "Wdq ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count); + + // RDPTR (1/2 MCLK, 64 PIs) + // BL0 -> B01PTRCTL0[03:00] (0x0-0xF) + // BL1 -> B01PTRCTL0[15:12] (0x0-0xF) + reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET); + msk = (byte_lane & BIT0) ? (BIT15 | BIT14 | BIT13 | BIT12) : (BIT3 | BIT2 | BIT1 | BIT0); + tempD = pi_count / HALF_CLK; + tempD <<= (byte_lane & BIT0) ? (12) : (0); + isbM32m(DDRPHY, reg, tempD, msk); + + // Adjust PI_COUNT + pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F) + // BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F) + reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0); + reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)); + msk = (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8); + tempD = pi_count << 8; + isbM32m(DDRPHY, reg, tempD, msk); + + // DEADBAND + // BL0/1 -> B01DBCTL1[06/09] (+1 select) + // BL0/1 -> B01DBCTL1[00/03] (enable) + reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET); + msk = 0x00; + tempD = 0x00; + // enable + msk |= (byte_lane & BIT0) ? (BIT3) : (BIT0); + if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) + { + tempD |= msk; + } + // select + msk |= (byte_lane & BIT0) ? (BIT9) : (BIT6); + if (pi_count < EARLY_DB) + { + tempD |= msk; + } + isbM32m(DDRPHY, reg, tempD, msk); + + // error check + if (pi_count > 0x3F) + { + training_message(channel, rank, byte_lane); + post_code(0xEE, 0xE3); + } + + LEAVEFN(); + return; +} + +// get_wdq: +// +// This function will return the amount of WDQ delay on the given channel, rank, byte_lane as an absolute PI count. +// (currently doesn't comprehend rank) +uint32_t get_wdq( + uint8_t channel, + uint8_t rank, + uint8_t byte_lane) +{ + uint32_t reg; + uint32_t tempD; + uint32_t pi_count; + + ENTERFN(); + + // RDPTR (1/2 MCLK, 64 PIs) + // BL0 -> B01PTRCTL0[03:00] (0x0-0xF) + // BL1 -> B01PTRCTL0[15:12] (0x0-0xF) + reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET); + tempD = isbR32m(DDRPHY, reg); + tempD >>= (byte_lane & BIT0) ? (12) : (0); + tempD &= 0xF; + + // Adjust PI_COUNT + pi_count = (tempD * HALF_CLK); + + // PI (1/64 MCLK, 1 PIs) + // BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F) + // BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F) + reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0); + reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)); + tempD = isbR32m(DDRPHY, reg); + tempD >>= 8; + tempD &= 0x3F; + + // Adjust PI_COUNT + pi_count += tempD; + + LEAVEFN(); + return pi_count; +} + +// set_wcmd: +// +// This function will program the WCMD delays based on an absolute number of PIs. +void set_wcmd( + uint8_t channel, + uint32_t pi_count) +{ + uint32_t reg; + uint32_t msk; + uint32_t tempD; + + ENTERFN(); + // RDPTR (1/2 MCLK, 64 PIs) + // CMDPTRREG[11:08] (0x0-0xF) + reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET); + msk = (BIT11 | BIT10 | BIT9 | BIT8); + tempD = pi_count / HALF_CLK; + tempD <<= 8; + isbM32m(DDRPHY, reg, tempD, msk); + + // Adjust PI_COUNT + pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused) + // CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused) + // CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused) + // CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused) + // CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused) + // CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F) + // CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused) + // CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused) + reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET); + + msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24) | (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16) + | (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8) | (BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0); + + tempD = (pi_count << 24) | (pi_count << 16) | (pi_count << 8) | (pi_count << 0); + + isbM32m(DDRPHY, reg, tempD, msk); + reg = CMDDLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET); // PO + isbM32m(DDRPHY, reg, tempD, msk); + + // DEADBAND + // CMDCFGREG0[17] (+1 select) + // CMDCFGREG0[16] (enable) + reg = CMDCFGREG0 + (channel * DDRIOCCC_CH_OFFSET); + msk = 0x00; + tempD = 0x00; + // enable + msk |= BIT16; + if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) + { + tempD |= msk; + } + // select + msk |= BIT17; + if (pi_count < EARLY_DB) + { + tempD |= msk; + } + isbM32m(DDRPHY, reg, tempD, msk); + + // error check + if (pi_count > 0x3F) + { + post_code(0xEE, 0xE4); + } + + LEAVEFN(); + return; +} + +// get_wcmd: +// +// This function will return the amount of WCMD delay on the given channel as an absolute PI count. +uint32_t get_wcmd( + uint8_t channel) +{ + uint32_t reg; + uint32_t tempD; + uint32_t pi_count; + + ENTERFN(); + // RDPTR (1/2 MCLK, 64 PIs) + // CMDPTRREG[11:08] (0x0-0xF) + reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET); + tempD = isbR32m(DDRPHY, reg); + tempD >>= 8; + tempD &= 0xF; + + // Adjust PI_COUNT + pi_count = tempD * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused) + // CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused) + // CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused) + // CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused) + // CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused) + // CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F) + // CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused) + // CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused) + reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET); + tempD = isbR32m(DDRPHY, reg); + tempD >>= 16; + tempD &= 0x3F; + + // Adjust PI_COUNT + pi_count += tempD; + + LEAVEFN(); + return pi_count; +} + +// set_wclk: +// +// This function will program the WCLK delays based on an absolute number of PIs. +void set_wclk( + uint8_t channel, + uint8_t rank, + uint32_t pi_count) +{ + uint32_t reg; + uint32_t msk; + uint32_t tempD; + + ENTERFN(); + // RDPTR (1/2 MCLK, 64 PIs) + // CCPTRREG[15:12] -> CLK1 (0x0-0xF) + // CCPTRREG[11:08] -> CLK0 (0x0-0xF) + reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET); + msk = (BIT15 | BIT14 | BIT13 | BIT12) | (BIT11 | BIT10 | BIT9 | BIT8); + tempD = ((pi_count / HALF_CLK) << 12) | ((pi_count / HALF_CLK) << 8); + isbM32m(DDRPHY, reg, tempD, msk); + + // Adjust PI_COUNT + pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F) + // ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F) + reg = (rank) ? (ECCB1DLLPICODER0) : (ECCB1DLLPICODER0); + reg += (channel * DDRIOCCC_CH_OFFSET); + msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16) | (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8); + tempD = (pi_count << 16) | (pi_count << 8); + isbM32m(DDRPHY, reg, tempD, msk); + reg = (rank) ? (ECCB1DLLPICODER1) : (ECCB1DLLPICODER1); + reg += (channel * DDRIOCCC_CH_OFFSET); + isbM32m(DDRPHY, reg, tempD, msk); + reg = (rank) ? (ECCB1DLLPICODER2) : (ECCB1DLLPICODER2); + reg += (channel * DDRIOCCC_CH_OFFSET); + isbM32m(DDRPHY, reg, tempD, msk); + reg = (rank) ? (ECCB1DLLPICODER3) : (ECCB1DLLPICODER3); + reg += (channel * DDRIOCCC_CH_OFFSET); + isbM32m(DDRPHY, reg, tempD, msk); + + // DEADBAND + // CCCFGREG1[11:08] (+1 select) + // CCCFGREG1[03:00] (enable) + reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET); + msk = 0x00; + tempD = 0x00; + // enable + msk |= (BIT3 | BIT2 | BIT1 | BIT0); // only ??? matters + if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) + { + tempD |= msk; + } + // select + msk |= (BIT11 | BIT10 | BIT9 | BIT8); // only ??? matters + if (pi_count < EARLY_DB) + { + tempD |= msk; + } + isbM32m(DDRPHY, reg, tempD, msk); + + // error check + if (pi_count > 0x3F) + { + post_code(0xEE, 0xE5); + } + + LEAVEFN(); + return; +} + +// get_wclk: +// +// This function will return the amout of WCLK delay on the given channel, rank as an absolute PI count. +uint32_t get_wclk( + uint8_t channel, + uint8_t rank) +{ + uint32_t reg; + uint32_t tempD; + uint32_t pi_count; + + ENTERFN(); + // RDPTR (1/2 MCLK, 64 PIs) + // CCPTRREG[15:12] -> CLK1 (0x0-0xF) + // CCPTRREG[11:08] -> CLK0 (0x0-0xF) + reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET); + tempD = isbR32m(DDRPHY, reg); + tempD >>= (rank) ? (12) : (8); + tempD &= 0xF; + + // Adjust PI_COUNT + pi_count = tempD * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F) + // ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F) + reg = (rank) ? (ECCB1DLLPICODER0) : (ECCB1DLLPICODER0); + reg += (channel * DDRIOCCC_CH_OFFSET); + tempD = isbR32m(DDRPHY, reg); + tempD >>= (rank) ? (16) : (8); + tempD &= 0x3F; + + pi_count += tempD; + + LEAVEFN(); + return pi_count; +} + +// set_wctl: +// +// This function will program the WCTL delays based on an absolute number of PIs. +// (currently doesn't comprehend rank) +void set_wctl( + uint8_t channel, + uint8_t rank, + uint32_t pi_count) +{ + uint32_t reg; + uint32_t msk; + uint32_t tempD; + + ENTERFN(); + + // RDPTR (1/2 MCLK, 64 PIs) + // CCPTRREG[31:28] (0x0-0xF) + // CCPTRREG[27:24] (0x0-0xF) + reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET); + msk = (BIT31 | BIT30 | BIT29 | BIT28) | (BIT27 | BIT26 | BIT25 | BIT24); + tempD = ((pi_count / HALF_CLK) << 28) | ((pi_count / HALF_CLK) << 24); + isbM32m(DDRPHY, reg, tempD, msk); + + // Adjust PI_COUNT + pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // ECCB1DLLPICODER?[29:24] (0x00-0x3F) + // ECCB1DLLPICODER?[29:24] (0x00-0x3F) + reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET); + msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24); + tempD = (pi_count << 24); + isbM32m(DDRPHY, reg, tempD, msk); + reg = ECCB1DLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET); + isbM32m(DDRPHY, reg, tempD, msk); + reg = ECCB1DLLPICODER2 + (channel * DDRIOCCC_CH_OFFSET); + isbM32m(DDRPHY, reg, tempD, msk); + reg = ECCB1DLLPICODER3 + (channel * DDRIOCCC_CH_OFFSET); + isbM32m(DDRPHY, reg, tempD, msk); + + // DEADBAND + // CCCFGREG1[13:12] (+1 select) + // CCCFGREG1[05:04] (enable) + reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET); + msk = 0x00; + tempD = 0x00; + // enable + msk |= (BIT5 | BIT4); // only ??? matters + if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) + { + tempD |= msk; + } + // select + msk |= (BIT13 | BIT12); // only ??? matters + if (pi_count < EARLY_DB) + { + tempD |= msk; + } + isbM32m(DDRPHY, reg, tempD, msk); + + // error check + if (pi_count > 0x3F) + { + post_code(0xEE, 0xE6); + } + + LEAVEFN(); + return; +} + +// get_wctl: +// +// This function will return the amount of WCTL delay on the given channel, rank as an absolute PI count. +// (currently doesn't comprehend rank) +uint32_t get_wctl( + uint8_t channel, + uint8_t rank) +{ + uint32_t reg; + uint32_t tempD; + uint32_t pi_count; + + ENTERFN(); + + // RDPTR (1/2 MCLK, 64 PIs) + // CCPTRREG[31:28] (0x0-0xF) + // CCPTRREG[27:24] (0x0-0xF) + reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET); + tempD = isbR32m(DDRPHY, reg); + tempD >>= 24; + tempD &= 0xF; + + // Adjust PI_COUNT + pi_count = tempD * HALF_CLK; + + // PI (1/64 MCLK, 1 PIs) + // ECCB1DLLPICODER?[29:24] (0x00-0x3F) + // ECCB1DLLPICODER?[29:24] (0x00-0x3F) + reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET); + tempD = isbR32m(DDRPHY, reg); + tempD >>= 24; + tempD &= 0x3F; + + // Adjust PI_COUNT + pi_count += tempD; + + LEAVEFN(); + return pi_count; +} + +// set_vref: +// +// This function will program the internal Vref setting in a given byte lane in a given channel. +void set_vref( + uint8_t channel, + uint8_t byte_lane, + uint32_t setting) +{ + uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL); + + ENTERFN(); + DPF(D_TRN, "Vref ch%d ln%d : val=%03X\n", channel, byte_lane, setting); + + isbM32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)), + (vref_codes[setting] << 2), (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2)); + //isbM32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)), (setting<<2), (BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)); + // need to wait ~300ns for Vref to settle (check that this is necessary) + delay_n(300); + // ??? may need to clear pointers ??? + LEAVEFN(); + return; +} + +// get_vref: +// +// This function will return the internal Vref setting for the given channel, byte_lane; +uint32_t get_vref( + uint8_t channel, + uint8_t byte_lane) +{ + uint8_t j; + uint32_t ret_val = sizeof(vref_codes) / 2; + uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL); + + uint32_t tempD; + + ENTERFN(); + tempD = isbR32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET))); + tempD >>= 2; + tempD &= 0x3F; + for (j = 0; j < sizeof(vref_codes); j++) + { + if (vref_codes[j] == tempD) + { + ret_val = j; + break; + } + } + LEAVEFN(); + return ret_val; +} + +// clear_pointers: +// +// This function will be used to clear the pointers in a given byte lane in a given channel. +void clear_pointers( + void) +{ + uint8_t channel_i; + uint8_t bl_i; + + ENTERFN(); + for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) + { + for (bl_i = 0; bl_i < NUM_BYTE_LANES; bl_i++) + { + isbM32m(DDRPHY, (B01PTRCTL1 + (channel_i * DDRIODQ_CH_OFFSET) + ((bl_i >> 1) * DDRIODQ_BL_OFFSET)), ~(BIT8), + (BIT8)); + //delay_m(1); // DEBUG + isbM32m(DDRPHY, (B01PTRCTL1 + (channel_i * DDRIODQ_CH_OFFSET) + ((bl_i >> 1) * DDRIODQ_BL_OFFSET)), (BIT8), + (BIT8)); + } + } + LEAVEFN(); + return; +} + +// void enable_cache: +void enable_cache( + void) +{ + // Cache control not used in Quark MRC + return; +} + +// void disable_cache: +void disable_cache( + void) +{ + // Cache control not used in Quark MRC + return; +} + +// Send DRAM command, data should be formated +// using DCMD_Xxxx macro or emrsXCommand structure. +static void dram_init_command( + uint32_t data) +{ + Wr32(DCMD, 0, data); +} + +// find_rising_edge: +// +// This function will find the rising edge transition on RCVN or WDQS. +void find_rising_edge( + MRCParams_t *mrc_params, + uint32_t delay[], + uint8_t channel, + uint8_t rank, + bool rcvn) +{ + +#define SAMPLE_CNT 3 // number of sample points +#define SAMPLE_DLY 26 // number of PIs to increment per sample +#define FORWARD true // indicates to increase delays when looking for edge +#define BACKWARD false // indicates to decrease delays when looking for edge + + bool all_edges_found; // determines stop condition + bool direction[NUM_BYTE_LANES]; // direction indicator + uint8_t sample_i; // sample counter + uint8_t bl_i; // byte lane counter + uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor + uint32_t sample_result[SAMPLE_CNT]; // results of "sample_dqs()" + uint32_t tempD; // temporary DWORD + uint32_t transition_pattern; + + ENTERFN(); + + // select hte and request initial configuration + select_hte(mrc_params); + first_run = 1; + + // Take 3 sample points (T1,T2,T3) to obtain a transition pattern. + for (sample_i = 0; sample_i < SAMPLE_CNT; sample_i++) + { + // program the desired delays for sample + for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) + { + // increase sample delay by 26 PI (0.2 CLK) + if (rcvn) + { + set_rcvn(channel, rank, bl_i, delay[bl_i] + (sample_i * SAMPLE_DLY)); + } + else + { + set_wdqs(channel, rank, bl_i, delay[bl_i] + (sample_i * SAMPLE_DLY)); + } + } // bl_i loop + // take samples (Tsample_i) + sample_result[sample_i] = sample_dqs(mrc_params, channel, rank, rcvn); + + DPF(D_TRN, "Find rising edge %s ch%d rnk%d: #%d dly=%d dqs=%02X\n", + (rcvn ? "RCVN" : "WDQS"), channel, rank, + sample_i, sample_i * SAMPLE_DLY, sample_result[sample_i]); + + } // sample_i loop + + // This pattern will help determine where we landed and ultimately how to place RCVEN/WDQS. + for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) + { + // build "transition_pattern" (MSB is 1st sample) + transition_pattern = 0x00; + for (sample_i = 0; sample_i < SAMPLE_CNT; sample_i++) + { + transition_pattern |= ((sample_result[sample_i] & (1 << bl_i)) >> bl_i) << (SAMPLE_CNT - 1 - sample_i); + } // sample_i loop + + DPF(D_TRN, "=== transition pattern %d\n", transition_pattern); + + // set up to look for rising edge based on "transition_pattern" + switch (transition_pattern) + { + case 0x00: // sampled 0->0->0 + // move forward from T3 looking for 0->1 + delay[bl_i] += 2 * SAMPLE_DLY; + direction[bl_i] = FORWARD; + break; + case 0x01: // sampled 0->0->1 + case 0x05: // sampled 1->0->1 (bad duty cycle) *HSD#237503* + // move forward from T2 looking for 0->1 + delay[bl_i] += 1 * SAMPLE_DLY; + direction[bl_i] = FORWARD; + break; +// HSD#237503 +// case 0x02: // sampled 0->1->0 (bad duty cycle) +// training_message(channel, rank, bl_i); +// post_code(0xEE, 0xE8); +// break; + case 0x02: // sampled 0->1->0 (bad duty cycle) *HSD#237503* + case 0x03: // sampled 0->1->1 + // move forward from T1 looking for 0->1 + delay[bl_i] += 0 * SAMPLE_DLY; + direction[bl_i] = FORWARD; + break; + case 0x04: // sampled 1->0->0 (assumes BL8, HSD#234975) + // move forward from T3 looking for 0->1 + delay[bl_i] += 2 * SAMPLE_DLY; + direction[bl_i] = FORWARD; + break; +// HSD#237503 +// case 0x05: // sampled 1->0->1 (bad duty cycle) +// training_message(channel, rank, bl_i); +// post_code(0xEE, 0xE9); +// break; + case 0x06: // sampled 1->1->0 + case 0x07: // sampled 1->1->1 + // move backward from T1 looking for 1->0 + delay[bl_i] += 0 * SAMPLE_DLY; + direction[bl_i] = BACKWARD; + break; + default: + post_code(0xEE, 0xEE); + break; + } // transition_pattern switch + // program delays + if (rcvn) + { + set_rcvn(channel, rank, bl_i, delay[bl_i]); + } + else + { + set_wdqs(channel, rank, bl_i, delay[bl_i]); + } + } // bl_i loop + + // Based on the observed transition pattern on the byte lane, + // begin looking for a rising edge with single PI granularity. + do + { + all_edges_found = true; // assume all byte lanes passed + tempD = sample_dqs(mrc_params, channel, rank, rcvn); // take a sample + // check all each byte lane for proper edge + for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) + { + if (tempD & (1 << bl_i)) + { + // sampled "1" + if (direction[bl_i] == BACKWARD) + { + // keep looking for edge on this byte lane + all_edges_found = false; + delay[bl_i] -= 1; + if (rcvn) + { + set_rcvn(channel, rank, bl_i, delay[bl_i]); + } + else + { + set_wdqs(channel, rank, bl_i, delay[bl_i]); + } + } + } + else + { + // sampled "0" + if (direction[bl_i] == FORWARD) + { + // keep looking for edge on this byte lane + all_edges_found = false; + delay[bl_i] += 1; + if (rcvn) + { + set_rcvn(channel, rank, bl_i, delay[bl_i]); + } + else + { + set_wdqs(channel, rank, bl_i, delay[bl_i]); + } + } + } + } // bl_i loop + } while (!all_edges_found); + + // restore DDR idle state + dram_init_command(DCMD_PREA(rank)); + + DPF(D_TRN, "Delay %03X %03X %03X %03X\n", + delay[0], delay[1], delay[2], delay[3]); + + LEAVEFN(); + return; +} + +// sample_dqs: +// +// This function will sample the DQTRAINSTS registers in the given channel/rank SAMPLE_SIZE times looking for a valid '0' or '1'. +// It will return an encoded DWORD in which each bit corresponds to the sampled value on the byte lane. +uint32_t sample_dqs( + MRCParams_t *mrc_params, + uint8_t channel, + uint8_t rank, + bool rcvn) +{ + uint8_t j; // just a counter + uint8_t bl_i; // which BL in the module (always 2 per module) + uint8_t bl_grp; // which BL module + uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor + uint32_t msk[2]; // BLx in module + uint32_t sampled_val[SAMPLE_SIZE]; // DQTRAINSTS register contents for each sample + uint32_t num_0s; // tracks the number of '0' samples + uint32_t num_1s; // tracks the number of '1' samples + uint32_t ret_val = 0x00; // assume all '0' samples + uint32_t address = get_addr(mrc_params, channel, rank); + + // initialise "msk[]" + msk[0] = (rcvn) ? (BIT1) : (BIT9); // BL0 + msk[1] = (rcvn) ? (BIT0) : (BIT8); // BL1 + + + // cycle through each byte lane group + for (bl_grp = 0; bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2; bl_grp++) + { + // take SAMPLE_SIZE samples + for (j = 0; j < SAMPLE_SIZE; j++) + { + HteMemOp(address, first_run, rcvn?0:1); + first_run = 0; + + // record the contents of the proper DQTRAINSTS register + sampled_val[j] = isbR32m(DDRPHY, (DQTRAINSTS + (bl_grp * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET))); + } + // look for a majority value ( (SAMPLE_SIZE/2)+1 ) on the byte lane + // and set that value in the corresponding "ret_val" bit + for (bl_i = 0; bl_i < 2; bl_i++) + { + num_0s = 0x00; // reset '0' tracker for byte lane + num_1s = 0x00; // reset '1' tracker for byte lane + for (j = 0; j < SAMPLE_SIZE; j++) + { + if (sampled_val[j] & msk[bl_i]) + { + num_1s++; + } + else + { + num_0s++; + } + } + if (num_1s > num_0s) + { + ret_val |= (1 << (bl_i + (bl_grp * 2))); + } + } + } + + // "ret_val.0" contains the status of BL0 + // "ret_val.1" contains the status of BL1 + // "ret_val.2" contains the status of BL2 + // etc. + return ret_val; +} + +// get_addr: +// +// This function will return a 32 bit address in the desired channel and rank. +uint32_t get_addr( + MRCParams_t *mrc_params, + uint8_t channel, + uint8_t rank) +{ + uint32_t offset = 0x02000000; // 32MB + + // Begin product specific code + if (channel > 0) + { + DPF(D_ERROR, "ILLEGAL CHANNEL\n"); + DEAD_LOOP(); + } + + if (rank > 1) + { + DPF(D_ERROR, "ILLEGAL RANK\n"); + DEAD_LOOP(); + } + + // use 256MB lowest density as per DRP == 0x0003 + offset += rank * (256 * 1024 * 1024); + + return offset; +} + +// byte_lane_mask: +// +// This function will return a 32 bit mask that will be used to check for byte lane failures. +uint32_t byte_lane_mask( + MRCParams_t *mrc_params) +{ + uint32_t j; + uint32_t ret_val = 0x00; + + // set "ret_val" based on NUM_BYTE_LANES such that you will check only BL0 in "result" + // (each bit in "result" represents a byte lane) + for (j = 0; j < MAX_BYTE_LANES; j += NUM_BYTE_LANES) + { + ret_val |= (1 << ((j / NUM_BYTE_LANES) * NUM_BYTE_LANES)); + } + + // HSD#235037 + // need to adjust the mask for 16-bit mode + if (mrc_params->channel_width == x16) + { + ret_val |= (ret_val << 2); + } + + return ret_val; +} + + +// read_tsc: +// +// This function will do some assembly to return TSC register contents as a uint64_t. +uint64_t read_tsc( + void) +{ + volatile uint64_t tsc; // EDX:EAX + +#if defined (SIM) || defined (GCC) + volatile uint32_t tscH; // EDX + volatile uint32_t tscL;// EAX + + asm("rdtsc":"=a"(tscL),"=d"(tscH)); + tsc = tscH; + tsc = (tsc<<32)|tscL; +#else + tsc = __rdtsc(); +#endif + + return tsc; +} + +// get_tsc_freq: +// +// This function returns the TSC frequency in MHz +uint32_t get_tsc_freq( + void) +{ + static uint32_t freq[] = + { 533, 400, 200, 100 }; + uint32_t fuse; +#if 0 + fuse = (isbR32m(FUSE, 0) >> 12) & (BIT1|BIT0); +#else + // todo!!! Fixed 533MHz for emulation or debugging + fuse = 0; +#endif + return freq[fuse]; +} + +#ifndef SIM +// delay_n: +// +// This is a simple delay function. +// It takes "nanoseconds" as a parameter. +void delay_n( + uint32_t nanoseconds) +{ + // 1000 MHz clock has 1ns period --> no conversion required + uint64_t final_tsc = read_tsc(); + final_tsc += ((get_tsc_freq() * (nanoseconds)) / 1000); + + while (read_tsc() < final_tsc) + ; + return; +} +#endif + +// delay_u: +// +// This is a simple delay function. +// It takes "microseconds as a parameter. +void delay_u( + uint32_t microseconds) +{ + // 64 bit math is not an option, just use loops + while (microseconds--) + { + delay_n(1000); + } + return; +} + +// delay_m: +// +// This is a simple delay function. +// It takes "milliseconds" as a parameter. +void delay_m( + uint32_t milliseconds) +{ + // 64 bit math is not an option, just use loops + while (milliseconds--) + { + delay_u(1000); + } + return; +} + +// delay_s: +// +// This is a simple delay function. +// It takes "seconds" as a parameter. +void delay_s( + uint32_t seconds) +{ + // 64 bit math is not an option, just use loops + while (seconds--) + { + delay_m(1000); + } + return; +} + +// post_code: +// +// This function will output the POST CODE to the four 7-Segment LED displays. +void post_code( + uint8_t major, + uint8_t minor) +{ +#ifdef EMU + // Update global variable for execution tracking in debug env + PostCode = ((major << 8) | minor); +#endif + + // send message to UART + DPF(D_INFO, "POST: 0x%01X%02X\n", major, minor); + + // error check: + if (major == 0xEE) + { + // todo!!! Consider updating error status and exit MRC +#ifdef SIM + // enable Ctrl-C handling + for(;;) delay_n(100); +#else + DEAD_LOOP(); +#endif + } +} + +void training_message( + uint8_t channel, + uint8_t rank, + uint8_t byte_lane) +{ + // send message to UART + DPF(D_INFO, "CH%01X RK%01X BL%01X\n", channel, rank, byte_lane); + return; +} + +void print_timings( + MRCParams_t *mrc_params) +{ + uint8_t algo_i; + uint8_t channel_i; + uint8_t rank_i; + uint8_t bl_i; + uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; + + DPF(D_INFO, "\n---------------------------"); + DPF(D_INFO, "\nALGO[CH:RK] BL0 BL1 BL2 BL3"); + DPF(D_INFO, "\n==========================="); + for (algo_i = 0; algo_i < eMAX_ALGOS; algo_i++) + { + for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) + { + if (mrc_params->channel_enables & (1 << channel_i)) + { + for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) + { + if (mrc_params->rank_enables & (1 << rank_i)) + { + switch (algo_i) + { + case eRCVN: + DPF(D_INFO, "\nRCVN[%02d:%02d]", channel_i, rank_i); + break; + case eWDQS: + DPF(D_INFO, "\nWDQS[%02d:%02d]", channel_i, rank_i); + break; + case eWDQx: + DPF(D_INFO, "\nWDQx[%02d:%02d]", channel_i, rank_i); + break; + case eRDQS: + DPF(D_INFO, "\nRDQS[%02d:%02d]", channel_i, rank_i); + break; + case eVREF: + DPF(D_INFO, "\nVREF[%02d:%02d]", channel_i, rank_i); + break; + case eWCMD: + DPF(D_INFO, "\nWCMD[%02d:%02d]", channel_i, rank_i); + break; + case eWCTL: + DPF(D_INFO, "\nWCTL[%02d:%02d]", channel_i, rank_i); + break; + case eWCLK: + DPF(D_INFO, "\nWCLK[%02d:%02d]", channel_i, rank_i); + break; + default: + break; + } // algo_i switch + for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) + { + switch (algo_i) + { + case eRCVN: + DPF(D_INFO, " %03d", get_rcvn(channel_i, rank_i, bl_i)); + break; + case eWDQS: + DPF(D_INFO, " %03d", get_wdqs(channel_i, rank_i, bl_i)); + break; + case eWDQx: + DPF(D_INFO, " %03d", get_wdq(channel_i, rank_i, bl_i)); + break; + case eRDQS: + DPF(D_INFO, " %03d", get_rdqs(channel_i, rank_i, bl_i)); + break; + case eVREF: + DPF(D_INFO, " %03d", get_vref(channel_i, bl_i)); + break; + case eWCMD: + DPF(D_INFO, " %03d", get_wcmd(channel_i)); + break; + case eWCTL: + DPF(D_INFO, " %03d", get_wctl(channel_i, rank_i)); + break; + case eWCLK: + DPF(D_INFO, " %03d", get_wclk(channel_i, rank_i)); + break; + default: + break; + } // algo_i switch + } // bl_i loop + } // if rank_i enabled + } // rank_i loop + } // if channel_i enabled + } // channel_i loop + } // algo_i loop + DPF(D_INFO, "\n---------------------------"); + DPF(D_INFO, "\n"); + return; +} + +// 32 bit LFSR with characteristic polynomial: X^32 + X^22 +X^2 + X^1 +// The function takes pointer to previous 32 bit value and modifies it to next value. +void lfsr32( + uint32_t *lfsr_ptr) +{ + uint32_t bit; + uint32_t lfsr; + uint32_t i; + + lfsr = *lfsr_ptr; + + for (i = 0; i < 32; i++) + { + bit = 1 ^ (lfsr & BIT0); + bit = bit ^ ((lfsr & BIT1) >> 1); + bit = bit ^ ((lfsr & BIT2) >> 2); + bit = bit ^ ((lfsr & BIT22) >> 22); + + lfsr = ((lfsr >> 1) | (bit << 31)); + } + + *lfsr_ptr = lfsr; + return; +} + +// The purpose of this function is to ensure the SEC comes out of reset +// and IA initiates the SEC enabling Memory Scrambling. +void enable_scrambling( + MRCParams_t *mrc_params) +{ + uint32_t lfsr = 0; + uint8_t i; + + if (mrc_params->scrambling_enables == 0) + return; + + ENTERFN(); + + // 32 bit seed is always stored in BIOS NVM. + lfsr = mrc_params->timings.scrambler_seed; + + if (mrc_params->boot_mode == bmCold) + { + // factory value is 0 and in first boot, a clock based seed is loaded. + if (lfsr == 0) + { + lfsr = read_tsc() & 0x0FFFFFFF; // get seed from system clock and make sure it is not all 1's + } + // need to replace scrambler + // get next 32bit LFSR 16 times which is the last part of the previous scrambler vector. + else + { + for (i = 0; i < 16; i++) + { + lfsr32(&lfsr); + } + } + mrc_params->timings.scrambler_seed = lfsr; // save new seed. + } // if (cold_boot) + + // In warm boot or S3 exit, we have the previous seed. + // In cold boot, we have the last 32bit LFSR which is the new seed. + lfsr32(&lfsr); // shift to next value + isbW32m(MCU, SCRMSEED, (lfsr & 0x0003FFFF)); + for (i = 0; i < 2; i++) + { + isbW32m(MCU, SCRMLO + i, (lfsr & 0xAAAAAAAA)); + } + + LEAVEFN(); + return; +} + +// This function will store relevant timing data +// This data will be used on subsequent boots to speed up boot times +// and is required for Suspend To RAM capabilities. +void store_timings( + MRCParams_t *mrc_params) +{ + uint8_t ch, rk, bl; + MrcTimings_t *mt = &mrc_params->timings; + + for (ch = 0; ch < NUM_CHANNELS; ch++) + { + for (rk = 0; rk < NUM_RANKS; rk++) + { + for (bl = 0; bl < NUM_BYTE_LANES; bl++) + { + mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl); // RCVN + mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl); // RDQS + mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl); // WDQS + mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl); // WDQ + if (rk == 0) + { + mt->vref[ch][bl] = get_vref(ch, bl); // VREF (RANK0 only) + } + } + mt->wctl[ch][rk] = get_wctl(ch, rk); // WCTL + } + mt->wcmd[ch] = get_wcmd(ch); // WCMD + } + + // need to save for a case of changing frequency after warm reset + mt->ddr_speed = mrc_params->ddr_speed; + + return; +} + +// This function will retrieve relevant timing data +// This data will be used on subsequent boots to speed up boot times +// and is required for Suspend To RAM capabilities. +void restore_timings( + MRCParams_t *mrc_params) +{ + uint8_t ch, rk, bl; + const MrcTimings_t *mt = &mrc_params->timings; + + for (ch = 0; ch < NUM_CHANNELS; ch++) + { + for (rk = 0; rk < NUM_RANKS; rk++) + { + for (bl = 0; bl < NUM_BYTE_LANES; bl++) + { + set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]); // RCVN + set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]); // RDQS + set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]); // WDQS + set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]); // WDQ + if (rk == 0) + { + set_vref(ch, bl, mt->vref[ch][bl]); // VREF (RANK0 only) + } + } + set_wctl(ch, rk, mt->wctl[ch][rk]); // WCTL + } + set_wcmd(ch, mt->wcmd[ch]); // WCMD + } + + return; +} + +// Configure default settings normally set as part of read training +// Some defaults have to be set earlier as they may affect earlier +// training steps. +void default_timings( + MRCParams_t *mrc_params) +{ + uint8_t ch, rk, bl; + + for (ch = 0; ch < NUM_CHANNELS; ch++) + { + for (rk = 0; rk < NUM_RANKS; rk++) + { + for (bl = 0; bl < NUM_BYTE_LANES; bl++) + { + set_rdqs(ch, rk, bl, 24); // RDQS + if (rk == 0) + { + set_vref(ch, bl, 32); // VREF (RANK0 only) + } + } + } + } + + return; +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h new file mode 100644 index 0000000000..af7b8c8951 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h @@ -0,0 +1,95 @@ +/************************************************************************ + * + * Copyright (c) 2013-2017 Intel Corporation. + * +* SPDX-License-Identifier: BSD-2-Clause-Patent + * + ***************************************************************************/ +#ifndef _MEMINIT_UTILS_H_ +#define _MEMINIT_UTILS_H_ + +// General Definitions: +#ifdef QUICKSIM +#define SAMPLE_SIZE 4 // reduce number of training samples in simulation env +#else +#define SAMPLE_SIZE 6 // must be odd number +#endif + +#define EARLY_DB (0x12) // must be less than this number to enable early deadband +#define LATE_DB (0x34) // must be greater than this number to enable late deadband +#define CHX_REGS (11*4) +#define FULL_CLK 128 +#define HALF_CLK 64 +#define QRTR_CLK 32 + + + +#define MCEIL(num,den) ((uint8_t)((num+den-1)/den)) +#define MMAX(a,b) ((((int32_t)(a))>((int32_t)(b)))?(a):(b)) +#define MCOUNT(a) (sizeof(a)/sizeof(*a)) + +typedef enum ALGOS_enum { + eRCVN = 0, + eWDQS, + eWDQx, + eRDQS, + eVREF, + eWCMD, + eWCTL, + eWCLK, + eMAX_ALGOS, +} ALGOs_t; + + +// Prototypes: +void set_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count); +void set_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count); +void set_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count); +void set_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count); +void set_wcmd(uint8_t channel, uint32_t pi_count); +void set_wclk(uint8_t channel, uint8_t grp, uint32_t pi_count); +void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count); +void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting); +uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane); +uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane); +uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane); +uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane); +uint32_t get_wcmd(uint8_t channel); +uint32_t get_wclk(uint8_t channel, uint8_t group); +uint32_t get_wctl(uint8_t channel, uint8_t rank); +uint32_t get_vref(uint8_t channel, uint8_t byte_lane); + +void clear_pointers(void); +void enable_cache(void); +void disable_cache(void); +void find_rising_edge(MRCParams_t *mrc_params, uint32_t delay[], uint8_t channel, uint8_t rank, bool rcvn); +uint32_t sample_dqs(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank, bool rcvn); +uint32_t get_addr(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank); +uint32_t byte_lane_mask(MRCParams_t *mrc_params); + +uint64_t read_tsc(void); +uint32_t get_tsc_freq(void); +void delay_n(uint32_t nanoseconds); +void delay_u(uint32_t microseconds); +void delay_m(uint32_t milliseconds); +void delay_s(uint32_t seconds); + +void post_code(uint8_t major, uint8_t minor); +void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane); +void print_timings(MRCParams_t *mrc_params); + +void enable_scrambling(MRCParams_t *mrc_params); +void store_timings(MRCParams_t *mrc_params); +void restore_timings(MRCParams_t *mrc_params); +void default_timings(MRCParams_t *mrc_params); + +#ifndef SIM +// +// Map memset() and memcpy() to BaseMemoryLib functions +// +#include +#define memset(d,c,n) ((c) == 0) ? ZeroMem ((d), (n)) : SetMem ((d), (n), (c)) +#define memcpy(d,s,n) CopyMem ((d), (s), (n)) +#endif + +#endif // _MEMINIT_UTILS_H_ diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h new file mode 100644 index 0000000000..b96d06908e --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h @@ -0,0 +1,77 @@ +/** @file +Common definitions and compilation switches for MRC + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef __MEMORY_OPTIONS_H +#define __MEMORY_OPTIONS_H + +#include "core_types.h" + +// MRC COMPILE TIME SWITCHES: +// ========================== + + + +//#define MRC_SV // enable some validation opitons + +#if defined (SIM) || defined(EMU) +#define QUICKSIM // reduce execution time using shorter rd/wr sequences +#endif + +#define CLT // required for Quark project + + + +//#define BACKUP_RCVN // enable STATIC timing settings for RCVN (BACKUP_MODE) +//#define BACKUP_WDQS // enable STATIC timing settings for WDQS (BACKUP_MODE) +//#define BACKUP_RDQS // enable STATIC timing settings for RDQS (BACKUP_MODE) +//#define BACKUP_WDQ // enable STATIC timing settings for WDQ (BACKUP_MODE) + + + +//#define BACKUP_COMPS // enable *COMP overrides (BACKUP_MODE) +//#define RX_EYE_CHECK // enable the RD_TRAIN eye check +#define HMC_TEST // enable Host to Memory Clock Alignment +#define R2R_SHARING // enable multi-rank support via rank2rank sharing + +#define FORCE_16BIT_DDRIO // disable signals not used in 16bit mode of DDRIO + + + +// +// Debug support +// + +#ifdef NDEBUG +#define DPF if(0) dpf +#else +#define DPF dpf +#endif + +void dpf( uint32_t mask, char_t *bla, ...); + + +uint8_t mgetc(void); +uint8_t mgetch(void); + + +// Debug print type +#define D_ERROR 0x0001 +#define D_INFO 0x0002 +#define D_REGRD 0x0004 +#define D_REGWR 0x0008 +#define D_FCALL 0x0010 +#define D_TRN 0x0020 +#define D_TIME 0x0040 + +#define ENTERFN() DPF(D_FCALL, "<%s>\n", __FUNCTION__) +#define LEAVEFN() DPF(D_FCALL, "\n", __FUNCTION__) +#define REPORTFN() DPF(D_FCALL, "<%s/>\n", __FUNCTION__) + +extern uint32_t DpfPrintMask; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c new file mode 100644 index 0000000000..f9b0e7050d --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c @@ -0,0 +1,40 @@ +/************************************************************************ + * + * Copyright (c) 2013-2015 Intel Corporation. + * +* SPDX-License-Identifier: BSD-2-Clause-Patent + * + ************************************************************************/ +#include "mrc.h" +#include "memory_options.h" + +#include "meminit.h" +#include "meminit_utils.h" +#include "prememinit.h" +#include "io.h" + +// Base address for UART registers +extern uint32_t UartMmioBase; + +// +// Memory Reference Code entry point when executing from BIOS +// +void Mrc( MRCParams_t *mrc_params) +{ + // configure uart base address assuming code relocated to eSRAM + UartMmioBase = mrc_params->uart_mmio_base; + + ENTERFN(); + + DPF(D_INFO, "MRC Version %04X %s %s\n", MRC_VERSION, __DATE__, __TIME__); + + // this will set up the data structures used by MemInit() + PreMemInit(mrc_params); + + // this will initialize system memory + MemInit(mrc_params); + + LEAVEFN(); + return; +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h new file mode 100644 index 0000000000..dfcfe58a9d --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h @@ -0,0 +1,160 @@ +/************************************************************************ + * + * Copyright (c) 2013-2015 Intel Corporation. + * +* SPDX-License-Identifier: BSD-2-Clause-Patent + * + ************************************************************************/ +#ifndef _MRC_H_ +#define _MRC_H_ + +#include "core_types.h" + +// define the MRC Version +#define MRC_VERSION 0x0112 + + +// architectural definitions +#define NUM_CHANNELS 1 // number of channels +#define NUM_RANKS 2 // number of ranks per channel +#define NUM_BYTE_LANES 4 // number of byte lanes per channel + +// software limitations +#define MAX_CHANNELS 1 +#define MAX_RANKS 2 +#define MAX_BYTE_LANES 4 + +// only to mock MrcWrapper +#define MAX_SOCKETS 1 +#define MAX_SIDES 1 +#define MAX_ROWS (MAX_SIDES * MAX_SOCKETS) +// end + + +// Specify DRAM of nenory channel width +enum { + x8, // DRAM width + x16, // DRAM width & Channel Width + x32 // Channel Width +}; + +// Specify DRAM speed +enum { + DDRFREQ_800, + DDRFREQ_1066 +}; + +// Specify DRAM type +enum { + DDR3, + DDR3L +}; + +// Delay configuration for individual signals +// Vref setting +// Scrambler seed +typedef struct MrcTimings_s +{ + uint32_t rcvn[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; + uint32_t rdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; + uint32_t wdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; + uint32_t wdq [NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; + uint32_t vref[NUM_CHANNELS][NUM_BYTE_LANES]; + uint32_t wctl[NUM_CHANNELS][NUM_RANKS]; + uint32_t wcmd[NUM_CHANNELS]; + + uint32_t scrambler_seed; + uint8_t ddr_speed; // need to save for the case of frequency change +} MrcTimings_t; + + +// DENSITY: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb +// tCL is DRAM CAS Latency in clocks. +// All other timings are in picoseconds. +// Refer to JEDEC spec (or DRAM datasheet) when changing these values. +typedef struct DRAMParams_s { + uint8_t DENSITY; + uint8_t tCL; // CAS latency in clocks + uint32_t tRAS; // ACT to PRE command period + uint32_t tWTR; // Delay from start of internal write transaction to internal read command + uint32_t tRRD; // ACT to ACT command period (JESD79 specific to page size 1K/2K) + uint32_t tFAW; // Four activate window (JESD79 specific to page size 1K/2K) +} DRAMParams_t; + + +// Boot mode defined as bit mask (1<boot_mode); + DPF(D_INFO, "- r - rank enable [%d]\n", mrc_params->rank_enables); + DPF(D_INFO, "- e - ecc switch [%d]\n", mrc_params->ecc_enables); + DPF(D_INFO, "- b - scrambling switch [%d]\n", mrc_params->scrambling_enables); + DPF(D_INFO, "- a - adr mode [%d]\n", mrc_params->address_mode); + DPF(D_INFO, "- m - menu after mrc [%d]\n", mrc_params->menu_after_mrc); + DPF(D_INFO, "- t - tune to rcvn [%d]\n", mrc_params->tune_rcvn); + DPF(D_INFO, "- o - odt switch [%d]\n", mrc_params->rd_odt_value); + DPF(D_INFO, "- d - dram density [%d]\n", mrc_params->params.DENSITY); + DPF(D_INFO, "- p - power down disable [%d]\n", mrc_params->power_down_disable); + DPF(D_INFO, "- l - log switch 0x%x\n", DpfPrintMask); + ch = mgetc(); + + switch (ch) + { + case 'f': + mrc_params->boot_mode >>= 1; + if(mrc_params->boot_mode == bmUnknown) + { + mrc_params->boot_mode = bmWarm; + } + DPF(D_INFO, "Boot mode %d\n", mrc_params->boot_mode); + break; + + case 'p': + mrc_params->power_down_disable ^= 1; + DPF(D_INFO, "Power down disable %d\n", mrc_params->power_down_disable); + break; + + case 'r': + mrc_params->rank_enables ^= 2; + DPF(D_INFO, "Rank enable %d\n", mrc_params->rank_enables); + break; + + case 'e': + mrc_params->ecc_enables ^= 1; + DPF(D_INFO, "Ecc enable %d\n", mrc_params->ecc_enables); + break; + + case 'b': + mrc_params->scrambling_enables ^= 1; + DPF(D_INFO, "Scrambler enable %d\n", mrc_params->scrambling_enables); + break; + + case 'a': + mrc_params->address_mode = (mrc_params->address_mode + 1) % 3; + DPF(D_INFO, "Adr mode %d\n", mrc_params->address_mode); + break; + + case 'm': + mrc_params->menu_after_mrc ^= 1; + DPF(D_INFO, "Menu after mrc %d\n", mrc_params->menu_after_mrc); + break; + + case 't': + mrc_params->tune_rcvn ^= 1; + DPF(D_INFO, "Tune to rcvn %d\n", mrc_params->tune_rcvn); + break; + + case 'o': + mrc_params->rd_odt_value = (mrc_params->rd_odt_value + 1) % 4; + DPF(D_INFO, "Rd_odt_value %d\n", mrc_params->rd_odt_value); + break; + + case 'd': + mrc_params->params.DENSITY = (mrc_params->params.DENSITY + 1) % 4; + DPF(D_INFO, "Dram density %d\n", mrc_params->params.DENSITY); + break; + + case 'l': + DpfPrintMask ^= 0x30; + DPF(D_INFO, "Log mask %x\n", DpfPrintMask); + break; + + default: + break; + } + + if (ch != 'c') + goto myloop; + + } +#endif + + // initially expect success + mrc_params->status = MRC_SUCCESS; + + // todo!!! Setup board layout (must be reviewed as is selecting static timings) + // 0 == R0 (DDR3 x16), 1 == R1 (DDR3 x16), 2 == DV (DDR3 x8), 3 == SV (DDR3 x8) + if (mrc_params->dram_width == x8) + { + mrc_params->board_id = 2; // select x8 layout + } + else + { + mrc_params->board_id = 0; // select x16 layout + } + + // initially no memory + mrc_params->mem_size = 0; + channel_i = 0; + + // begin of channel settings + dram_width = mrc_params->dram_width; + dram_params = &mrc_params->params; + dram_cfg_index = 0; + + // Determine Column & Row Bits: + // Column: + // 11 for 8Gbx8, else 10 + mrc_params->column_bits[channel_i] = ((dram_params[dram_cfg_index].DENSITY == 4) && (dram_width == x8)) ? (11) : (10); + + // Row: + // 512Mbx16=12 512Mbx8=13 + // 1Gbx16=13 1Gbx8=14 + // 2Gbx16=14 2Gbx8=15 + // 4Gbx16=15 4Gbx8=16 + // 8Gbx16=16 8Gbx8=16 + mrc_params->row_bits[channel_i] = 12 + (dram_params[dram_cfg_index].DENSITY) + + (((dram_params[dram_cfg_index].DENSITY < 4) && (dram_width == x8)) ? (1) : (0)); + + // Determine Per Channel Memory Size: + // (For 2 RANKs, multiply by 2) + // (For 16 bit data bus, divide by 2) + // DENSITY WIDTH MEM_AVAILABLE + // 512Mb x16 0x008000000 ( 128MB) + // 512Mb x8 0x010000000 ( 256MB) + // 1Gb x16 0x010000000 ( 256MB) + // 1Gb x8 0x020000000 ( 512MB) + // 2Gb x16 0x020000000 ( 512MB) + // 2Gb x8 0x040000000 (1024MB) + // 4Gb x16 0x040000000 (1024MB) + // 4Gb x8 0x080000000 (2048MB) + mrc_params->channel_size[channel_i] = (1 << dram_params[dram_cfg_index].DENSITY); + mrc_params->channel_size[channel_i] *= ((dram_width == x8) ? (2) : (1)); + mrc_params->channel_size[channel_i] *= (mrc_params->rank_enables == 0x3) ? (2) : (1); + mrc_params->channel_size[channel_i] *= (mrc_params->channel_width == x16) ? (1) : (2); + + // Determine memory size (convert number of 64MB/512Mb units) + mrc_params->mem_size += mrc_params->channel_size[channel_i] << 26; + + // end of channel settings + + LEAVEFN(); + return; +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h new file mode 100644 index 0000000000..13853fdaa2 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h @@ -0,0 +1,15 @@ +/************************************************************************ + * + * Copyright (c) 2013-2015 Intel Corporation. + * +* SPDX-License-Identifier: BSD-2-Clause-Patent + * + ************************************************************************/ +#ifndef __PREMEMINIT_H_ +#define __PREMEMINIT_H_ + +// Function prototypes +void PreMemInit(MRCParams_t *mrc_params); + + +#endif // _PREMEMINIT_H_ diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h new file mode 100644 index 0000000000..20bea9277a --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/CommonHeader.h @@ -0,0 +1,49 @@ +/** @file +Common header file shared by all source files. + +This file includes package header files, library classes and protocol, PPI & GUID definitions. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef __COMMON_HEADER_H_ +#define __COMMON_HEADER_H_ + +// +// The package level header files this module uses +// +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c new file mode 100644 index 0000000000..2731bfe136 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.c @@ -0,0 +1,612 @@ +/** @file +Implementation for SMBus DXE driver entry point and SMBus Host +Controller protocol. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "CommonHeader.h" + +#include "DxeQNCSmbus.h" + +// +// Interface defintion of SMBUS Host Controller Protocol. +// +EFI_SMBUS_HC_PROTOCOL mSmbusHc = { + SmbusExecute, + SmbusArpDevice, + SmbusGetArpMap, + SmbusNotify +}; + +// +// Handle to install SMBus Host Controller protocol. +// +EFI_HANDLE mSmbusHcHandle = NULL; +UINT8 mDeviceMapEntries = 0; +EFI_SMBUS_DEVICE_MAP mDeviceMap[MAX_SMBUS_DEVICES]; +UINT8 mPlatformNumRsvd = 0; +UINT8 *mPlatformAddrRsvd = NULL; + +// +// These addresses are reserved by the SMBus 2.0 specification +// +UINT8 mReservedAddress[SMBUS_NUM_RESERVED] = { + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x18, 0x50, 0x6E, 0xC2, + 0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE +}; + + +/** + Gets Io port base address of Smbus Host Controller. + + This internal function depends on a feature flag named PcdIchSmbusFixedIoPortBaseAddress + to retrieve Smbus Io port base. If that feature flag is true, it will get Smbus Io port base + address from a preset Pcd entry named PcdIchSmbusIoPortBaseAddress; otherwise, it will always + read Pci configuration space to get that value in each Smbus bus transaction. + + @return The Io port base address of Smbus host controller. + +**/ +UINTN +GetSmbusIoPortBaseAddress ( + VOID + ) +{ + UINTN IoPortBaseAddress; + + if (FeaturePcdGet (PcdSmbaIoBaseAddressFixed)) { + IoPortBaseAddress = (UINTN) PcdGet16 (PcdSmbaIoBaseAddress); + } else { + IoPortBaseAddress = (UINTN) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) & B_QNC_LPC_SMBUS_BASE_MASK; + } + + // + // Make sure that the IO port base address has been properly set. + // + ASSERT (IoPortBaseAddress != 0); + + return IoPortBaseAddress; +} + + +VOID +InitializeInternal ( + ) +{ + UINTN IoPortBaseAddress; + + IoPortBaseAddress = GetSmbusIoPortBaseAddress (); + + // + // Step1: Enable QNC SMBUS I/O space. + // + LpcPciCfg32Or(R_QNC_LPC_SMBUS_BASE, B_QNC_LPC_SMBUS_BASE_EN); + + // + // Step2: Clear Status Register before anyone uses the interfaces. + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL); + + // + // Step3: Program the correct smbus clock + // + IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCLK, V_QNC_SMBUS_HCLK_100KHZ); +} + + + + +BOOLEAN +IsAddressAvailable ( + IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress + ) +{ + UINT8 Index; + + // + // See if we have already assigned this address to a device + // + for (Index = 0; Index < mDeviceMapEntries; Index++) { + if (SlaveAddress.SmbusDeviceAddress == + mDeviceMap[Index].SmbusDeviceAddress.SmbusDeviceAddress) { + return FALSE; + } + } + + // + // See if this address is claimed by a platform non-ARP-capable device + // + for (Index = 0; Index < mPlatformNumRsvd; Index++) { + if ((SlaveAddress.SmbusDeviceAddress << 1) == mPlatformAddrRsvd[Index]) { + return FALSE; + } + } + + // + // See if this is a reserved address + // + for (Index = 0; Index < SMBUS_NUM_RESERVED; Index++) { + if (SlaveAddress.SmbusDeviceAddress == (UINTN) mReservedAddress[Index]) { + return FALSE; + } + } + + return TRUE; +} + + +EFI_STATUS +GetNextAvailableAddress ( + IN EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress + ) +{ + for (SlaveAddress->SmbusDeviceAddress = 0x03; + SlaveAddress->SmbusDeviceAddress < 0x7F; + SlaveAddress->SmbusDeviceAddress++ + ) { + if (IsAddressAvailable (*SlaveAddress)) { + return EFI_SUCCESS; + } + } + + return EFI_OUT_OF_RESOURCES; +} + +EFI_STATUS +SmbusPrepareToArp ( + ) +{ + EFI_SMBUS_DEVICE_ADDRESS SlaveAddress; + EFI_STATUS Status; + UINTN Length; + UINT8 Buffer; + + SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP; + Length = 1; + Buffer = SMBUS_DATA_PREPARE_TO_ARP; + + Status = Execute ( + SlaveAddress, + 0, + EfiSmbusSendByte, + TRUE, + &Length, + &Buffer + ); + return Status; +} + +EFI_STATUS +SmbusGetUdidGeneral ( + IN OUT EFI_SMBUS_DEVICE_MAP *DeviceMap + ) +{ + EFI_SMBUS_DEVICE_ADDRESS SlaveAddress; + EFI_STATUS Status; + UINTN Length; + UINT8 Buffer[SMBUS_GET_UDID_LENGTH]; + + SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP; + Length = SMBUS_GET_UDID_LENGTH; + + Status = Execute ( + SlaveAddress, + SMBUS_DATA_GET_UDID_GENERAL, + EfiSmbusReadBlock, + TRUE, + &Length, + Buffer + ); + + if (!EFI_ERROR(Status)) { + if (Length == SMBUS_GET_UDID_LENGTH) { + DeviceMap->SmbusDeviceUdid.DeviceCapabilities = Buffer[0]; + DeviceMap->SmbusDeviceUdid.VendorRevision = Buffer[1]; + DeviceMap->SmbusDeviceUdid.VendorId = (UINT16)((Buffer[2] << 8) + Buffer[3]); + DeviceMap->SmbusDeviceUdid.DeviceId = (UINT16)((Buffer[4] << 8) + Buffer[5]); + DeviceMap->SmbusDeviceUdid.Interface = (UINT16)((Buffer[6] << 8) + Buffer[7]); + DeviceMap->SmbusDeviceUdid.SubsystemVendorId = (UINT16)((Buffer[8] << 8) + Buffer[9]); + DeviceMap->SmbusDeviceUdid.SubsystemDeviceId = (UINT16)((Buffer[10] << 8) + Buffer[11]); + DeviceMap->SmbusDeviceUdid.VendorSpecificId = (UINT32)((Buffer[12] << 24) + (Buffer[13] << 16) + (Buffer[14] << 8) + Buffer[15]); + DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress = (UINT8)(Buffer[16] >> 1); + } else { + Status = EFI_DEVICE_ERROR; + } + } + + return Status; +} + +EFI_STATUS +SmbusAssignAddress ( + IN OUT EFI_SMBUS_DEVICE_MAP *DeviceMap + ) +{ + EFI_SMBUS_DEVICE_ADDRESS SlaveAddress; + EFI_STATUS Status; + UINTN Length; + UINT8 Buffer[SMBUS_GET_UDID_LENGTH]; + + Buffer[0] = DeviceMap->SmbusDeviceUdid.DeviceCapabilities; + Buffer[1] = DeviceMap->SmbusDeviceUdid.VendorRevision; + Buffer[2] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorId >> 8); + Buffer[3] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorId); + Buffer[4] = (UINT8)(DeviceMap->SmbusDeviceUdid.DeviceId >> 8); + Buffer[5] = (UINT8)(DeviceMap->SmbusDeviceUdid.DeviceId); + Buffer[6] = (UINT8)(DeviceMap->SmbusDeviceUdid.Interface >> 8); + Buffer[7] = (UINT8)(DeviceMap->SmbusDeviceUdid.Interface); + Buffer[8] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemVendorId >> 8); + Buffer[9] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemVendorId); + Buffer[10] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemDeviceId >> 8); + Buffer[11] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemDeviceId); + Buffer[12] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 24); + Buffer[13] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 16); + Buffer[14] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 8); + Buffer[15] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId); + Buffer[16] = (UINT8)(DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress << 1); + + SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP; + Length = SMBUS_GET_UDID_LENGTH; + + Status = Execute ( + SlaveAddress, + SMBUS_DATA_ASSIGN_ADDRESS, + EfiSmbusWriteBlock, + TRUE, + &Length, + Buffer + ); + return Status; +} + + +EFI_STATUS +SmbusFullArp ( + ) +{ + EFI_STATUS Status; + EFI_SMBUS_DEVICE_MAP *CurrentDeviceMap; + + Status = SmbusPrepareToArp (); + if (EFI_ERROR(Status)) { + if (Status == EFI_DEVICE_ERROR) { + // + // ARP is complete + // + return EFI_SUCCESS; + } else { + return Status; + } + } + + // + // Main loop to ARP all ARP-capable devices + // + do { + CurrentDeviceMap = &mDeviceMap[mDeviceMapEntries]; + Status = SmbusGetUdidGeneral (CurrentDeviceMap); + if (EFI_ERROR(Status)) { + break; + } + + if (CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress == (0xFF >> 1)) { + // + // If address is unassigned, assign it + // + Status = GetNextAvailableAddress ( + &CurrentDeviceMap->SmbusDeviceAddress + ); + if (EFI_ERROR(Status)) { + return EFI_OUT_OF_RESOURCES; + } + } else if (((CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities) & 0xC0) != 0) { + // + // if address is not fixed, check if the current address is available + // + if (!IsAddressAvailable ( + CurrentDeviceMap->SmbusDeviceAddress + )) { + // + // if currently assigned address is already used, get a new one + // + Status = GetNextAvailableAddress ( + &CurrentDeviceMap->SmbusDeviceAddress + ); + if (EFI_ERROR(Status)) { + return EFI_OUT_OF_RESOURCES; + } + } + } + + Status = SmbusAssignAddress (CurrentDeviceMap); + if (EFI_ERROR(Status)) { + // + // If there was a device error, just continue on and try again. + // Other errors should be reported. + // + if (Status != EFI_DEVICE_ERROR) { + return Status; + } + } else { + // + // If there was no error, the address was assigned and we must update our + // records. + // + mDeviceMapEntries++; + } + + } while (mDeviceMapEntries < MAX_SMBUS_DEVICES); + + return EFI_SUCCESS; +} + + +EFI_STATUS +SmbusDirectedArp ( + IN EFI_SMBUS_UDID *SmbusUdid, + IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress + ) +{ + EFI_STATUS Status; + EFI_SMBUS_DEVICE_MAP *CurrentDeviceMap; + + if (mDeviceMapEntries >= MAX_SMBUS_DEVICES) { + return EFI_OUT_OF_RESOURCES; + } + + CurrentDeviceMap = &mDeviceMap[mDeviceMapEntries]; + + // + // Find an available address to assign + // + Status = GetNextAvailableAddress ( + &CurrentDeviceMap->SmbusDeviceAddress + ); + if (EFI_ERROR(Status)) { + return EFI_OUT_OF_RESOURCES; + } + + CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities = SmbusUdid->DeviceCapabilities; + CurrentDeviceMap->SmbusDeviceUdid.DeviceId = SmbusUdid->DeviceId; + CurrentDeviceMap->SmbusDeviceUdid.Interface = SmbusUdid->Interface; + CurrentDeviceMap->SmbusDeviceUdid.SubsystemDeviceId = SmbusUdid->SubsystemDeviceId; + CurrentDeviceMap->SmbusDeviceUdid.SubsystemVendorId = SmbusUdid->SubsystemVendorId; + CurrentDeviceMap->SmbusDeviceUdid.VendorId = SmbusUdid->VendorId; + CurrentDeviceMap->SmbusDeviceUdid.VendorRevision = SmbusUdid->VendorRevision; + CurrentDeviceMap->SmbusDeviceUdid.VendorSpecificId = SmbusUdid->VendorSpecificId; + + Status = SmbusAssignAddress (CurrentDeviceMap); + if (EFI_ERROR(Status)) { + return Status; + } + + mDeviceMapEntries++; + SlaveAddress->SmbusDeviceAddress = CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress; + + return EFI_SUCCESS; +} + + + +/** + Executes an SMBus operation to an SMBus controller. Returns when either the command has been + executed or an error is encountered in doing the operation. + + The Execute() function provides a standard way to execute an operation as defined in the System + Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus + slave devices accept this transaction or that this function returns with error. + + @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance. + @param SlaveAddress The SMBus slave address of the device with which to communicate. + @param Command This command is transmitted by the SMBus host controller to the + SMBus slave device and the interpretation is SMBus slave device + specific. It can mean the offset to a list of functions inside an + SMBus slave device. Not all operations or slave devices support + this command's registers. + @param Operation Signifies which particular SMBus hardware protocol instance that + it will use to execute the SMBus transactions. This SMBus + hardware protocol is defined by the SMBus Specification and is + not related to EFI. + @param PecCheck Defines if Packet Error Code (PEC) checking is required for this + operation. + @param Length Signifies the number of bytes that this operation will do. The + maximum number of bytes can be revision specific and operation + specific. This field will contain the actual number of bytes that + are executed for this operation. Not all operations require this + argument. + @param Buffer Contains the value of data to execute to the SMBus slave device. + Not all operations require this argument. The length of this + buffer is identified by Length. + + @retval EFI_SUCCESS The last data that was returned from the access matched the poll + exit criteria. + @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect). + @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is + determined by the SMBus host controller device. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The request was not completed because a failure that was + reflected in the Host Status Register bit. Device errors are a + result of a transaction collision, illegal command field, + unclaimed cycle (host initiated), or bus errors (collisions). + @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION. + @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead + and EfiSmbusQuickWrite. Length is outside the range of valid + values. + @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported. + @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation. + +**/ +EFI_STATUS +EFIAPI +SmbusExecute ( + IN CONST EFI_SMBUS_HC_PROTOCOL *This, + IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, + IN CONST EFI_SMBUS_DEVICE_COMMAND Command, + IN CONST EFI_SMBUS_OPERATION Operation, + IN CONST BOOLEAN PecCheck, + IN OUT UINTN *Length, + IN OUT VOID *Buffer + ) +{ + InitializeInternal (); + return Execute ( + SlaveAddress, + Command, + Operation, + PecCheck, + Length, + Buffer + ); +} + +/** + Sets the SMBus slave device addresses for the device with a given unique ID or enumerates the + entire bus. + + The ArpDevice() function provides a standard way for a device driver to enumerate the entire + SMBus or specific devices on the bus. + + @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance. + @param ArpAll A Boolean expression that indicates if the host drivers need to + enumerate all the devices or enumerate only the device that is + identified by SmbusUdid. If ArpAll is TRUE, SmbusUdid and + SlaveAddress are optional. If ArpAll is FALSE, ArpDevice will + enumerate SmbusUdid and the address will be at SlaveAddress. + @param SmbusUdid The Unique Device Identifier (UDID) that is associated with this + device. + @param SlaveAddress The SMBus slave address that is associated with an SMBus UDID. + + @retval EFI_SUCCESS The last data that was returned from the access matched the poll + exit criteria. + @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect). + @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is + determined by the SMBus host controller device. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The request was not completed because a failure that was + reflected in the Host Status Register bit. Device errors are a + result of a transaction collision, illegal command field, + unclaimed cycle (host initiated), or bus errors (collisions). + @retval EFI_UNSUPPORTED The corresponding SMBus operation is not supported. + +**/ +EFI_STATUS +EFIAPI +SmbusArpDevice ( + IN CONST EFI_SMBUS_HC_PROTOCOL *This, + IN BOOLEAN ArpAll, + IN EFI_SMBUS_UDID *SmbusUdid, OPTIONAL + IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL + ) +{ + InitializeInternal (); + + if (ArpAll) { + return SmbusFullArp (); + } else { + if ((SmbusUdid == NULL) || (SlaveAddress == NULL)) { + return EFI_INVALID_PARAMETER; + } + return SmbusDirectedArp ((EFI_SMBUS_UDID *)SmbusUdid, SlaveAddress); + } +} + +/** + Returns a pointer to the Address Resolution Protocol (ARP) map that contains the ID/address pair + of the slave devices that were enumerated by the SMBus host controller driver. + + The GetArpMap() function returns the mapping of all the SMBus devices that were enumerated by the + SMBus host driver. + + @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance. + @param Length Size of the buffer that contains the SMBus device map. + @param SmbusDeviceMap The pointer to the device map as enumerated by the SMBus + controller driver. + + @retval EFI_SUCCESS The SMBus returned the current device map. + @retval EFI_UNSUPPORTED The corresponding operation is not supported. + +**/ +EFI_STATUS +EFIAPI +SmbusGetArpMap ( + IN CONST EFI_SMBUS_HC_PROTOCOL *This, + IN OUT UINTN *Length, + IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap + ) +{ + *Length = mDeviceMapEntries; + *SmbusDeviceMap = mDeviceMap; + return EFI_SUCCESS; +} + + +/** + Allows a device driver to register for a callback when the bus driver detects a state that it + needs to propagate to other drivers that are registered for a callback. + + The Notify() function registers all the callback functions to allow the bus driver to call these + functions when the SlaveAddress/Data pair happens. + If NotifyFunction is NULL, then ASSERT (). + + @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance. + @param SlaveAddress The SMBUS hardware address to which the SMBUS device is + preassigned or allocated. + @param Data Data of the SMBus host notify command that the caller wants to be + called. + @param NotifyFunction The function to call when the bus driver detects the SlaveAddress + and Data pair. + + @retval EFI_SUCCESS NotifyFunction was registered. + @retval EFI_UNSUPPORTED The corresponding operation is not supported. + +**/ +EFI_STATUS +EFIAPI +SmbusNotify ( + IN CONST EFI_SMBUS_HC_PROTOCOL *This, + IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, + IN CONST UINTN Data, + IN CONST EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Entry point to the DXE Driver that produces the SMBus Host Controller Protocol. + + @param ImageHandle ImageHandle of the loaded driver. + @param SystemTable Pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point of SMBus DXE driver is executed successfully. + @retval !EFI_SUCESS Some error occurs in the entry point of SMBus DXE driver. + +**/ +EFI_STATUS +EFIAPI +InitializeQNCSmbus ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mPlatformNumRsvd = (UINT8)PcdGet32 (PcdPlatformSmbusAddrNum); + mPlatformAddrRsvd = (UINT8 *)(UINTN) PcdGet64 (PcdPlatformSmbusAddrTable); + + // + // Install SMBus Host Controller protocol interface. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSmbusHcHandle, + &gEfiSmbusHcProtocolGuid, + &mSmbusHc, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h new file mode 100644 index 0000000000..6a302ce838 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/DxeQNCSmbus.h @@ -0,0 +1,205 @@ +/** @file +Header file for the defintions used in SMBus DXE driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _DXE_QNC_SMBUS_H_ +#define _DXE_QNC_SMBUS_H_ +#include "CommonHeader.h" + +#include "QNCSmbus.h" + +#define MAX_SMBUS_DEVICES 107 // Max number of SMBus devices (7 bit + // address yields 128 combinations but 21 + // of those are reserved) + +#define MICROSECOND 10 +#define MILLISECOND (1000 * MICROSECOND) +#define ONESECOND (1000 * MILLISECOND) + +#define STALL_TIME 1000000 // 1,000,000 microseconds = 1 second +#define BUS_TRIES 3 // How many times to retry on Bus Errors +#define SMBUS_NUM_RESERVED 21 // Number of device addresses that are + // reserved by the SMBus spec. +#define SMBUS_ADDRESS_ARP 0xC2 >> 1 +#define SMBUS_DATA_PREPARE_TO_ARP 0x01 +#define SMBUS_DATA_RESET_DEVICE 0x02 +#define SMBUS_DATA_GET_UDID_GENERAL 0x03 +#define SMBUS_DATA_ASSIGN_ADDRESS 0x04 +#define SMBUS_GET_UDID_LENGTH 17 // 16 byte UDID + 1 byte address + +/** + Executes an SMBus operation to an SMBus controller. Returns when either the command has been + executed or an error is encountered in doing the operation. + + The Execute() function provides a standard way to execute an operation as defined in the System + Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus + slave devices accept this transaction or that this function returns with error. + + @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance. + @param SlaveAddress The SMBus slave address of the device with which to communicate. + @param Command This command is transmitted by the SMBus host controller to the + SMBus slave device and the interpretation is SMBus slave device + specific. It can mean the offset to a list of functions inside an + SMBus slave device. Not all operations or slave devices support + this command's registers. + @param Operation Signifies which particular SMBus hardware protocol instance that + it will use to execute the SMBus transactions. This SMBus + hardware protocol is defined by the SMBus Specification and is + not related to EFI. + @param PecCheck Defines if Packet Error Code (PEC) checking is required for this + operation. + @param Length Signifies the number of bytes that this operation will do. The + maximum number of bytes can be revision specific and operation + specific. This field will contain the actual number of bytes that + are executed for this operation. Not all operations require this + argument. + @param Buffer Contains the value of data to execute to the SMBus slave device. + Not all operations require this argument. The length of this + buffer is identified by Length. + + @retval EFI_SUCCESS The last data that was returned from the access matched the poll + exit criteria. + @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect). + @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is + determined by the SMBus host controller device. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The request was not completed because a failure that was + reflected in the Host Status Register bit. Device errors are a + result of a transaction collision, illegal command field, + unclaimed cycle (host initiated), or bus errors (collisions). + @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION. + @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead + and EfiSmbusQuickWrite. Length is outside the range of valid + values. + @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported. + @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation. + +**/ +EFI_STATUS +EFIAPI +SmbusExecute ( + IN CONST EFI_SMBUS_HC_PROTOCOL *This, + IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, + IN CONST EFI_SMBUS_DEVICE_COMMAND Command, + IN CONST EFI_SMBUS_OPERATION Operation, + IN CONST BOOLEAN PecCheck, + IN OUT UINTN *Length, + IN OUT VOID *Buffer + ); + +/** + Sets the SMBus slave device addresses for the device with a given unique ID or enumerates the + entire bus. + + The ArpDevice() function provides a standard way for a device driver to enumerate the entire + SMBus or specific devices on the bus. + + @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance. + @param ArpAll A Boolean expression that indicates if the host drivers need to + enumerate all the devices or enumerate only the device that is + identified by SmbusUdid. If ArpAll is TRUE, SmbusUdid and + SlaveAddress are optional. If ArpAll is FALSE, ArpDevice will + enumerate SmbusUdid and the address will be at SlaveAddress. + @param SmbusUdid The Unique Device Identifier (UDID) that is associated with this + device. + @param SlaveAddress The SMBus slave address that is associated with an SMBus UDID. + + @retval EFI_SUCCESS The last data that was returned from the access matched the poll + exit criteria. + @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect). + @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is + determined by the SMBus host controller device. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The request was not completed because a failure that was + reflected in the Host Status Register bit. Device errors are a + result of a transaction collision, illegal command field, + unclaimed cycle (host initiated), or bus errors (collisions). + @retval EFI_UNSUPPORTED The corresponding operation is not supported. + +**/ +EFI_STATUS +EFIAPI +SmbusArpDevice ( + IN CONST EFI_SMBUS_HC_PROTOCOL *This, + IN BOOLEAN ArpAll, + IN EFI_SMBUS_UDID *SmbusUdid, OPTIONAL + IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL + ); + +/** + Returns a pointer to the Address Resolution Protocol (ARP) map that contains the ID/address pair + of the slave devices that were enumerated by the SMBus host controller driver. + + The GetArpMap() function returns the mapping of all the SMBus devices that were enumerated by the + SMBus host driver. + + @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance. + @param Length Size of the buffer that contains the SMBus device map. + @param SmbusDeviceMap The pointer to the device map as enumerated by the SMBus + controller driver. + + @retval EFI_SUCCESS The SMBus returned the current device map. + @retval EFI_UNSUPPORTED The corresponding operation is not supported. + +**/ +EFI_STATUS +EFIAPI +SmbusGetArpMap ( + IN CONST EFI_SMBUS_HC_PROTOCOL *This, + IN OUT UINTN *Length, + IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap + ); + +/** + Allows a device driver to register for a callback when the bus driver detects a state that it + needs to propagate to other drivers that are registered for a callback. + + The Notify() function registers all the callback functions to allow the bus driver to call these + functions when the SlaveAddress/Data pair happens. + If NotifyFunction is NULL, then ASSERT (). + + @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance. + @param SlaveAddress The SMBUS hardware address to which the SMBUS device is + preassigned or allocated. + @param Data Data of the SMBus host notify command that the caller wants to be + called. + @param NotifyFunction The function to call when the bus driver detects the SlaveAddress + and Data pair. + + @retval EFI_SUCCESS NotifyFunction was registered. + @retval EFI_UNSUPPORTED The corresponding operation is not supported. + +**/ +EFI_STATUS +EFIAPI +SmbusNotify ( + IN CONST EFI_SMBUS_HC_PROTOCOL *This, + IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, + IN CONST UINTN Data, + IN CONST EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction + ); + +/** + Entry point to the DXE Driver that produces the SMBus Host Controller Protocol. + + @param ImageHandle ImageHandle of the loaded driver. + @param SystemTable Pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point of SMBus DXE driver is executed successfully. + @retval !EFI_SUCESS Some error occurs in the entry point of SMBus DXE driver. + +**/ +EFI_STATUS +EFIAPI +InitializeQNCSmbus ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c new file mode 100644 index 0000000000..db9c6f29e5 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.c @@ -0,0 +1,237 @@ +/** @file +QNC Legacy Region Driver + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CommonHeader.h" +#include "LegacyRegion.h" + +// +// Handle used to install the Legacy Region Protocol +// +EFI_HANDLE mLegacyRegion2Handle = NULL; + +// +// Instance of the Legacy Region Protocol to install into the handle database +// +EFI_LEGACY_REGION2_PROTOCOL mLegacyRegion2 = { + LegacyRegion2Decode, + LegacyRegion2Lock, + LegacyRegion2BootLock, + LegacyRegion2Unlock, + LegacyRegionGetInfo +}; + + +/** + Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region. + + If the On parameter evaluates to TRUE, this function enables memory reads in the address range + Start to (Start + Length - 1). + If the On parameter evaluates to FALSE, this function disables memory reads in the address range + Start to (Start + Length - 1). + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose attributes + should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address + was not aligned to a region's starting address or if the length + was greater than the number of bytes in the first region. + @param On[in] Decode / Non-Decode flag. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Decode ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity, + IN BOOLEAN *On + ) +{ + return QNCLegacyRegionManipulation (Start, Length, On, NULL, Granularity); +} + + +/** + Modify the hardware to disallow memory attribute changes in a region. + + This function makes the attributes of a region read only. Once a region is boot-locked with this + function, the read and write attributes of that region cannot be changed until a power cycle has + reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in + a way that will not affect memory regions outside the legacy memory + region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2BootLock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ) +{ + if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) { + return EFI_INVALID_PARAMETER; + } + + return EFI_UNSUPPORTED; +} + + +/** + Modify the hardware to disallow memory writes in a region. + + This function changes the attributes of a memory range to not allow writes. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Lock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ) +{ + BOOLEAN WriteEnable; + + WriteEnable = FALSE; + return QNCLegacyRegionManipulation (Start, Length, NULL, &WriteEnable, Granularity); +} + + +/** + Modify the hardware to allow memory writes in a region. + + This function changes the attributes of a memory range to allow writes. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Unlock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ) +{ + BOOLEAN WriteEnable; + + WriteEnable = TRUE; + return QNCLegacyRegionManipulation (Start, Length, NULL, &WriteEnable, Granularity); +} + +/** + Get region information for the attributes of the Legacy Region. + + This function is used to discover the granularity of the attributes for the memory in the legacy + region. Each attribute may have a different granularity and the granularity may not be the same + for all memory ranges in the legacy region. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor + buffer. + @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy + region information is deposited. This buffer will contain a list of + DescriptorCount number of region descriptors. This function will + provide the memory for the buffer. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegionGetInfo ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + OUT UINT32 *DescriptorCount, + OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor + ) +{ + + return EFI_UNSUPPORTED; +} + +/** + Entry point to the DXE Driver that produces the Legacy Region Protocol. + + @retval EFI_SUCCESS One or more of the drivers returned a success code. + @retval !EFI_SUCESS The return status from the last driver entry point in the list. + +**/ +EFI_STATUS +LegacyRegionInit ( + ) +{ + EFI_STATUS Status; + + // + // Install the Legacy Region Protocol on a new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mLegacyRegion2Handle, + &gEfiLegacyRegion2ProtocolGuid, &mLegacyRegion2, + NULL + ); + + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h new file mode 100644 index 0000000000..8afe23f02f --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/LegacyRegion.h @@ -0,0 +1,198 @@ +/** @file +The header file legacy region initialization in QNC DXE component. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LEGACY_REGION_H_ +#define _LEGACY_REGION_H_ +#include "CommonHeader.h" + +#include + +#define LEGACY_REGION_INSTANCE_SIGNATURE SIGNATURE_32('R','E','G','N') + +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + EFI_LEGACY_REGION2_PROTOCOL LegacyRegion2; + EFI_HANDLE ImageHandle; + + // + // Protocol for PAM register access + // + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; +} LEGACY_REGION_INSTANCE; + +#define LEGACY_REGION_INSTANCE_FROM_THIS(this) \ + CR(this, LEGACY_REGION_INSTANCE, LegacyRegion2, LEGACY_REGION_INSTANCE_SIGNATURE) + + +EFI_STATUS +LegacyRegionManipluateRegion ( + IN LEGACY_REGION_INSTANCE *Private + ); + +EFI_STATUS +LegacyRegionInit ( + VOID + ); + +/** + Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region. + + If the On parameter evaluates to TRUE, this function enables memory reads in the address range + Start to (Start + Length - 1). + If the On parameter evaluates to FALSE, this function disables memory reads in the address range + Start to (Start + Length - 1). + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose attributes + should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address + was not aligned to a region's starting address or if the length + was greater than the number of bytes in the first region. + @param On[in] Decode / Non-Decode flag. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Decode ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity, + IN BOOLEAN *On + ); + +/** + Modify the hardware to disallow memory writes in a region. + + This function changes the attributes of a memory range to not allow writes. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Lock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ); + +/** + Modify the hardware to disallow memory attribute changes in a region. + + This function makes the attributes of a region read only. Once a region is boot-locked with this + function, the read and write attributes of that region cannot be changed until a power cycle has + reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in + a way that will not affect memory regions outside the legacy memory + region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2BootLock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ); + +/** + Modify the hardware to allow memory writes in a region. + + This function changes the attributes of a memory range to allow writes. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param Start[in] The beginning of the physical address of the region whose + attributes should be modified. + @param Length[in] The number of bytes of memory whose attributes should be modified. + The actual number of bytes modified may be greater than the number + specified. + @param Granularity[out] The number of bytes in the last region affected. This may be less + than the total number of bytes affected if the starting address was + not aligned to a region's starting address or if the length was + greater than the number of bytes in the first region. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegion2Unlock ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + IN UINT32 Start, + IN UINT32 Length, + OUT UINT32 *Granularity + ); + +/** + Get region information for the attributes of the Legacy Region. + + This function is used to discover the granularity of the attributes for the memory in the legacy + region. Each attribute may have a different granularity and the granularity may not be the same + for all memory ranges in the legacy region. + + @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance. + @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor + buffer. + @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy + region information is deposited. This buffer will contain a list of + DescriptorCount number of region descriptors. This function will + provide the memory for the buffer. + + @retval EFI_SUCCESS The region's attributes were successfully modified. + @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region. + +**/ +EFI_STATUS +EFIAPI +LegacyRegionGetInfo ( + IN EFI_LEGACY_REGION2_PROTOCOL *This, + OUT UINT32 *DescriptorCount, + OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor + ); + +#endif //_QNC_LEGACY_REGION_H_ diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c new file mode 100644 index 0000000000..b0751a6362 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.c @@ -0,0 +1,518 @@ +/** @file +QuarkNcSocId module initialization module + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "CommonHeader.h" + +#include "LegacyRegion.h" +#include "DxeQNCSmbus.h" + +#include "QNCInit.h" + +// +// Definitions +// +#define QNC_RESERVED_ITEM_IO 0 +#define QNC_RESERVED_ITEM_MEMORYIO 1 +#define DXE_DEVICE_DISABLED 0 +#define DXE_DEVICE_ENABLED 1 + +typedef struct _QNC_SPACE_TABLE_ITEM { + UINTN IoOrMemory; + UINTN Type; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + UINTN Alignment; + BOOLEAN RuntimeOrNot; +} QNC_SPACE_TABLE_ITEM; + +typedef struct { + ACPI_CPU_DATA AcpuCpuData; + MTRR_SETTINGS MtrrTable; + IA32_DESCRIPTOR GdtrProfile; + IA32_DESCRIPTOR IdtrProfile; + CPU_REGISTER_TABLE RegisterTable; + CPU_REGISTER_TABLE PreSmmInitRegisterTable; +} ACPI_CPU_DATA_EX; + +// +// Spaces to be reserved in GCD +// Expand it to add more +// +const QNC_SPACE_TABLE_ITEM mQNCReservedSpaceTable[] = { + { + QNC_RESERVED_ITEM_MEMORYIO, + EfiGcdMemoryTypeMemoryMappedIo, + FixedPcdGet64 (PcdIoApicBaseAddress), + FixedPcdGet64 (PcdIoApicSize), + 0, + FALSE + }, + { + QNC_RESERVED_ITEM_MEMORYIO, + EfiGcdMemoryTypeMemoryMappedIo, + FixedPcdGet64 (PcdHpetBaseAddress), + FixedPcdGet64 (PcdHpetSize), + 0, + FALSE + } +}; + +// +// Global variable for ImageHandle of QNCInit driver +// +EFI_HANDLE gQNCInitImageHandle; +QNC_DEVICE_ENABLES mQNCDeviceEnables; + + +VOID +QNCInitializeResource ( + VOID + ); + +EFI_STATUS +InitializeQNCPolicy ( + VOID + ); + +/** + Allocate EfiACPIMemoryNVS below 4G memory address. + + This function allocates EfiACPIMemoryNVS below 4G memory address. + + @param Size Size of memory to allocate. + + @return Allocated address for output. + +**/ +VOID * +AllocateAcpiNvsMemoryBelow4G ( + IN UINTN Size + ) +{ + UINTN Pages; + EFI_PHYSICAL_ADDRESS Address; + EFI_STATUS Status; + VOID* Buffer; + + Pages = EFI_SIZE_TO_PAGES (Size); + Address = 0xffffffff; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + Pages, + &Address + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + Buffer = (VOID *) (UINTN) Address; + ZeroMem (Buffer, Size); + + return Buffer; +} + +/** + Prepare ACPI NVS memory below 4G memory for use of S3 resume. + + This function allocates ACPI NVS memory below 4G memory for use of S3 resume, + and saves data into the memory region. + +**/ +VOID +SaveCpuS3Data ( + VOID + ) +{ + EFI_STATUS Status; + ACPI_CPU_DATA_EX *AcpiCpuDataEx; + ACPI_CPU_DATA *AcpiCpuData; + UINTN GdtSize; + UINTN IdtSize; + VOID *Gdt; + VOID *Idt; + + // + // Allocate ACPI NVS memory below 4G memory for use of S3 resume. + // + AcpiCpuDataEx = AllocateAcpiNvsMemoryBelow4G (sizeof (ACPI_CPU_DATA_EX)); + AcpiCpuData = &AcpiCpuDataEx->AcpuCpuData; + + // + // + // + AcpiCpuData->NumberOfCpus = 1; + AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize); + AcpiCpuData->ApMachineCheckHandlerBase = 0; + AcpiCpuData->ApMachineCheckHandlerSize = 0; + AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->GdtrProfile; + AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->IdtrProfile; + AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->MtrrTable; + AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->RegisterTable; + AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->PreSmmInitRegisterTable; + + // + // Allocate stack space for all CPUs + // + AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateAcpiNvsMemoryBelow4G (AcpiCpuData->NumberOfCpus * AcpiCpuData->StackSize); + + // + // Get MTRR settings from currently executing CPU + // + MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable); + + // + // Get the BSP's data of GDT and IDT + // + AsmReadGdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->GdtrProfile); + AsmReadIdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->IdtrProfile); + + // + // Allocate GDT and IDT in ACPI NVS and copy in current GDT and IDT contents + // + GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1; + IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1; + Gdt = AllocateAcpiNvsMemoryBelow4G (GdtSize + IdtSize); + Idt = (VOID *)((UINTN)Gdt + GdtSize); + CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize); + CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize); + AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt; + AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt; + + // + // No RegisterTable entries + // + AcpiCpuDataEx->RegisterTable.TableLength = 0; + + // + // No PreSmmInitRegisterTable entries + // + AcpiCpuDataEx->PreSmmInitRegisterTable.TableLength = 0; + + // + // Set the base address of CPU S3 data to PcdCpuS3DataAddress + // + Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData); + ASSERT_EFI_ERROR (Status); +} + +/** + The entry function for QNCInit driver. + + This function just call initialization function for PciHostBridge, + LegacyRegion and QNCSmmAccess module. + + @param ImageHandle The driver image handle for GmchInit driver + @param SystemTable The pointer to System Table + + @retval EFI_SUCCESS Success to initialize every module for GMCH driver. + @return EFI_STATUS The status of initialization work. + +**/ +EFI_STATUS +EFIAPI +QNCInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + S3BootScriptSaveInformationAsciiString ( + "QNCInitDxeEntryBegin" + ); + + gQNCInitImageHandle = ImageHandle; + + mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables); + + + // + // Initialize PCIE root ports + // + Status = QncInitRootPorts (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "QNC Root Port initialization is failed!\n")); + return Status; + } + + Status = LegacyRegionInit (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "QNC LegacyRegion initialization is failed!\n")); + return Status; + } + + + Status = InitializeQNCPolicy (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "QNC Policy initialization is failed!\n")); + return Status; + } + + Status = InitializeQNCSmbus (ImageHandle,SystemTable); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "QNC Smbus driver is failed!\n")); + return Status; + } + + QNCInitializeResource (); + + SaveCpuS3Data (); + + S3BootScriptSaveInformationAsciiString ( + "QNCInitDxeEntryEnd" + ); + + return EFI_SUCCESS; +} + + +/** + Reserve I/O or memory space in GCD + + @param IoOrMemory Switch of I/O or memory. + @param GcdType Type of the space. + @param BaseAddress Base address of the space. + @param Length Length of the space. + @param Alignment Align with 2^Alignment + @param RuntimeOrNot For runtime usage or not + @param ImageHandle Handle for the image of this driver. + + @retval EFI_SUCCESS Reserve successful +**/ +EFI_STATUS +QNCReserveSpaceInGcd( + IN UINTN IoOrMemory, + IN UINTN GcdType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINTN Alignment, + IN BOOLEAN RuntimeOrNot, + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + + if (IoOrMemory == QNC_RESERVED_ITEM_MEMORYIO) { + Status = gDS->AddMemorySpace ( + GcdType, + BaseAddress, + Length, + EFI_MEMORY_UC + ); + if (EFI_ERROR (Status)) { + DEBUG (( + EFI_D_ERROR, + "Failed to add memory space :0x%x 0x%x\n", + BaseAddress, + Length + )); + } + ASSERT_EFI_ERROR (Status); + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateAddress, + GcdType, + Alignment, + Length, + &BaseAddress, + ImageHandle, + NULL + ); + ASSERT_EFI_ERROR (Status); + if (RuntimeOrNot) { + Status = gDS->SetMemorySpaceAttributes ( + BaseAddress, + Length, + EFI_MEMORY_RUNTIME | EFI_MEMORY_UC + ); + ASSERT_EFI_ERROR (Status); + } + } else { + Status = gDS->AddIoSpace ( + GcdType, + BaseAddress, + Length + ); + ASSERT_EFI_ERROR (Status); + Status = gDS->AllocateIoSpace ( + EfiGcdAllocateAddress, + GcdType, + Alignment, + Length, + &BaseAddress, + ImageHandle, + NULL + ); + ASSERT_EFI_ERROR (Status); + } + return Status; +} + + +/** + Initialize the memory and io resource which belong to QNC. + 1) Report and allocate all BAR's memory to GCD. + 2) Report PCI memory and I/O space to GCD. + 3) Set memory attribute for <1M memory space. +**/ +VOID +QNCInitializeResource ( + ) +{ + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_STATUS Status; + UINT64 ExtraRegionLength; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + UINTN Index; + + // Report TSEG range + // This range maybe has been reportted in PEI phase via Resource Hob. + // + QNCGetTSEGMemoryRange (&BaseAddress, &ExtraRegionLength); + if (ExtraRegionLength != 0) { + Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &Descriptor); + if (Status == EFI_NOT_FOUND) { + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeReserved, + BaseAddress, + ExtraRegionLength, + EFI_MEMORY_UC + ); + } + } + + // + // < 1M resource setting. The memory ranges <1M has been added into GCD via + // resource hob produced by PEI phase. Here will set memory attribute of these + // ranges for DXE phase. + // + + // + // Dos Area (0 ~ 0x9FFFFh) + // + Status = gDS->GetMemorySpaceDescriptor (0, &Descriptor); + DEBUG (( + EFI_D_INFO, + "DOS Area Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n", + Descriptor.BaseAddress, + Descriptor.Length, + Descriptor.Attributes + )); + ASSERT_EFI_ERROR (Status); + Status = gDS->SetMemorySpaceAttributes( + 0, + 0xA0000, + EFI_MEMORY_WB + ); + ASSERT_EFI_ERROR (Status); + + // + // Default SMRAM UnCachable until SMBASE relocated. + // + Status = gDS->SetMemorySpaceAttributes( + 0x30000, + 0x10000, + EFI_MEMORY_UC + ); + ASSERT_EFI_ERROR (Status); + + // + // Default SMM ABSEG area. (0xA0000 ~ 0xBFFFF) + // + Status = gDS->GetMemorySpaceDescriptor (0xA0000, &Descriptor); + DEBUG (( + EFI_D_INFO, + "ABSEG Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n", + Descriptor.BaseAddress, + Descriptor.Length, + Descriptor.Attributes + )); + ASSERT_EFI_ERROR (Status); + Status = gDS->SetMemorySpaceAttributes( + 0xA0000, + 0x20000, + EFI_MEMORY_UC + ); + ASSERT_EFI_ERROR (Status); + + // + // Expansion BIOS area. + // + Status = gDS->GetMemorySpaceDescriptor (0xC0000, &Descriptor); + DEBUG (( + EFI_D_INFO, + "Memory base = 0x%x, length = 0x%x, attribute = 0x%x\n", + Descriptor.BaseAddress, + Descriptor.Length, + Descriptor.Attributes + )); + ASSERT_EFI_ERROR (Status); + Status = gDS->SetMemorySpaceAttributes( + 0xC0000, + 0x30000, + EFI_MEMORY_UC + ); + ASSERT_EFI_ERROR (Status); + + // + // Report other IO resources from mQNCReservedSpaceTable in GCD + // + for (Index = 0; Index < sizeof (mQNCReservedSpaceTable) / sizeof (QNC_SPACE_TABLE_ITEM); Index++) { + Status = QNCReserveSpaceInGcd ( + mQNCReservedSpaceTable[Index].IoOrMemory, + mQNCReservedSpaceTable[Index].Type, + mQNCReservedSpaceTable[Index].BaseAddress, + mQNCReservedSpaceTable[Index].Length, + mQNCReservedSpaceTable[Index].Alignment, + mQNCReservedSpaceTable[Index].RuntimeOrNot, + gQNCInitImageHandle + ); + ASSERT_EFI_ERROR (Status); + } + + // + // Report unused PCIe config space as reserved. + // + if (PcdGet64 (PcdPciExpressSize) < SIZE_256MB) { + Status = QNCReserveSpaceInGcd ( + QNC_RESERVED_ITEM_MEMORYIO, + EfiGcdMemoryTypeMemoryMappedIo, + (PcdGet64(PcdPciExpressBaseAddress) + PcdGet64(PcdPciExpressSize)), + (SIZE_256MB - PcdGet64(PcdPciExpressSize)), + 0, + FALSE, + gQNCInitImageHandle + ); + ASSERT_EFI_ERROR (Status); + } +} + +/** + Use the platform PCD to initialize devices in the QNC + + @param ImageHandle Handle for the image of this driver. + @retval EFI_SUCCESS Initialize successful +**/ +EFI_STATUS +InitializeQNCPolicy ( + ) +{ + UINT32 PciD31F0RegBase; // LPC + + PciD31F0RegBase = PciDeviceMmBase (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC); + + // + // Disable for smbus + // + if (mQNCDeviceEnables.Bits.Smbus == DXE_DEVICE_DISABLED) { + S3MmioAnd32 (PciD31F0RegBase + R_QNC_LPC_SMBUS_BASE, (~B_QNC_LPC_SMBUS_BASE_EN)); + } + + return EFI_SUCCESS; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h new file mode 100644 index 0000000000..c5d1ffad40 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInit.h @@ -0,0 +1,49 @@ +/** @file +Header file for QNC Initialization Driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ +#ifndef _QNC_INITIALIZATION_DRIVER_H_ +#define _QNC_INITIALIZATION_DRIVER_H_ + +EFI_STATUS +QncInitRootPorts ( + ) +/*++ + +Routine Description: + + Perform Initialization of the Downstream Root Ports. + +Arguments: + +Returns: + + EFI_STATUS + +--*/ +; + +EFI_STATUS +SetInitRootPortDownstreamS3Item ( + ) +/*++ + +Routine Description: + + Set an Init Root Port Downstream devices S3 dispatch item, this function may assert if any error happend + +Arguments: + +Returns: + + EFI_SUCCESS The function completed successfully + +--*/ +; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf new file mode 100644 index 0000000000..b250602cf4 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf @@ -0,0 +1,92 @@ +## @file +# Component description file for QNCInit driver. +# +# QNCInit driver implement QuarkNcSocId related drivers, includes: +# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver. +# +# This driver mainly do full initialization for the QNC chipet includes: +# 1. Initialize the PCI Express device. +# 2. Initialize the PciHostBridge, and allocate the I/O and memory space from GCD service. +# 3. Initialize the SmmAccess module and install EFI_SMM_ACCESS_PROTOCOL +# 4. Initialize the LegacyRegion module, install EFI_LEGACY_REGION_PROTOCOL and set below 1M +# memory attribute from MTRR. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = QNCInitDxe + FILE_GUID = 74D3B506-EE9C-47ed-B749-41261401DA78 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = QNCInit + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + LegacyRegion.h + LegacyRegion.c + DxeQNCSmbus.c + DxeQNCSmbus.h + QNCSmbusExec.c + QNCSmbus.h + QNCInit.c + QNCInit.h + CommonHeader.h + QNCRootPorts.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + UefiBootServicesTableLib + DxeServicesTableLib + BaseMemoryLib + DebugLib + PcdLib + MtrrLib + IoLib + SmbusLib + S3IoLib + S3BootScriptLib + IntelQNCLib + QNCAccessLib + +[Protocols] + gEfiLegacyRegion2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSmbusHcProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiQncS3SupportProtocolGuid # PROTOCOL ALWAYS_CONSUMED + +[FeaturePcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed + +[FixedPcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicSize + gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetSize + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress|0x0|UINT64|0x60000010 ## PRODUCES + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## CONSUMES + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciExpressSize ## CONSUMES + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrNum + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrTable + +[Depex] + gEfiPlatformPolicyProtocolGuid AND gEfiQncS3SupportProtocolGuid diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c new file mode 100644 index 0000000000..7c3f18efc7 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCRootPorts.c @@ -0,0 +1,76 @@ +/** @file +PciHostBridge driver module, part of QNC module. + +Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "CommonHeader.h" +#include "QNCInit.h" + +UINT32 mS3ParameterRootPortDownstream = 0; +EFI_QNC_S3_DISPATCH_ITEM mS3DispatchItem = { + QncS3ItemTypeInitPcieRootPortDownstream, + &mS3ParameterRootPortDownstream + }; + +EFI_STATUS +QncInitRootPorts ( + ) +/*++ + +Routine Description: + + Perform Initialization of the Downstream Root Ports + +Arguments: + +Returns: + + EFI_SUCCESS The function completed successfully + +--*/ +{ + EFI_STATUS Status; + EFI_QNC_S3_SUPPORT_PROTOCOL *QncS3Support; + VOID *Context; + VOID *S3DispatchEntryPoint; + + Status = PciExpressInit (); + ASSERT_EFI_ERROR (Status); + + // + // Get the QNC S3 Support Protocol + // + Status = gBS->LocateProtocol ( + &gEfiQncS3SupportProtocolGuid, + NULL, + (VOID **) &QncS3Support + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the QNC S3 Support Protocol + // + Status = QncS3Support->SetDispatchItem ( + QncS3Support, + &mS3DispatchItem, + &S3DispatchEntryPoint, + &Context + ); + ASSERT_EFI_ERROR (Status); + + // + // Save the script dispatch item in the Boot Script + // + Status = S3BootScriptSaveDispatch2 (S3DispatchEntryPoint, Context); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h new file mode 100644 index 0000000000..fbd1859dea --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbus.h @@ -0,0 +1,80 @@ +/** @file +Common definitons for SMBus PEIM/DXE driver. Smbus PEI and DXE +modules share the same version of this file. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _QNC_SMBUS_H_ +#define _QNC_SMBUS_H_ + +#include "CommonHeader.h" + +// +// Minimum and maximum length for SMBus bus block protocols defined in SMBus spec 2.0. +// +#define MIN_SMBUS_BLOCK_LEN 1 +#define MAX_SMBUS_BLOCK_LEN 32 +#define ADD_LENGTH(SmbusAddress, Length) ((SmbusAddress) + SMBUS_LIB_ADDRESS (0, 0, (Length), FALSE)) + +/** + Executes an SMBus operation to an SMBus controller. Returns when either the command has been + executed or an error is encountered in doing the operation. + + The internal worker function provides a standard way to execute an operation as defined in the + System Management Bus (SMBus) Specification. The resulting transaction will be either that the + SMBus slave devices accept this transaction or that this function returns with error. + + @param SlaveAddress The SMBus slave address of the device with which to communicate. + @param Command This command is transmitted by the SMBus host controller to the + SMBus slave device and the interpretation is SMBus slave device + specific. It can mean the offset to a list of functions inside an + SMBus slave device. Not all operations or slave devices support + this command's registers. + @param Operation Signifies which particular SMBus hardware protocol instance that + it will use to execute the SMBus transactions. This SMBus + hardware protocol is defined by the SMBus Specification and is + not related to EFI. + @param PecCheck Defines if Packet Error Code (PEC) checking is required for this + operation. + @param Length Signifies the number of bytes that this operation will do. The + maximum number of bytes can be revision specific and operation + specific. This field will contain the actual number of bytes that + are executed for this operation. Not all operations require this + argument. + @param Buffer Contains the value of data to execute to the SMBus slave device. + Not all operations require this argument. The length of this + buffer is identified by Length. + + @retval EFI_SUCCESS The last data that was returned from the access matched the poll + exit criteria. + @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect). + @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is + determined by the SMBus host controller device. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The request was not completed because a failure that was + reflected in the Host Status Register bit. Device errors are a + result of a transaction collision, illegal command field, + unclaimed cycle (host initiated), or bus errors (collisions). + @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION. + @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead + and EfiSmbusQuickWrite. Length is outside the range of valid + values. + @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported. + @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation. + +**/ +EFI_STATUS +Execute ( + IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, + IN EFI_SMBUS_DEVICE_COMMAND Command, + IN EFI_SMBUS_OPERATION Operation, + IN BOOLEAN PecCheck, + IN OUT UINTN *Length, + IN OUT VOID *Buffer + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c new file mode 100644 index 0000000000..dbd3566496 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCSmbusExec.c @@ -0,0 +1,246 @@ +/** @file +Common code to implement SMBus bus protocols. Smbus PEI and DXE modules +share the same version of this file. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "CommonHeader.h" + +#include "QNCSmbus.h" + +/** + Checks the parameter of SmbusExecute(). + + This function checks the input parameters of SmbusExecute(). If the input parameters are valid + for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain + error code based on the input SMBus bus protocol. + + @param SlaveAddress The SMBus slave address of the device with which to communicate. + @param Command This command is transmitted by the SMBus host controller to the + SMBus slave device and the interpretation is SMBus slave device + specific. It can mean the offset to a list of functions inside an + SMBus slave device. Not all operations or slave devices support + this command's registers. + @param Operation Signifies which particular SMBus hardware protocol instance that + it will use to execute the SMBus transactions. This SMBus + hardware protocol is defined by the SMBus Specification and is + not related to EFI. + @param PecCheck Defines if Packet Error Code (PEC) checking is required for this + operation. + @param Length Signifies the number of bytes that this operation will do. The + maximum number of bytes can be revision specific and operation + specific. This field will contain the actual number of bytes that + are executed for this operation. Not all operations require this + argument. + @param Buffer Contains the value of data to execute to the SMBus slave device. + Not all operations require this argument. The length of this + buffer is identified by Length. + + @retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus + protocol. + @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION. + @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead + and EfiSmbusQuickWrite. Length is outside the range of valid + values. + @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported. + @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation. + +**/ +EFI_STATUS +QncSmbusExecCheckParameters ( + IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, + IN EFI_SMBUS_DEVICE_COMMAND Command, + IN EFI_SMBUS_OPERATION Operation, + IN BOOLEAN PecCheck, + IN OUT UINTN *Length, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN RequiredLen; + + // + // Set default value to be 2: + // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall. + // + RequiredLen = 2; + Status = EFI_SUCCESS; + switch (Operation) { + case EfiSmbusQuickRead: + case EfiSmbusQuickWrite: + if (PecCheck || Command != 0) { + return EFI_UNSUPPORTED; + } + break; + case EfiSmbusReceiveByte: + case EfiSmbusSendByte: + if (Command != 0) { + return EFI_UNSUPPORTED; + } + // + // Cascade to check length parameter. + // + case EfiSmbusReadByte: + case EfiSmbusWriteByte: + RequiredLen = 1; + // + // Cascade to check length parameter. + // + case EfiSmbusReadWord: + case EfiSmbusWriteWord: + case EfiSmbusProcessCall: + if (Buffer == NULL || Length == NULL) { + return EFI_INVALID_PARAMETER; + } else if (*Length < RequiredLen) { + Status = EFI_BUFFER_TOO_SMALL; + } + *Length = RequiredLen; + break; + case EfiSmbusReadBlock: + case EfiSmbusWriteBlock: + if ((Buffer == NULL) || + (Length == NULL) || + (*Length < MIN_SMBUS_BLOCK_LEN) || + (*Length > MAX_SMBUS_BLOCK_LEN)) { + return EFI_INVALID_PARAMETER; + } + break; + case EfiSmbusBWBRProcessCall: + return EFI_UNSUPPORTED; + default: + return EFI_INVALID_PARAMETER; + } + return Status; +} + +/** + Executes an SMBus operation to an SMBus controller. Returns when either the command has been + executed or an error is encountered in doing the operation. + + The internal worker function provides a standard way to execute an operation as defined in the + System Management Bus (SMBus) Specification. The resulting transaction will be either that the + SMBus slave devices accept this transaction or that this function returns with error. + + @param SlaveAddress The SMBus slave address of the device with which to communicate. + @param Command This command is transmitted by the SMBus host controller to the + SMBus slave device and the interpretation is SMBus slave device + specific. It can mean the offset to a list of functions inside an + SMBus slave device. Not all operations or slave devices support + this command's registers. + @param Operation Signifies which particular SMBus hardware protocol instance that + it will use to execute the SMBus transactions. This SMBus + hardware protocol is defined by the SMBus Specification and is + not related to EFI. + @param PecCheck Defines if Packet Error Code (PEC) checking is required for this + operation. + @param Length Signifies the number of bytes that this operation will do. The + maximum number of bytes can be revision specific and operation + specific. This field will contain the actual number of bytes that + are executed for this operation. Not all operations require this + argument. + @param Buffer Contains the value of data to execute to the SMBus slave device. + Not all operations require this argument. The length of this + buffer is identified by Length. + + @retval EFI_SUCCESS The last data that was returned from the access matched the poll + exit criteria. + @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect). + @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is + determined by the SMBus host controller device. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The request was not completed because a failure that was + reflected in the Host Status Register bit. Device errors are a + result of a transaction collision, illegal command field, + unclaimed cycle (host initiated), or bus errors (collisions). + @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION. + @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead + and EfiSmbusQuickWrite. Length is outside the range of valid + values. + @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported. + @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation. + +**/ +EFI_STATUS +Execute ( + IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, + IN EFI_SMBUS_DEVICE_COMMAND Command, + IN EFI_SMBUS_OPERATION Operation, + IN BOOLEAN PecCheck, + IN OUT UINTN *Length, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN SmbusAddress; + UINTN WorkBufferLen; + UINT8 WorkBuffer[MAX_SMBUS_BLOCK_LEN]; + + Status = QncSmbusExecCheckParameters ( + SlaveAddress, + Command, + Operation, + PecCheck, + Length, + Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + SmbusAddress = SMBUS_LIB_ADDRESS (SlaveAddress.SmbusDeviceAddress, Command, *Length, PecCheck); + + switch (Operation) { + case EfiSmbusQuickRead: + SmBusQuickRead (SmbusAddress, &Status); + break; + case EfiSmbusQuickWrite: + SmBusQuickWrite (SmbusAddress, &Status); + break; + case EfiSmbusReceiveByte: + *(UINT8 *) Buffer = SmBusReceiveByte (SmbusAddress, &Status); + break; + case EfiSmbusSendByte: + SmBusSendByte (SmbusAddress, *(UINT8 *) Buffer, &Status); + break; + case EfiSmbusReadByte: + *(UINT8 *) Buffer = SmBusReadDataByte (SmbusAddress, &Status); + break; + case EfiSmbusWriteByte: + SmBusWriteDataByte (SmbusAddress, *(UINT8 *) Buffer, &Status); + break; + case EfiSmbusReadWord: + *(UINT16 *) Buffer = SmBusReadDataWord (SmbusAddress, &Status); + break; + case EfiSmbusWriteWord: + SmBusWriteDataWord (SmbusAddress, *(UINT16 *) Buffer, &Status); + break; + case EfiSmbusProcessCall: + *(UINT16 *) Buffer = SmBusProcessCall (SmbusAddress, *(UINT16 *) Buffer, &Status); + break; + case EfiSmbusReadBlock: + WorkBufferLen = SmBusReadBlock (SmbusAddress, WorkBuffer, &Status); + if (!EFI_ERROR (Status)) { + // + // Read block transaction is complete successfully, and then + // check whether the output buffer is large enough. + // + if (*Length >= WorkBufferLen) { + CopyMem (Buffer, WorkBuffer, WorkBufferLen); + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + *Length = WorkBufferLen; + } + break; + case EfiSmbusWriteBlock: + SmBusWriteBlock (ADD_LENGTH (SmbusAddress, *Length), Buffer, &Status); + break; + default: + break; + } + + return Status; +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c new file mode 100644 index 0000000000..a4617ccca2 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c @@ -0,0 +1,417 @@ +/** @file +This is the driver that implements the QNC S3 Support protocol + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "QncS3Support.h" + +// +// Global Variables +// +EFI_QNC_S3_SUPPORT_PROTOCOL mQncS3SupportProtocol; +QNC_S3_PARAMETER_HEADER *mS3Parameter; +UINT32 mQncS3ImageEntryPoint; +VOID *mQncS3ImageAddress; +UINTN mQncS3ImageSize; + +extern EFI_GUID gQncS3CodeInLockBoxGuid; +extern EFI_GUID gQncS3ContextInLockBoxGuid; + +/** + + Create a buffer that is used to store context information for use with + dispatch functions. + + @retval EFI_SUCCESS - Buffer allocated and initialized. + +**/ +EFI_STATUS +CreateContextBuffer ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + UINT32 ContextStoreSize; + + ContextStoreSize = EFI_PAGE_SIZE; + + // + // Allcoate <4G EfiReservedMemory + // + Address = 0xFFFFFFFF; + Status = gBS->AllocatePages (AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (ContextStoreSize), &Address); + if (EFI_ERROR (Status)) { + return Status; + } + mS3Parameter = (QNC_S3_PARAMETER_HEADER *) (UINTN) Address; + + // + // Determine the maximum number of context entries that can be stored in this + // table. + // + mS3Parameter->MaxContexts = ((ContextStoreSize - sizeof(QNC_S3_PARAMETER_HEADER)) / sizeof(EFI_DISPATCH_CONTEXT_UNION)) + 1; + mS3Parameter->StorePosition = 0; + + return Status; +} + +// +// Functions +// +EFI_STATUS +EFIAPI +QncS3SupportEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + + Routine Description: + + QNC S3 support driver entry point + + Arguments: + + ImageHandle - Handle for the image of this driver + SystemTable - Pointer to the EFI System Table + + Returns: + + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + VOID *TmpPtr; + EFI_EVENT Event; + + // + // If the protocol is found execution is happening in ACPI NVS memory. If it + // is not found copy the driver into ACPI NVS memory and pass control to it. + // + Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &TmpPtr); + + // + // Load the QNC S3 image + // + if (EFI_ERROR (Status)) { + Status = LoadQncS3Image (SystemTable); + ASSERT_EFI_ERROR (Status); + + } else { + DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - Begin\n")); + // + // Allocate and initialize context buffer. + // + Status = CreateContextBuffer (); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Install the QNC S3 Support protocol + // + mQncS3SupportProtocol.SetDispatchItem = QncS3SetDispatchItem; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiQncS3SupportProtocolGuid, + &mQncS3SupportProtocol, + NULL + ); + + mQncS3ImageAddress = (VOID *)(UINTN)PcdGet64(PcdQncS3CodeInLockBoxAddress); + mQncS3ImageSize = (UINTN)PcdGet64(PcdQncS3CodeInLockBoxSize); + DEBUG ((DEBUG_INFO, "QncS3SupportEntry Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize)); + DEBUG ((DEBUG_INFO, "QncS3SupportEntry Contex = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE)); + ASSERT (mQncS3ImageAddress != 0); + + // + // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + QncS3BootEvent, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - End\n")); + } + + + + return Status; +} + +EFI_STATUS +EFIAPI +QncS3SetDispatchItem ( + IN EFI_QNC_S3_SUPPORT_PROTOCOL *This, + IN EFI_QNC_S3_DISPATCH_ITEM *DispatchItem, + OUT VOID **S3DispatchEntryPoint, + OUT VOID **Context + ) +/*++ + +Routine Description: + + Set an item to be dispatched at S3 resume time. At the same time, the entry point + of the QNC S3 support image is returned to be used in subsequent boot script save + call + +Arguments: + + This - Pointer to the protocol instance. + DispatchItem - The item to be dispatched. + S3DispatchEntryPoint - The entry point of the QNC S3 support image. + +Returns: + + EFI_STATUS - Successfully completed. + EFI_OUT_OF_RESOURCES - Out of resources. + +--*/ +{ + + DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() Start\n")); + + // + // Set default values. + // + *S3DispatchEntryPoint = NULL; + *Context = NULL; + + // + // Determine if this entry will fit. + // + if (mS3Parameter->StorePosition >= mS3Parameter->MaxContexts) { + DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem exceeds max length - 0x%08x\n", (UINTN)mS3Parameter->MaxContexts)); + return EFI_OUT_OF_RESOURCES; + } + // + // Calculate the size required; + // ** Always round up to be 8 byte aligned + // + switch (DispatchItem->Type) { + case QncS3ItemTypeInitPcieRootPortDownstream: + *S3DispatchEntryPoint = (VOID*) (UINTN)QncS3InitPcieRootPortDownstream; + *Context = &mS3Parameter->Contexts[mS3Parameter->StorePosition]; + CopyMem (&mS3Parameter->Contexts[mS3Parameter->StorePosition], DispatchItem->Parameter, sizeof(UINT32)); + DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream @ 0x%08x - context 0x%08x\n", (UINTN)*S3DispatchEntryPoint, (UINTN)*Context)); + break; + + default: + return EFI_UNSUPPORTED; + + } + + mS3Parameter->StorePosition ++; + DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() End\n")); + + return EFI_SUCCESS; +} + +EFI_STATUS +LoadQncS3Image ( + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Load the QNC S3 Image into Efi Reserved Memory below 4G. + +Arguments: + + ImageEntryPoint the ImageEntryPoint after success loading + +Returns: + + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + UINT8 *Buffer; + UINTN BufferSize; + VOID *FfsBuffer; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_HANDLE NewImageHandle; + + // + // Install NULL protocol on module file handle to indicate that the entry point + // has been called for the first time. + // + NewImageHandle = NULL; + Status = gBS->InstallProtocolInterface ( + &NewImageHandle, + &gEfiCallerIdGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + + + // + // Find this module so it can be loaded again. + // + Status = GetSectionFromAnyFv ( + &gEfiCallerIdGuid, + EFI_SECTION_PE32, + 0, + (VOID**) &Buffer, + &BufferSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + + // + // Get information about the image being loaded. + // + ImageContext.Handle = Buffer; + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->AllocatePool ( + EfiReservedMemoryType, + BufferSize + ImageContext.SectionAlignment, + &FfsBuffer + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for no enough space! \n")); + return EFI_OUT_OF_RESOURCES; + } + + mQncS3ImageAddress = FfsBuffer; + mQncS3ImageSize = BufferSize + ImageContext.SectionAlignment; + Status = PcdSet64S (PcdQncS3CodeInLockBoxAddress, (UINT64)(UINTN)mQncS3ImageAddress); + ASSERT_EFI_ERROR (Status); + Status = PcdSet64S (PcdQncS3CodeInLockBoxSize, (UINT64)mQncS3ImageSize); + ASSERT_EFI_ERROR (Status); + // + // Align buffer on section boundary + // + ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; + if (ImageContext.SectionAlignment != 0) { + ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; + ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); + } + + // + // Load the image to our new buffer + // + Status = PeCoffLoaderLoadImage (&ImageContext); + if (EFI_ERROR (Status)) { + gBS->FreePool (FfsBuffer); + DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderLoadImage failure! \n")); + return Status; + } + + // + // Relocate the image in our new buffer + // + Status = PeCoffLoaderRelocateImage (&ImageContext); + if (EFI_ERROR (Status)) { + PeCoffLoaderUnloadImage (&ImageContext); + gBS->FreePool (FfsBuffer); + DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderRelocateImage failure! \n")); + return Status; + } + + // + // Invalidate instruction cache and pass control to the image. This will perform + // the initialization of the module and publish the supporting protocols. + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); + Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); + if (EFI_ERROR (Status)) { + gBS->FreePool (FfsBuffer); + return Status; + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +QncS3InitPcieRootPortDownstream ( + IN EFI_HANDLE ImageHandle, + IN VOID *Context + ) +/*++ + + Routine Description: + Perform Init Root Port Downstream devices on S3 resume + + Arguments: + Parameter Parameters passed in from DXE + + Returns: + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() Begin\n")); + + // + // Initialize the device behind the root port. + // + Status = PciExpressInit (); + + // + // Not checking the error status here - downstream device not present does not + // mean an error of this root port. Our return status of EFI_SUCCESS means this + // port is enabled and outer function depends on this return status to do + // subsequent initializations. + // + + if (Status != EFI_SUCCESS){ + DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() failed\n")); + } + + DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() End\n")); + return Status; +} + +VOID +EFIAPI +QncS3BootEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // These 2 boxes will be restored by RestoreAllLockBoxInPlace in S3Resume automatically + // + DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize)); + SaveLockBox(&gQncS3CodeInLockBoxGuid, mQncS3ImageAddress, mQncS3ImageSize); + Status = SetLockBoxAttributes (&gQncS3CodeInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Context = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE)); + SaveLockBox(&gQncS3ContextInLockBoxGuid, (VOID *)mS3Parameter, EFI_PAGE_SIZE); + Status = SetLockBoxAttributes (&gQncS3ContextInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h new file mode 100644 index 0000000000..a126e38b7f --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.h @@ -0,0 +1,117 @@ +/** @file +Header file for QNC S3 Support driver + +This file includes package header files, library classes and protocol, PPI & GUID definitions. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _QNC_S3_SUPPORT_H_ +#define _QNC_S3_SUPPORT_H_ + +// +// External include files do NOT need to be explicitly specified in real EDKII +// environment +// +// +// Driver Consumed Protocol Prototypes +// +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf new file mode 100644 index 0000000000..0e12a2c594 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf @@ -0,0 +1,64 @@ +## @file +# Component description file for Qnc Initialization driver +# +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = QncS3Support + FILE_GUID = C7EA9787-CA0A-43b4-B1E5-25EF87391F8D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = QncS3SupportEntryPoint +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + QncS3Support.h + QncS3Support.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + IoLib + DebugLib + DxeServicesLib + BaseMemoryLib + UefiDriverEntryPoint + PeCoffLib + LockBoxLib + S3BootScriptLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + CacheMaintenanceLib + IntelQNCLib + +[Protocols] + gEfiQncS3SupportProtocolGuid ## PRODUCES + gEfiLoadPeImageProtocolGuid ## CONSUMES + gEfiFirmwareVolume2ProtocolGuid ## CONSUMES + +[Guids] + gQncS3CodeInLockBoxGuid + gQncS3ContextInLockBoxGuid + gEfiEndOfDxeEventGroupGuid + +[Pcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxSize + +[Depex] + gEfiFirmwareVolume2ProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf new file mode 100644 index 0000000000..405e9eb7fd --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf @@ -0,0 +1,49 @@ +## @file +# Component description file for SmmAccess module +# +# Copyright (c) 2013-2019 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmAccess + FILE_GUID = 274F0C8F-9E57-41d8-9966-29CCD48D31C2 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SmmAccessDriverEntryPoint + +[Sources] + SmmAccessDriver.h + SmmAccessDriver.c + +[Packages] + MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + HobLib + DebugLib + UefiLib + BaseLib + BaseMemoryLib + S3BootScriptLib + UefiDriverEntryPoint + UefiBootServicesTableLib + DxeServicesTableLib + PcdLib + SmmLib + +[Protocols] + gEfiPciRootBridgeIoProtocolGuid + gEfiSmmAccess2ProtocolGuid + +[Guids] + gEfiSmmPeiSmramMemoryReserveGuid + +[Depex] + gEfiPciRootBridgeIoProtocolGuid diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c new file mode 100644 index 0000000000..830f8b83c3 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c @@ -0,0 +1,405 @@ +/** @file +This is the driver that publishes the SMM Access Protocol +instance for the Tylersburg chipset. + +Copyright (c) 2013-2019 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SmmAccessDriver.h" + + + +SMM_ACCESS_PRIVATE_DATA mSmmAccess; + +VOID +SmmAccessOnBoot ( + IN EFI_EVENT Event, + IN VOID *Context +); + +EFI_STATUS +EFIAPI +SmmAccessDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Installs an SMM Access Protocol. + +Arguments: + + ImageHandle - Handle for the image of this driver. + SystemTable - Pointer to the EFI System Table. + +Returns: + + EFI_SUCCESS - Protocol successfully started and installed. + EFI_UNSUPPORTED - Protocol can't be started. + EFI_NOT_FOUND - Protocol not found. +--*/ +{ + + EFI_STATUS Status; + EFI_EVENT BootEvent; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + UINTN Index; + EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock; + EFI_HOB_GUID_TYPE *GuidHob; + + + // + // Initialize private data + // + ZeroMem (&mSmmAccess, sizeof (mSmmAccess)); + + Status = gBS->LocateProtocol ( + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + (VOID **) &PciRootBridgeIo + ); + ASSERT_EFI_ERROR (Status); + + // + // Build SMM related information + // + mSmmAccess.Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE; + mSmmAccess.Handle = NULL; + mSmmAccess.PciRootBridgeIo = PciRootBridgeIo; + + // + // Get Hob list + // + GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid); + DescriptorBlock = GET_GUID_HOB_DATA (GuidHob); + ASSERT (DescriptorBlock); + + + // + // Get CPU Max bus number + // + mSmmAccess.MaxBusNumber = PCI_BUS_NUMBER_QNC; + for (Index = 0; Index < MAX_CPU_SOCKET; Index++) { + mSmmAccess.SocketPopulated[Index] = TRUE; + } + + // + // Use the hob to publish SMRAM capabilities + // + ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES); + for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) { + mSmmAccess.SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart; + mSmmAccess.SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart; + mSmmAccess.SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize; + mSmmAccess.SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState; + DEBUG ((EFI_D_INFO, "SM RAM index[%d] startaddr:%08X Size :%08X\n", Index, mSmmAccess.SmramDesc[Index].CpuStart, + mSmmAccess.SmramDesc[Index].PhysicalSize)); + } + + mSmmAccess.NumberRegions = Index; + mSmmAccess.SmmAccess.Open = Open; + mSmmAccess.SmmAccess.Close = Close; + mSmmAccess.SmmAccess.Lock = Lock; + mSmmAccess.SmmAccess.GetCapabilities = GetCapabilities; + mSmmAccess.SmmAccess.LockState = FALSE; + mSmmAccess.SmmAccess.OpenState = FALSE; + mSmmAccess.SMMRegionState = EFI_SMRAM_CLOSED; + + // + // Install our protocol interfaces on the device's handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSmmAccess.Handle, + &gEfiSmmAccess2ProtocolGuid, + &mSmmAccess.SmmAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_INFO, "SMM Base: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalStart))); + DEBUG ((EFI_D_INFO, "SMM Size: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize))); + + mSmmAccess.TsegSize = (UINT8)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize); + // + // T Seg setting done in QPI RC + // + + // + // Prior ReadyToBoot, lock CSEG + // + Status = EfiCreateEventReadyToBootEx( + TPL_NOTIFY, + SmmAccessOnBoot, + NULL, + &BootEvent ); + ASSERT (!EFI_ERROR (Status)); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +Open ( + IN EFI_SMM_ACCESS2_PROTOCOL *This + ) +/*++ + +Routine Description: + + This routine accepts a request to "open" a region of SMRAM. The + region could be legacy ABSEG, HSEG, or TSEG near top of physical memory. + The use of "open" means that the memory is visible from all boot-service + and SMM agents. + +Arguments: + + This - Pointer to the SMM Access Interface. + DescriptorIndex - Region of SMRAM to Open. + +Returns: + + EFI_SUCCESS - The region was successfully opened. + EFI_DEVICE_ERROR - The region could not be opened because locked by + chipset. + EFI_INVALID_PARAMETER - The descriptor index was out of bounds. + +--*/ +{ + SMM_ACCESS_PRIVATE_DATA *SmmAccess; + + SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); + + if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) { + DEBUG ((EFI_D_ERROR, "Cannot open a locked SMRAM region\n")); + return EFI_DEVICE_ERROR; + } + + // + // Open TSEG + // + if (!QNCOpenSmramRegion ()) { + mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED; + return EFI_DEVICE_ERROR; + } + + mSmmAccess.SMMRegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED); + SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EFI_ALLOCATED))); + mSmmAccess.SMMRegionState |= EFI_SMRAM_OPEN; + SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN); + SmmAccess->SmmAccess.OpenState = TRUE; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +Close ( + IN EFI_SMM_ACCESS2_PROTOCOL *This + ) +/*++ + +Routine Description: + + This routine accepts a request to "close" a region of SMRAM. This is valid for + compatible SMRAM region. + +Arguments: + + This - Pointer to the SMM Access Interface. + DescriptorIndex - Region of SMRAM to Close. + +Returns: + + EFI_SUCCESS - The region was successfully closed. + EFI_DEVICE_ERROR - The region could not be closed because locked by + chipset. + EFI_INVALID_PARAMETER - The descriptor index was out of bounds. + +--*/ +{ + EFI_STATUS Status; + SMM_ACCESS_PRIVATE_DATA *SmmAccess; + BOOLEAN OpenState; + UINTN Index; + + SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); + + if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) { + // + // Cannot close a "locked" region + // + DEBUG ((EFI_D_WARN, "Cannot close the locked SMRAM Region\n")); + return EFI_DEVICE_ERROR; + } + + if (mSmmAccess.SMMRegionState & EFI_SMRAM_CLOSED) { + return EFI_DEVICE_ERROR; + } + + // + // Reset SMRAM cacheability to UC + // + for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) { + DEBUG ((DEBUG_INFO, "SmmAccess->Close: Set to UC Base=%016lx Size=%016lx\n", SmmAccess->SmramDesc[Index].CpuStart, SmmAccess->SmramDesc[Index].PhysicalSize)); + Status = gDS->SetMemorySpaceAttributes( + SmmAccess->SmramDesc[Index].CpuStart, + SmmAccess->SmramDesc[Index].PhysicalSize, + EFI_MEMORY_UC + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "SmmAccess: Failed to reset SMRAM window to EFI_MEMORY_UC\n")); + } + } + + // + // Close TSEG + // + if (!QNCCloseSmramRegion ()) { + mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED; + return EFI_DEVICE_ERROR; + } + + mSmmAccess.SMMRegionState &= ~EFI_SMRAM_OPEN; + SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN)); + mSmmAccess.SMMRegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED); + SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED); + + // + // Find out if any regions are still open + // + OpenState = FALSE; + for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) { + if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) { + OpenState = TRUE; + } + } + + SmmAccess->SmmAccess.OpenState = OpenState; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +Lock ( + IN EFI_SMM_ACCESS2_PROTOCOL *This + ) +/*++ + +Routine Description: + + This routine accepts a request to "lock" SMRAM. The + region could be legacy AB or TSEG near top of physical memory. + The use of "lock" means that the memory can no longer be opened + to BS state.. + +Arguments: + + This - Pointer to the SMM Access Interface. + DescriptorIndex - Region of SMRAM to Lock. + +Returns: + + EFI_SUCCESS - The region was successfully locked. + EFI_DEVICE_ERROR - The region could not be locked because at least + one range is still open. + EFI_INVALID_PARAMETER - The descriptor index was out of bounds. + +--*/ +{ + SMM_ACCESS_PRIVATE_DATA *SmmAccess; + + SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); + + if (SmmAccess->SmmAccess.OpenState) { + return EFI_DEVICE_ERROR; + } + + mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED; + SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED); + SmmAccess->SmmAccess.LockState = TRUE; + + // + // Lock TSEG + // + QNCLockSmramRegion (); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GetCapabilities ( + IN CONST EFI_SMM_ACCESS2_PROTOCOL *This, + IN OUT UINTN *SmramMapSize, + IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap + ) +/*++ + +Routine Description: + + This routine services a user request to discover the SMRAM + capabilities of this platform. This will report the possible + ranges that are possible for SMRAM access, based upon the + memory controller capabilities. + +Arguments: + + This - Pointer to the SMRAM Access Interface. + SmramMapSize - Pointer to the variable containing size of the + buffer to contain the description information. + SmramMap - Buffer containing the data describing the Smram + region descriptors. +Returns: + + EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer. + EFI_SUCCESS - The user provided a sufficiently-sized buffer. + +--*/ +{ + EFI_STATUS Status; + SMM_ACCESS_PRIVATE_DATA *SmmAccess; + UINTN BufferSize; + + SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); + BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR); + + if (*SmramMapSize < BufferSize) { + Status = EFI_BUFFER_TOO_SMALL; + } else { + CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize); + Status = EFI_SUCCESS; + } + *SmramMapSize = BufferSize; + + return Status; +} + +VOID +SmmAccessOnBoot ( + IN EFI_EVENT Event, + IN VOID *Context +) +{ + +} +VOID +SyncRegionState2SmramDesc( + IN BOOLEAN OrAnd, + IN UINT64 Value + ) +{ + UINT32 Index; + + for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) { + if (OrAnd) { + mSmmAccess.SmramDesc[Index].RegionState |= Value; + } else { + mSmmAccess.SmramDesc[Index].RegionState &= Value; + } + } +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h new file mode 100644 index 0000000000..aca169d3e2 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h @@ -0,0 +1,230 @@ +/** @file +Header file for SMM Access Driver. + +This file includes package header files, library classes and protocol, PPI & GUID definitions. + +Copyright (c) 2013-2019 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _SMM_ACCESS_DRIVER_H +#define _SMM_ACCESS_DRIVER_H + +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c new file mode 100644 index 0000000000..a3e992848f --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c @@ -0,0 +1,358 @@ +/** @file +This module produces the SMM COntrol2 Protocol for QNC + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#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 GPE0BLK_Base; + + // + // Get GPE0BLK_Base + // + GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress); + + // + // Clear the Power Button Override Status Bit, it gates EOS from being set. + // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing. + // + + // + // Clear the APM SMI Status Bit + // + IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM); + + // + // Set the EOS Bit + // + IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS); + + return EFI_SUCCESS; +} + +/** + Generates an SMI using the parameters passed in. + + @param This A pointer to an instance of + EFI_SMM_CONTROL_PROTOCOL + @param ArgumentBuffer The argument buffer + @param ArgumentBufferSize The size of the argument buffer + @param Periodic TRUE to indicate a periodical SMI + @param ActivationInterval Interval of the periodical SMI + + @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1 + @retval EFI_SUCCESS SMI generated + +**/ +EFI_STATUS +EFIAPI +Activate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN OUT UINT8 *CommandPort OPTIONAL, + IN OUT UINT8 *DataPort OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN EFI_SMM_PERIOD ActivationInterval OPTIONAL + ) +{ + UINT16 GPE0BLK_Base; + UINT32 NewValue; + + // + // Get GPE0BLK_Base + // + GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress); + + if (Periodic) { + return EFI_INVALID_PARAMETER; + } + + // + // Clear any pending the APM SMI + // + if (EFI_ERROR (SmmClear())) { + return EFI_DEVICE_ERROR; + } + + // + // Enable the APMC SMI + // + IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM); + + // + // Enable SMI globally + // + NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); + NewValue |= SMI_EN; + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue); + + + // + // Set APMC_STS + // + if (DataPort == NULL) { + IoWrite8 (PcdGet16 (PcdSmmDataPort), 0xFF); + } else { + IoWrite8 (PcdGet16 (PcdSmmDataPort), *DataPort); + } + + // + // Generate the APMC SMI + // + if (CommandPort == NULL) { + IoWrite8 (PcdGet16 (PcdSmmActivationPort), 0xFF); + } else { + IoWrite8 (PcdGet16 (PcdSmmActivationPort), *CommandPort); + } + + return EFI_SUCCESS; +} + +/** + Clears an SMI. + + @param This Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL + @param Periodic TRUE to indicate a periodical SMI + + @return Return value from SmmClear() + +**/ +EFI_STATUS +EFIAPI +Deactivate ( + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, + IN BOOLEAN Periodic + ) +{ + if (Periodic) { + return EFI_INVALID_PARAMETER; + } + + return SmmClear(); +} + +/** + This is the constructor for the SMM Control protocol. + + This function installs EFI_SMM_CONTROL2_PROTOCOL. + + @param ImageHandle Handle for the image of this driver + @param SystemTable Pointer to the EFI System Table + + @retval EFI_UNSUPPORTED There's no Intel ICH on this platform + @return The status returned from InstallProtocolInterface(). + +--*/ +EFI_STATUS +SmmControl2Init ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + UINT16 PM1BLK_Base; + UINT16 GPE0BLK_Base; + BOOLEAN SciEn; + UINT32 NewValue; + + // + // Get PM1BLK_Base & GPE0BLK_Base + // + PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress); + GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress); + + // + // Install our protocol interfaces on the device's handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSmmControl2Handle, + &gEfiSmmControl2ProtocolGuid, &mSmmControl2, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Determine whether an ACPI OS is present (via the SCI_EN bit) + // + SciEn = (BOOLEAN)((IoRead16 (PM1BLK_Base + R_QNC_PM1BLK_PM1C) & B_QNC_PM1BLK_PM1C_SCIEN) != 0); + if (!SciEn) { + // + // Clear any SMIs that double as SCIs (when SCI_EN==0) + // + IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1S), B_QNC_PM1BLK_PM1S_ALL); + IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1E), 0x00000000); + IoWrite32 ((PM1BLK_Base + R_QNC_PM1BLK_PM1C), 0x00000000); + IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0S), B_QNC_GPE0BLK_GPE0S_ALL); + IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0E), 0x00000000); + } + + // + // Clear and disable all SMIs that are unaffected by SCI_EN + // Set EOS + // + IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), 0x00000000); + IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), (B_QNC_GPE0BLK_SMIS_EOS + B_QNC_GPE0BLK_SMIS_ALL)); + + // + // Enable SMI globally + // + NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); + NewValue |= SMI_EN; + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue); + + // + // Make sure to write this register last -- EOS re-enables SMIs for the QNC + // + IoAndThenOr32 ( + GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, + (UINT32)(~B_QNC_GPE0BLK_SMIE_ALL), + B_QNC_GPE0BLK_SMIE_APM + ); + + // + // Make sure EOS bit cleared + // + DEBUG_CODE_BEGIN (); + if (IoRead32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS) & B_QNC_GPE0BLK_SMIS_EOS) { + DEBUG (( + EFI_D_ERROR, + "******************************************************************************\n" + "BIG ERROR: SmmControl constructor couldn't properly initialize the ACPI table.\n" + " SmmControl->Clear will probably hang. \n" + " NOTE: SCI_EN = %d \n" + "******************************************************************************\n", + SciEn + )); + + // + // If we want the system to stop, then keep the ASSERT(FALSE). + // Otherwise, comment it out. + // + ASSERT (FALSE); + } + DEBUG_CODE_END (); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SmmControlVirtualddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf new file mode 100644 index 0000000000..1367f0a1f4 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf @@ -0,0 +1,55 @@ +## @file +# QNC SmmControl driver to install EFI_SMM_CONTROL_PROTOCOL. +# +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmControlDxe + FILE_GUID = A03A9429-C570-4ef9-9E00-C7A673976E5F + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SmmControl2Init + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SmmControlDriver.c + +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + DebugLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + PcdLib + IoLib + PciLib + QNCAccessLib + +[Protocols] + gEfiSmmControl2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + +[Pcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress + +[Guids] + gEfiEventVirtualAddressChangeGuid + +[Depex] + TRUE diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h new file mode 100644 index 0000000000..c8bead8081 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h @@ -0,0 +1,45 @@ +/** @file +Common header file shared by all source files. + +This file includes package header files, library classes and protocol, PPI & GUID definitions. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef __COMMON_HEADER_H_ +#define __COMMON_HEADER_H_ + + + +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c new file mode 100644 index 0000000000..98c9c0690c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c @@ -0,0 +1,32 @@ +/** @file +File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmmHelpers.h" + +CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC = { + QNC_SMM_NO_FLAGS, + { + { + {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_GPIO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_GPIO + } + } +}; + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c new file mode 100644 index 0000000000..5d01c9ef3d --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c @@ -0,0 +1,549 @@ +/** @file + +This driver is responsible for the registration of child drivers +and the abstraction of the QNC SMI sources. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmmHelpers.h" + +// +// Help handle porting bit shifts to IA-64. +// +#define BIT_ZERO 0x00000001 + + +VOID +QNCSmmPublishDispatchProtocols( + VOID + ) +{ + UINTN Index; + EFI_STATUS Status; + + // + // Install protocol interfaces. + // + for (Index = 0; Index < NUM_PROTOCOLS; Index++) { + Status = gSmst->SmmInstallProtocolInterface ( + &mPrivateData.InstallMultProtHandle, + mPrivateData.Protocols[Index].Guid, + EFI_NATIVE_INTERFACE, + &mPrivateData.Protocols[Index].Protocols.Generic + ); + + ASSERT_EFI_ERROR (Status); +} +} + +EFI_STATUS +QNCSmmInitHardware( + VOID + ) +/*++ + +Routine Description: + + Initialize bits that aren't necessarily related to an SMI source. + +Dependencies: + + gSmst - SMM System Table; contains an entry for SMM CPU IO + +Returns: + + EFI_SUCCESS. Asserts, otherwise. + +--*/ +{ + EFI_STATUS Status; + + // + // Clear all SMIs + // + QNCSmmClearSmi(); + + Status = QNCSmmEnableGlobalSmiBit (); + ASSERT_EFI_ERROR (Status); + + // + // Be *really* sure to clear all SMIs + // + QNCSmmClearSmi (); + + return EFI_SUCCESS; +} + +EFI_STATUS +QNCSmmEnableGlobalSmiBit ( + VOID + ) +/*++ + +Routine Description: + + Enables the QNC to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + +Arguments: + + None + +Returns: + + EFI_SUCCESS. + Asserts, otherwise. + +--*/ +{ + UINT32 NewValue; + + // + // Enable SMI globally + // + NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); + NewValue |= SMI_EN; + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue); + + return EFI_SUCCESS; +} + +EFI_STATUS +QNCSmmClearSmi( + VOID + ) +/*++ + +Routine Description: + + Clears the SMI after all SMI source have been processed. + Note that this function will not work correctly (as it is + written) unless all SMI sources have been processed. + A revision of this function could manually clear all SMI + status bits to guarantee success. + +Returns: + + EFI_SUCCESS. + Asserts, otherwise. + +--*/ +{ + BOOLEAN EosSet; + BOOLEAN SciEn; + + UINT32 Pm1Cnt = 0; + UINT16 Pm1Sts = 0; + UINT32 Gpe0Sts = 0; + UINT32 SmiSts = 0; + + // + // Determine whether an ACPI OS is present (via the SCI_EN bit) + // + Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); + SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN); + + if (SciEn == FALSE) { + + // + // Clear any SMIs that double as SCIs (when SCI_EN==0) + // + Pm1Sts = (B_QNC_PM1BLK_PM1S_WAKE | B_QNC_PM1BLK_PM1S_PCIEWSTS | B_QNC_PM1BLK_PM1S_RTC | B_QNC_PM1BLK_PM1S_GLOB | B_QNC_PM1BLK_PM1S_TO); + + Gpe0Sts = B_QNC_GPE0BLK_GPE0S_ALL; + + IoOr16((PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S), Pm1Sts); + IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S), Gpe0Sts); + } + + // + // Clear all SMIs that are unaffected by SCI_EN + // + SmiSts = IoRead32((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS); + SmiSts |= B_QNC_GPE0BLK_SMIS_ALL; + IoWrite32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), SmiSts); + + // + // Try to clear the EOS bit. ASSERT on an error + // + EosSet = QNCSmmSetAndCheckEos(); + ASSERT (EosSet); + + return EFI_SUCCESS; +} + +BOOLEAN +QNCSmmSetAndCheckEos( + VOID + ) +{ + // + // Reset the QNC to generate subsequent SMIs + // + IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS); + return TRUE; +} + +BOOLEAN +QNCSmmGetSciEn( + ) +{ + BOOLEAN SciEn; + UINT32 Pm1Cnt; + + // + // Determine whether an ACPI OS is present (via the SCI_EN bit) + // + Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); + + SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN); + + return SciEn; +} + +// +// These may or may not need to change w/ the QNC version; they're highly IA-32 dependent, though. +// + +BOOLEAN +ReadBitDesc ( + CONST QNC_SMM_BIT_DESC *BitDesc + ) +{ + UINT64 Register; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + BOOLEAN BitWasOne; + + ASSERT (BitDesc != NULL ); + ASSERT (!IS_BIT_DESC_NULL( *BitDesc ) ); + + Register = 0; + BitWasOne = FALSE; + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + // + // Double check that we correctly read in the acpi base address + // + ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1) ); + + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE ); + break; + + case 1: + Register = (UINT64) IoRead8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi); + break; + + case 2: + Register = (UINT64) IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi); + break; + + case 4: + Register = (UINT64) IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE ); + break; + }; + + if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case GPE_ADDR_TYPE: + // + // Double check that we correctly read in the gpe base address + // + ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1) ); + + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE ); + break; + + case 1: + Register = (UINT64) IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe); + break; + + case 2: + Register = (UINT64) IoRead16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe); + break; + + case 4: + Register = (UINT64) IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE ); + break; + }; + + if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + // + // Read the register, and it with the bit to read + // + + // + // This code does not support reads greater then 64 bits + // + ASSERT (BitDesc->SizeInBytes <= 8); + CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes); + Register &= LShiftU64 (BIT0, BitDesc->Bit); + if (Register) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case PCI_ADDR_TYPE: + PciBus = BitDesc->Reg.Data.pci.Fields.Bus; + PciDev = BitDesc->Reg.Data.pci.Fields.Dev; + PciFun = BitDesc->Reg.Data.pci.Fields.Fnc; + PciReg = BitDesc->Reg.Data.pci.Fields.Reg; + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + ASSERT (FALSE ); + break; + + case 1: + Register = (UINT64) PciRead8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg)); + break; + + case 2: + Register = (UINT64) PciRead16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg)); + break; + + case 4: + Register = (UINT64) PciRead32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg)); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE ); + break; + }; + + if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + default: + // + // This address type is not yet implemented + // + ASSERT (FALSE ); + break; + }; + + return BitWasOne; +} + +VOID +WriteBitDesc ( + CONST QNC_SMM_BIT_DESC *BitDesc, + CONST BOOLEAN ValueToWrite + ) +{ + UINT64 Register; + UINT64 AndVal; + UINT64 OrVal; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + + ASSERT (BitDesc != NULL); + ASSERT (!IS_BIT_DESC_NULL(*BitDesc)); + + AndVal = ~(BIT_ZERO << (BitDesc->Bit)); + OrVal = ((UINT32)ValueToWrite) << (BitDesc->Bit); + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + // + // Double check that we correctly read in the acpi base address + // + ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1)); + + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE ); + break; + + case 1: + IoAndThenOr8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT8)AndVal, (UINT8)OrVal); + break; + + case 2: + IoAndThenOr16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT16)AndVal, (UINT16)OrVal); + break; + + case 4: + IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT32)AndVal, (UINT32)OrVal); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE ); + break; + }; + break; + + case GPE_ADDR_TYPE: + // + // Double check that we correctly read in the gpe base address + // + ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1)); + + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized. + // Check your assignments to bit descriptions. + // + ASSERT (FALSE ); + break; + + case 1: + IoAndThenOr8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT8)AndVal, (UINT8)OrVal); + break; + + case 2: + IoAndThenOr16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT16)AndVal, (UINT16)OrVal); + break; + + case 4: + IoAndThenOr32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT32)AndVal, (UINT32)OrVal); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE ); + break; + }; + break; + + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + // + // Read the register, or it with the bit to set, then write it back. + // + + // + // This code does not support writes greater then 64 bits + // + ASSERT (BitDesc->SizeInBytes <= 8); + CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes); + Register &= AndVal; + Register |= OrVal; + CopyMem (BitDesc->Reg.Data.Mmio, &Register, BitDesc->SizeInBytes); + break; + + case PCI_ADDR_TYPE: + PciBus = BitDesc->Reg.Data.pci.Fields.Bus; + PciDev = BitDesc->Reg.Data.pci.Fields.Dev; + PciFun = BitDesc->Reg.Data.pci.Fields.Fnc; + PciReg = BitDesc->Reg.Data.pci.Fields.Reg; + switch (BitDesc->SizeInBytes) { + + case 0: + // + // Chances are that this field didn't get initialized -- check your assignments + // to bit descriptions. + // + ASSERT (FALSE ); + break; + + case 1: + PciAndThenOr8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal); + break; + + case 2: + PciAndThenOr16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal); + break; + + case 4: + PciAndThenOr32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal); + break; + + default: + // + // Unsupported or invalid register size + // + ASSERT (FALSE ); + break; + }; + break; + + default: + // + // This address type is not yet implemented + // + ASSERT (FALSE ); + break; + }; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c new file mode 100644 index 0000000000..b0825bde9d --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c @@ -0,0 +1,424 @@ +/** @file +File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmmHelpers.h" + +typedef enum { + PERIODIC_TIMER = 0, + NUM_TIMERS +} SUPPORTED_TIMER; + +typedef struct _TIMER_INTERVAL +{ + UINT64 Interval; + UINT8 AssociatedTimer; +} TIMER_INTERVAL; + +// +// Time constants, in 100 nano-second units +// +#define TIME_64s 640000000 /* 64 s */ +#define TIME_32s 320000000 /* 32 s */ +#define TIME_16s 160000000 /* 16 s */ +#define TIME_8s 80000000 /* 8 s */ +#define TIME_64ms 640000 /* 64 ms */ +#define TIME_32ms 320000 /* 32 ms */ +#define TIME_16ms 160000 /* 16 ms */ +#define TIME_1_5ms 15000 /* 1.5 ms */ + +// PMCW (GPE+28h) [2:0] Periodic SMI Rate selection +// 000 1.5ms +// 001 16ms +// 010 32ms +// 011 64ms +// 100 8s +// 101 16s +// 110 32s +// 111 64s + +typedef enum { + INDEX_TIME_1_5ms = 0, + INDEX_TIME_16ms, + INDEX_TIME_32ms, + INDEX_TIME_64ms, + INDEX_TIME_8s, + INDEX_TIME_16s, + INDEX_TIME_32s, + INDEX_TIME_64s, + INDEX_TIME_MAX +} TIMER_INTERVAL_INDEX; + +TIMER_INTERVAL mSmmPeriodicTimerIntervals[INDEX_TIME_MAX] = { + {TIME_1_5ms, PERIODIC_TIMER}, + {TIME_16ms, PERIODIC_TIMER}, + {TIME_32ms, PERIODIC_TIMER}, + {TIME_64ms, PERIODIC_TIMER}, + { TIME_8s, PERIODIC_TIMER }, + {TIME_16s, PERIODIC_TIMER}, + {TIME_32s, PERIODIC_TIMER}, + {TIME_64s, PERIODIC_TIMER} +}; + +typedef struct _TIMER_INFO { + UINTN NumChildren; // number of children using this timer + UINT64 MinReqInterval; // minimum interval required by children + UINTN CurrentSetting; // interval this timer is set at right now (index into interval table) +} TIMER_INFO; + +TIMER_INFO mTimers[NUM_TIMERS]; + +QNC_SMM_SOURCE_DESC mTIMER_SOURCE_DESCS[NUM_TIMERS] = { + { + QNC_SMM_NO_FLAGS, + { + {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SWT}, + NULL_BIT_DESC_INITIALIZER + }, + { + {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SWT} + } + } +}; + +VOID +QNCSmmPeriodicTimerProgramTimers( + VOID + ); + + +TIMER_INTERVAL * +ContextToTimerInterval ( + IN QNC_SMM_CONTEXT *RegisterContext + ) +{ + UINTN loopvar; + + // + // Determine which timer this child is using + // + for (loopvar = 0; loopvar < INDEX_TIME_MAX; loopvar++) { + if (((RegisterContext->PeriodicTimer.SmiTickInterval == 0) && (RegisterContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) || + (RegisterContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval) + ) { + return &mSmmPeriodicTimerIntervals[loopvar]; + } + } + + // + // If this assertion fires, then either: + // (1) the context contains an invalid interval + // (2) the timer interval table is corrupt + // + // ASSERT (FALSE); + + return NULL; +} + +EFI_STATUS +MapPeriodicTimerToSrcDesc ( + IN QNC_SMM_CONTEXT *RegisterContext, + OUT QNC_SMM_SOURCE_DESC *SrcDesc + ) +{ + TIMER_INTERVAL *TimerInterval; + + // + // Figure out which timer the child is requesting and + // send back the source description + // + TimerInterval = ContextToTimerInterval (RegisterContext); + if (TimerInterval == NULL) { + return EFI_INVALID_PARAMETER; + } + CopyMem (SrcDesc, &mTIMER_SOURCE_DESCS[TimerInterval->AssociatedTimer], sizeof (QNC_SMM_SOURCE_DESC));; + + // + // Program the value of the interval into hardware + // + QNCSmmPeriodicTimerProgramTimers (); + + return EFI_SUCCESS; +} + +VOID +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT QNC_SMM_CONTEXT *HwContext + ) +{ + TIMER_INTERVAL *TimerInterval; + + ASSERT (Record->ProtocolType == PeriodicTimerType); + + TimerInterval = ContextToTimerInterval (&Record->ChildContext); + + if (TimerInterval != NULL) { + // + // Ignore the hardware context. It's not required for this protocol. + // Instead, just increment the child's context. + // Update the elapsed time w/ the data from our tables + // + Record->CommBuffer.PeriodicTimer.ElapsedTime += TimerInterval->Interval; + CopyMem (HwContext, &Record->ChildContext, sizeof (QNC_SMM_CONTEXT)); + } +} + +BOOLEAN +PeriodicTimerCmpContext ( + IN QNC_SMM_CONTEXT *HwContext, + IN QNC_SMM_CONTEXT *ChildContext + ) +{ + DATABASE_RECORD *Record; + + Record = DATABASE_RECORD_FROM_CONTEXT (ChildContext); + + if (Record->CommBuffer.PeriodicTimer.ElapsedTime >= ChildContext->PeriodicTimer.Period) { + // + // This child should be dispatched + // The timer will be restarted on the "ClearSource" call. + // + return TRUE; + } else { + return FALSE; + } +} + +VOID +PeriodicTimerGetBuffer ( + IN DATABASE_RECORD * Record + ) +{ + // + // CommBuffer has been updated by PeriodicTimerGetContext, so return directly + // + return; +} + +VOID +QNCSmmPeriodicTimerProgramTimers ( + VOID + ) +{ + UINT32 GpePmcwValue; + SUPPORTED_TIMER Timer; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + TIMER_INTERVAL *TimerInterval; + + // + // Find the minimum required interval for each timer + // + for (Timer = (SUPPORTED_TIMER)0; Timer < NUM_TIMERS; Timer++) { + mTimers[Timer].MinReqInterval = ~(UINT64)0x0; + mTimers[Timer].NumChildren = 0; + } + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (RecordInDb->ProtocolType == PeriodicTimerType) { + // + // This child is registerd with the PeriodicTimer protocol + // + TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext); + + if(TimerInterval != NULL) { + Timer = (SUPPORTED_TIMER)((TIMER_INTERVAL *) (TimerInterval))->AssociatedTimer; + + ASSERT (Timer >= 0 && Timer < NUM_TIMERS); + + if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) { + mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval; + } + mTimers[Timer].NumChildren++; + } + } + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } + + // + // Program the hardware + // + GpePmcwValue = 0; + if (mTimers[PERIODIC_TIMER].NumChildren > 0) { + switch (mTimers[PERIODIC_TIMER].MinReqInterval) { + + case TIME_64s: + GpePmcwValue = INDEX_TIME_64s; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s; + break; + + case TIME_32s: + GpePmcwValue = INDEX_TIME_32s; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s; + break; + + case TIME_16s: + GpePmcwValue = INDEX_TIME_16s; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s; + break; + + case TIME_8s: + GpePmcwValue = INDEX_TIME_8s; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s; + break; + + case TIME_64ms: + GpePmcwValue = INDEX_TIME_64ms; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64ms; + break; + + case TIME_32ms: + GpePmcwValue = INDEX_TIME_32ms; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32ms; + break; + + case TIME_16ms: + GpePmcwValue = INDEX_TIME_16ms; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16ms; + break; + + case TIME_1_5ms: + GpePmcwValue = INDEX_TIME_1_5ms; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_1_5ms; + break; + + default: + ASSERT (FALSE); + break; + }; + + GpePmcwValue |= B_QNC_GPE0BLK_PMCW_PSE; + + IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMCW), GpePmcwValue); + + // + // Restart the timer here, just need to clear the SMI + // + QNCSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]); + } else { + QNCSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]); + } +} + +EFI_STATUS +QNCSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ) +/*++ + +Routine Description: + + This services returns the next SMI tick period that is supported by the chipset. + The order returned is from longest to shortest interval period. + +Arguments: + + This - Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance. + SmiTickInterval - Pointer to pointer of the next shorter SMI interval period that is supported by the child. + +Returns: + + EFI_SUCCESS - The service returned successfully. + EFI_INVALID_PARAMETER - The parameter SmiTickInterval is invalid. + +--*/ +{ + TIMER_INTERVAL *IntervalPointer; + + ASSERT (SmiTickInterval != NULL); + + IntervalPointer = (TIMER_INTERVAL*)*SmiTickInterval; + + if (IntervalPointer == NULL) { + // + // The first time child requesting an interval + // + IntervalPointer = &mSmmPeriodicTimerIntervals[0]; + } else if (IntervalPointer == &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1]) { + // + // At end of the list + // + IntervalPointer = NULL; + } else { + if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) && + (IntervalPointer < &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1])) { + // + // Get the next interval in the list + // + IntervalPointer++; + } else { + // + // Input is out of range + // + return EFI_INVALID_PARAMETER; + } + } + + if (IntervalPointer != NULL) { + *SmiTickInterval = &IntervalPointer->Interval; + } else { + *SmiTickInterval = NULL; + } + + return EFI_SUCCESS; +} + +VOID +QNCSmmPeriodicTimerClearSource ( + IN QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + This function is responsible for calculating and enabling any timers that are required + to dispatch messages to children. The SrcDesc argument isn't acutally used. + +Arguments: + + SrcDesc - Pointer to the QNC_SMM_SOURCE_DESC instance. + +Returns: + + None. + +--*/ +{ + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + QNCSmmPeriodicTimerProgramTimers (); + + // + // Reset Elapsed time + // + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (RecordInDb->ProtocolType == PeriodicTimerType) { + // + // This child is registerd with the PeriodicTimer protocol and Callback + // has been invoked, so reset the ElapsedTime to 0 + // + if (RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime >= RecordInDb->ChildContext.PeriodicTimer.Period) { + RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime = 0; + } + } + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c new file mode 100644 index 0000000000..2ce0499975 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c @@ -0,0 +1,211 @@ +/** @file +File to contain all the hardware specific stuff for the Smm QNCn dispatch protocol. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmmHelpers.h" + +QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES] = { + + // QNCnMch (0) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnPme (1) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnRtcAlarm (2) + { + QNC_SMM_NO_FLAGS, + { + {{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1E}}, S_QNC_PM1BLK_PM1E, N_QNC_PM1BLK_PM1E_RTC}, + NULL_BIT_DESC_INITIALIZER + }, + { + {{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1S}}, S_QNC_PM1BLK_PM1S, N_QNC_PM1BLK_PM1S_RTC} + } + }, + + // QNCnRingIndicate (3) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnAc97Wake (4) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnSerialIrq (5) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnY2KRollover (6) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnTcoTimeout (7) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnOsTco (8) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnNmi (9) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnIntruderDetect (10) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnBiosWp (11) + { + QNC_SMM_CLEAR_WITH_ZERO, + { + { + { + PCI_ADDR_TYPE, + { + ( + (PCI_BUS_NUMBER_QNC << 24) | + (PCI_DEVICE_NUMBER_QNC_LPC << 16) | + (PCI_FUNCTION_NUMBER_QNC_LPC << 8) | + R_QNC_LPC_BIOS_CNTL + ) + } + }, + S_QNC_LPC_BIOS_CNTL, + N_QNC_LPC_BIOS_CNTL_BLE + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCI_ADDR_TYPE, + { + ( + (PCI_BUS_NUMBER_QNC << 24) | + (PCI_DEVICE_NUMBER_QNC_LPC << 16) | + (PCI_FUNCTION_NUMBER_QNC_LPC << 8) | + R_QNC_LPC_BIOS_CNTL + ) + } + }, + S_QNC_LPC_BIOS_CNTL, + N_QNC_LPC_BIOS_CNTL_BIOSWE + } + } + }, + + // QNCnMcSmi (12) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnPmeB0 (13) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnThrmSts (14) + { + QNC_SMM_SCI_EN_DEPENDENT, + { + {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0E}}, S_QNC_GPE0BLK_GPE0E, N_QNC_GPE0BLK_GPE0E_THRM}, + NULL_BIT_DESC_INITIALIZER + }, + { + {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0S}}, S_QNC_GPE0BLK_GPE0S, N_QNC_GPE0BLK_GPE0S_THRM} + } + }, + + // QNCnSmBus (15) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnIntelUsb2 (16) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnMonSmi7 (17) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnMonSmi6 (18) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnMonSmi5 (19) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnMonSmi4 (20) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap13 (21) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap12 (22) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap11 (23) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap10 (24) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap9 (25) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap8 (26) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap7 (27) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap6 (28) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap5 (29) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap3 (30) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap2 (31) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap1 (32) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnDevTrap0 (33) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnIoTrap3 (34) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnIoTrap2 (35) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnIoTrap1 (36) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnIoTrap0 (37) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnPciExpress (38) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnMonitor (39) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnSpi (40) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnQRT (41) + NULL_SOURCE_DESC_INITIALIZER, + + // QNCnGpioUnlock (42) + NULL_SOURCE_DESC_INITIALIZER +}; + +VOID +QNCSmmQNCnClearSource( + QNC_SMM_SOURCE_DESC *SrcDesc + ) +{ + QNCSmmClearSource (SrcDesc); +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c new file mode 100644 index 0000000000..c820df8067 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c @@ -0,0 +1,90 @@ +/** @file +File to contain all the hardware specific stuff for the Smm Sw dispatch protocol. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmmHelpers.h" + +EFI_SMM_CPU_PROTOCOL *mSmmCpu = NULL; + +CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC = { + QNC_SMM_NO_FLAGS, + { + { + {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_APM + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_APM + } + } +}; + +VOID +SwGetContext( + IN DATABASE_RECORD *Record, + OUT QNC_SMM_CONTEXT *Context + ) +{ + Context->Sw.SwSmiInputValue = IoRead8 (R_APM_CNT); +} + +BOOLEAN +SwCmpContext ( + IN QNC_SMM_CONTEXT *Context1, + IN QNC_SMM_CONTEXT *Context2 + ) +{ + return (BOOLEAN)( Context1->Sw.SwSmiInputValue == Context2->Sw.SwSmiInputValue ); +} + +VOID +SwGetBuffer ( + IN DATABASE_RECORD * Record + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN CpuIndex; + EFI_SMM_SAVE_STATE_IO_INFO IoState; + + // + // Locate SMM CPU protocol to retrieve the CPU save state + // + if (mSmmCpu == NULL) { + Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu); + ASSERT_EFI_ERROR (Status); + } + + // + // Find the CPU which generated the software SMI + // + CpuIndex = 0; + for (Index = 0; Index < gSmst->NumberOfCpus; Index++) { + Status = mSmmCpu->ReadSaveState ( + mSmmCpu, + sizeof (EFI_SMM_SAVE_STATE_IO_INFO), + EFI_SMM_SAVE_STATE_REGISTER_IO, + Index, + &IoState + ); + if (!EFI_ERROR (Status) && (IoState.IoPort == R_APM_CNT)) { + CpuIndex = Index; + break; + } + } + + Record->CommBuffer.Sw.SwSmiCpuIndex = CpuIndex; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c new file mode 100644 index 0000000000..6381a2c598 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c @@ -0,0 +1,147 @@ +/** @file +File to contain all the hardware specific stuff for the Smm Sx dispatch protocol. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmmHelpers.h" + +CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC = { + QNC_SMM_NO_FLAGS, + { + { + {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SLP + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SLP + } + } +}; + +VOID +SxGetContext( + IN DATABASE_RECORD *Record, + OUT QNC_SMM_CONTEXT *Context + ) +{ + UINT32 Pm1Cnt; + + Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); + + // + // By design, the context phase will always be ENTRY + // + Context->Sx.Phase = SxEntry; + + // + // Map the PM1_CNT register's SLP_TYP bits to the context type + // + switch (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) { + + case V_S0: + Context->Sx.Type = SxS0; + break; + + case V_S3: + Context->Sx.Type = SxS3; + break; + + case V_S4: + Context->Sx.Type = SxS4; + break; + + case V_S5: + Context->Sx.Type = SxS5; + break; + + default: + ASSERT (FALSE); + break; + }; +} + +BOOLEAN +SxCmpContext ( + IN QNC_SMM_CONTEXT *Context1, + IN QNC_SMM_CONTEXT *Context2 + ) +{ + return (BOOLEAN)(Context1->Sx.Type == Context2->Sx.Type); +} + +VOID +QNCSmmSxGoToSleep( + VOID + ) +/*++ + +Routine Description: + + When we get an SMI that indicates that we are transitioning to a sleep state, + we need to actually transition to that state. We do this by disabling the + "SMI on sleep enable" feature, which generates an SMI when the operating system + tries to put the system to sleep, and then physically putting the system to sleep. + +Returns: + + None. + +--*/ +{ + UINT32 Pm1Cnt; + + // + // Flush cache into memory before we go to sleep. It is necessary for S3 sleep + // because we may update memory in SMM Sx sleep handlers -- the updates are in cache now + // + AsmWbinvd(); + + // + // Disable SMIs + // + QNCSmmClearSource (&SX_SOURCE_DESC ); + QNCSmmDisableSource (&SX_SOURCE_DESC); + + // + // Clear Sleep Type Enable + // + IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIE, (UINT16)(~B_QNC_GPE0BLK_SMIE_SLP)); + + // clear sleep SMI status + IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, (UINT16)(S_QNC_GPE0BLK_SMIS)); + + // + // Now that SMIs are disabled, write to the SLP_EN bit again to trigger the sleep + // + Pm1Cnt = IoOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, B_QNC_PM1BLK_PM1C_SLPEN); + + // + // The system just went to sleep. If the sleep state was S1, then code execution will resume + // here when the system wakes up. + // + Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); + if ((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == 0) { + // + // An ACPI OS isn't present, clear the sleep information + // + Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SLPTP; + Pm1Cnt |= V_S0; + + IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Pm1Cnt); + } + + QNCSmmClearSource (&SX_SOURCE_DESC); + QNCSmmEnableSource (&SX_SOURCE_DESC); +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h new file mode 100644 index 0000000000..ae3529f679 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h @@ -0,0 +1,868 @@ +/** @file +Prototypes and defines for the QNC SMM Dispatcher. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef QNC_SMM_H +#define QNC_SMM_H + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmmRegisters.h" + +extern EFI_HANDLE mQNCSmmDispatcherImageHandle; + + +// +// ///////////////////////////////////////////////////////////////////////////// +// SUPPORTED PROTOCOLS +// + +// +// Define an enumeration for all the supported protocols +// +typedef enum { + // UsbType, DELETE:on QuarkNcSocId, there is no usb smi supported + SxType, + SwType, + GpiType, + QNCnType, + PowerButtonType, + PeriodicTimerType, + NUM_PROTOCOLS +} QNC_SMM_PROTOCOL_TYPE; + +// +// ///////////////////////////////////////////////////////////////////////////// +// SPECIFYING A REGISTER +// We want a general way of referring to addresses. For this case, we'll only +// need addresses in the ACPI table (and the TCO entries within the ACPI table). +// However, it's interesting to consider what it would take to support other types +// of addresses. To address Will's concern, I think it prudent to accommodate it +// early on in the design. +// +// Addresses we need to consider: +// +// Type: Required: +// I/O Yes +// ACPI (special case of I/O) Only if we want to +// TCO (special case of ACPI) Only if we want to +// Memory (or Memory Mapped I/O) Only if we want to +// PCI Yes, for BiosWp +// +typedef enum { + // + // IO_ADDR_TYPE, // unimplemented + // + ACPI_ADDR_TYPE, + GPE_ADDR_TYPE, + // + // MEMORY_ADDR_TYPE, // unimplemented + // + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCI_ADDR_TYPE, + NUM_ADDR_TYPES, // count of items in this enum + QNC_SMM_ADDR_TYPE_NULL = -1 // sentinel to indicate NULL or to signal end of arrays +} ADDR_TYPE; + +// +// Assumption: 32-bits -- enum's evaluate to integer +// Assumption: This code will only run on IA-32. Justification: IA-64 doesn't have SMIs. +// We don't have to worry about 64-bit addresses. +// Typedef the size of addresses in case the numbers I'm using are wrong or in case +// this changes. This is a good idea because PCI_ADDR will change, for example, when +// we add support for PciExpress. +// +typedef UINT16 IO_ADDR; +typedef IO_ADDR ACPI_ADDR; // can omit +typedef IO_ADDR GPE_ADDR; // can omit +typedef IO_ADDR TCO_ADDR; // can omit +typedef VOID *MEM_ADDR; +typedef MEM_ADDR MEMORY_MAPPED_IO_ADDRESS; +typedef union { + UINT32 Raw; + struct { + UINT8 Reg; + UINT8 Fnc; + UINT8 Dev; + UINT8 Bus; + } Fields; +} PCI_ADDR; + +typedef struct { + ADDR_TYPE Type; + union { + // + // used to initialize during declaration/definition + // + UINTN raw; + + // + // used to access useful data + // + IO_ADDR io; + ACPI_ADDR acpi; + GPE_ADDR gpe; + TCO_ADDR tco; + MEM_ADDR mem; + MEMORY_MAPPED_IO_ADDRESS Mmio; + PCI_ADDR pci; + + } Data; + +} QNC_SMM_ADDRESS; +// +// Assumption: total size is 64 bits (32 for type and 32 for data) or 8 bytes +// +#define EFI_PCI_ADDRESS_PORT 0xcf8 +#define EFI_PCI_DATA_PORT 0xcfc + +// +// ///////////////////////////////////////////////////////////////////////////// +// SPECIFYING BITS WITHIN A REGISTER +// Here's a struct that helps us specify a source or enable bit. +// +typedef struct { + QNC_SMM_ADDRESS Reg; + UINT8 SizeInBytes; // of the register + UINT8 Bit; +} QNC_SMM_BIT_DESC; + +// +// Sometimes, we'll have bit descriptions that are unused. It'd be great to have a +// way to easily identify them: +// +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type == QNC_SMM_ADDR_TYPE_NULL) // "returns" true when BitDesc is NULL +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = QNC_SMM_ADDR_TYPE_NULL) // will "return" an integer w/ value of 0 +#define NULL_BIT_DESC_INITIALIZER \ + { \ + { \ + QNC_SMM_ADDR_TYPE_NULL, \ + { \ + 0 \ + } \ + }, \ + 0, 0 \ + } +// +// I'd like a type to specify the callback's Sts & En bits because they'll +// be commonly used together: +// +#define NUM_EN_BITS 2 +#define NUM_STS_BITS 1 + +// +// Flags +// +typedef UINT8 QNC_SMM_SOURCE_FLAGS; + +// +// Flags required today +// +#define QNC_SMM_NO_FLAGS 0 +#define QNC_SMM_SCI_EN_DEPENDENT (BIT0) +#define QNC_SMM_CLEAR_WITH_ZERO (BIT6) + +// +// Flags that might be required tomorrow +// #define QNC_SMM_CLEAR_WITH_ONE 2 // may need to support bits that clear by writing 0 +// #define QNC_SMM_MULTIBIT_FIELD 3 // may need to support status/enable fields 2 bits wide +// +typedef struct { + QNC_SMM_SOURCE_FLAGS Flags; + QNC_SMM_BIT_DESC En[NUM_EN_BITS]; + QNC_SMM_BIT_DESC Sts[NUM_STS_BITS]; +} QNC_SMM_SOURCE_DESC; +// +// 31 bytes, I think +// +#define NULL_SOURCE_DESC_INITIALIZER \ + { \ + QNC_SMM_NO_FLAGS, \ + { \ + NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \ + }, \ + { \ + NULL_BIT_DESC_INITIALIZER \ + } \ + } + +// +// ///////////////////////////////////////////////////////////////////////////// +// CHILD CONTEXTS +// To keep consistent w/ the architecture, we'll need to provide the context +// to the child when we call its callback function. After talking with Will, +// we agreed that we'll need functions to "dig" the context out of the hardware +// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those +// contexts to prevent unnecessary dispatches. I'd like a general type for these +// "GetContext" functions, so I'll need a union of all the protocol contexts for +// our internal use: +// +typedef union { + // + // (in no particular order) + // + EFI_SMM_ICHN_REGISTER_CONTEXT QNCn; + EFI_SMM_SX_REGISTER_CONTEXT Sx; + EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer; + EFI_SMM_SW_REGISTER_CONTEXT Sw; + EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton; + // EFI_SMM_USB_REGISTER_CONTEXT Usb; DELETE:on QuarkNcSocId, there is no usb smi supported + EFI_SMM_GPI_REGISTER_CONTEXT Gpi; +} QNC_SMM_CONTEXT; + +typedef union { + // + // (in no particular order) + // + EFI_SMM_SW_CONTEXT Sw; + EFI_SMM_PERIODIC_TIMER_CONTEXT PeriodicTimer; +} QNC_SMM_BUFFER; + +// +// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes +// +typedef struct _DATABASE_RECORD DATABASE_RECORD; + +typedef +VOID +(EFIAPI *GET_CONTEXT) ( + IN DATABASE_RECORD * Record, + OUT QNC_SMM_CONTEXT * Context + ); +// +// Assumption: the GET_CONTEXT function will be as small and simple as possible. +// Assumption: We don't need to pass in an enumeration for the protocol because each +// GET_CONTEXT function is written for only one protocol. +// We also need a function to compare contexts to see if the child should be dispatched +// +typedef +BOOLEAN +(EFIAPI *CMP_CONTEXT) ( + IN QNC_SMM_CONTEXT * Context1, + IN QNC_SMM_CONTEXT * Context2 + ); + +/* + Returns: True when contexts are equivalent; False otherwise +*/ + +// +// This function is used to get the content of CommBuffer that will be passed +// to Callback function +// +typedef +VOID +(EFIAPI *GET_BUFFER) ( + IN DATABASE_RECORD * Record + ); + +// +// Finally, every protocol will require a "Get Context", "Compare Context" +// and "Get CommBuffer" call, so we may as well wrap that up in a table, too. +// +typedef struct { + GET_CONTEXT GetContext; + CMP_CONTEXT CmpContext; + GET_BUFFER GetBuffer; +} CONTEXT_FUNCTIONS; + +extern CONTEXT_FUNCTIONS ContextFunctions[NUM_PROTOCOLS]; + +// +// ///////////////////////////////////////////////////////////////////////////// +// MAPPING CONTEXT TO BIT DESCRIPTIONS +// I'd like to have a general approach to mapping contexts to bit descriptions. +// Sometimes, we'll find that we can use table lookups or CONSTant assignments; +// other times, we'll find that we'll need to use a function to perform the mapping. +// If we define a macro to mask that process, we'll never have to change the code. +// I don't know if this is desirable or not -- if it isn't, then we can get rid +// of the macros and just use function calls or variable assignments. Doesn't matter +// to me. +// Mapping complex contexts requires a function +// +// DELETE:on QuarkNcSocId, there is no usb smi supported +//EFI_STATUS +//EFIAPI +//MapUsbToSrcDesc ( +// IN QNC_SMM_CONTEXT *RegisterContext, +// OUT QNC_SMM_SOURCE_DESC *SrcDesc +// ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + RegisterContext - GC_TODO: add argument description + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +EFI_STATUS +MapPeriodicTimerToSrcDesc ( + IN QNC_SMM_CONTEXT *RegisterContext, + OUT QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + RegisterContext - GC_TODO: add argument description + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +// +// Mapping simple contexts can be done by assignment or lookup table +// +extern CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC; +extern CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC; + +// +// With the changes we've made to the protocols, we can now use table +// lookups for the following protocols: +// +extern CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC; + +extern QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES]; + + +// +// For QNCx, APMC is UINT8 port, so the MAX SWI Value is 0xFF. +// +#define MAXIMUM_SWI_VALUE 0xFF + + +// +// Open: Need to make sure this kind of type cast will actually work. +// May need an intermediate form w/ two VOID* arguments. I'll figure +// that out when I start compiling. + +/////////////////////////////////////////////////////////////////////////////// +// +typedef +VOID +(EFIAPI *QNC_SMM_CLEAR_SOURCE) ( + QNC_SMM_SOURCE_DESC * SrcDesc + ); + +// +// ///////////////////////////////////////////////////////////////////////////// +// "DATABASE" RECORD +// Linked list data structures +// +#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C') + +struct _DATABASE_RECORD { + UINT32 Signature; + LIST_ENTRY Link; + + BOOLEAN Processed; + + // + // Status and Enable bit description + // + QNC_SMM_SOURCE_DESC SrcDesc; + + // + // Callback function + // + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; + QNC_SMM_CONTEXT ChildContext; + VOID *CallbackContext; + QNC_SMM_BUFFER CommBuffer; + UINTN BufferSize; + + // + // Special handling hooks -- init them to NULL if unused/unneeded + // + QNC_SMM_CLEAR_SOURCE ClearSource; // needed for SWSMI timer + // Functions required to make callback code general + // + CONTEXT_FUNCTIONS ContextFunctions; + + // + // The protocol that this record dispatches + // + QNC_SMM_PROTOCOL_TYPE ProtocolType; + +}; + +#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE) +#define DATABASE_RECORD_FROM_CONTEXT(_record) CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE) + +// +// ///////////////////////////////////////////////////////////////////////////// +// HOOKING INTO THE ARCHITECTURE +// +typedef +EFI_STATUS +(EFIAPI *QNC_SMM_GENERIC_REGISTER) ( + IN VOID **This, + IN VOID *DispatchFunction, + IN VOID *RegisterContext, + OUT EFI_HANDLE * DispatchHandle + ); +typedef +EFI_STATUS +(EFIAPI *QNC_SMM_GENERIC_UNREGISTER) ( + IN VOID **This, + IN EFI_HANDLE DispatchHandle + ); + +// +// Define a memory "stamp" equivalent in size and function to most of the protocols +// +typedef struct { + QNC_SMM_GENERIC_REGISTER Register; + QNC_SMM_GENERIC_UNREGISTER Unregister; + UINTN Extra1; + UINTN Extra2; // may not need this one +} QNC_SMM_GENERIC_PROTOCOL; + +EFI_STATUS +QNCSmmCoreRegister ( + IN QNC_SMM_GENERIC_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN QNC_SMM_CONTEXT *RegisterContext, + OUT EFI_HANDLE *DispatchHandle + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + This - GC_TODO: add argument description + DispatchFunction - GC_TODO: add argument description + RegisterContext - GC_TODO: add argument description + DispatchHandle - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; +EFI_STATUS +QNCSmmCoreUnRegister ( + IN QNC_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + This - GC_TODO: add argument description + DispatchHandle - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +typedef union { + QNC_SMM_GENERIC_PROTOCOL Generic; + + // EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; DELETE:on QuarkNcSocId, there is no usb smi supported + EFI_SMM_SX_DISPATCH2_PROTOCOL Sx; + EFI_SMM_SW_DISPATCH2_PROTOCOL Sw; + EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi; + EFI_SMM_ICHN_DISPATCH2_PROTOCOL QNCn; + EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton; + EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer; +} QNC_SMM_PROTOCOL; + +// +// Define a structure to help us identify the generic protocol +// +#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T') + +typedef struct { + UINTN Signature; + + QNC_SMM_PROTOCOL_TYPE Type; + EFI_GUID *Guid; + QNC_SMM_PROTOCOL Protocols; +} QNC_SMM_QUALIFIED_PROTOCOL; + +#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \ + CR (_generic, \ + QNC_SMM_QUALIFIED_PROTOCOL, \ + Protocols, \ + PROTOCOL_SIGNATURE \ + ) + +// +// Create private data for the protocols that we'll publish +// +typedef struct { + LIST_ENTRY CallbackDataBase; + EFI_HANDLE SmiHandle; + EFI_HANDLE InstallMultProtHandle; + QNC_SMM_QUALIFIED_PROTOCOL Protocols[NUM_PROTOCOLS]; +} PRIVATE_DATA; + +extern PRIVATE_DATA mPrivateData; + +// +// ///////////////////////////////////////////////////////////////////////////// +// +VOID +EFIAPI +SwGetContext ( + IN DATABASE_RECORD *Record, + OUT QNC_SMM_CONTEXT *Context + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Record - GC_TODO: add argument description + Context - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +EFIAPI +SwCmpContext ( + IN QNC_SMM_CONTEXT *Context1, + IN QNC_SMM_CONTEXT *Context2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Context1 - GC_TODO: add argument description + Context2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +SwGetBuffer ( + IN DATABASE_RECORD * Record + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Record - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +EFIAPI +SxGetContext ( + IN DATABASE_RECORD *Record, + OUT QNC_SMM_CONTEXT *Context + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Record - GC_TODO: add argument description + Context - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +EFIAPI +SxCmpContext ( + IN QNC_SMM_CONTEXT *Context1, + IN QNC_SMM_CONTEXT *Context2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Context1 - GC_TODO: add argument description + Context2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +EFIAPI +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT QNC_SMM_CONTEXT *Context + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Record - GC_TODO: add argument description + Context - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +EFIAPI +PeriodicTimerCmpContext ( + IN QNC_SMM_CONTEXT *Context1, + IN QNC_SMM_CONTEXT *Context2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Context1 - GC_TODO: add argument description + Context2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +PeriodicTimerGetBuffer ( + IN DATABASE_RECORD * Record + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Record - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +EFIAPI +PowerButtonGetContext ( + IN DATABASE_RECORD *Record, + OUT QNC_SMM_CONTEXT *Context + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Record - GC_TODO: add argument description + Context - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +EFIAPI +PowerButtonCmpContext ( + IN QNC_SMM_CONTEXT *Context1, + IN QNC_SMM_CONTEXT *Context2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Context1 - GC_TODO: add argument description + Context2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +// +// ///////////////////////////////////////////////////////////////////////////// +// +VOID +EFIAPI +QNCSmmPeriodicTimerClearSource ( + QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +EFI_STATUS +QNCSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + This - GC_TODO: add argument description + SmiTickInterval - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +QNCSmmSxGoToSleep ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +EFIAPI +QNCSmmQNCnClearSource ( + QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c new file mode 100644 index 0000000000..6e6d48fe02 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c @@ -0,0 +1,825 @@ +/** @file +This driver is responsible for the registration of child drivers +and the abstraction of the QNC SMI sources. + +Copyright (c) 2013-2017 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmm.h" +#include "QNCSmmHelpers.h" + +// +// ///////////////////////////////////////////////////////////////////////////// +// MODULE / GLOBAL DATA +// +// Module variables used by the both the main dispatcher and the source dispatchers +// Declared in QNCSmmSources.h +// +UINT32 mPciData; +UINT32 mPciAddress; + +PRIVATE_DATA mPrivateData = { // for the structure + { + NULL + }, // CallbackDataBase linked list head + NULL, // Handler returned whan calling SmiHandlerRegister + NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces + { // protocol arrays + // elements within the array + // + { + PROTOCOL_SIGNATURE, + SxType, + &gEfiSmmSxDispatch2ProtocolGuid, + { + { + (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister, + (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister + } + } + }, + { + PROTOCOL_SIGNATURE, + SwType, + &gEfiSmmSwDispatch2ProtocolGuid, + { + { + (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister, + (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister, + (UINTN) MAXIMUM_SWI_VALUE + } + } + }, + { + PROTOCOL_SIGNATURE, + GpiType, + &gEfiSmmGpiDispatch2ProtocolGuid, + { + { + (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister, + (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister, + (UINTN) 1 + } + } + }, + { + PROTOCOL_SIGNATURE, + QNCnType, + &gEfiSmmIchnDispatch2ProtocolGuid, + { + { + (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister, + (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister + } + } + }, + { + PROTOCOL_SIGNATURE, + PowerButtonType, + &gEfiSmmPowerButtonDispatch2ProtocolGuid, + { + { + (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister, + (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister + } + } + }, + { + PROTOCOL_SIGNATURE, + PeriodicTimerType, + &gEfiSmmPeriodicTimerDispatch2ProtocolGuid, + { + { + (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister, + (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister, + (UINTN) QNCSmmPeriodicTimerDispatchGetNextShorterInterval + } + } + }, + } +}; + +CONTEXT_FUNCTIONS mContextFunctions[NUM_PROTOCOLS] = { + { + SxGetContext, + SxCmpContext, + NULL + }, + { + SwGetContext, + SwCmpContext, + SwGetBuffer + }, + { + NULL, + NULL, + NULL + }, + { + NULL, + NULL, + NULL + }, + { + NULL, + NULL, + NULL + }, + { + PeriodicTimerGetContext, + PeriodicTimerCmpContext, + PeriodicTimerGetBuffer, + }, +}; + +// +// ///////////////////////////////////////////////////////////////////////////// +// PROTOTYPES +// +// Functions use only in this file +// +EFI_STATUS +QNCSmmCoreDispatcher ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, OPTIONAL + IN OUT VOID *CommBuffer, OPTIONAL + IN OUT UINTN *CommBufferSize OPTIONAL + ); + + +UINTN +DevicePathSize ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +// +// ///////////////////////////////////////////////////////////////////////////// +// FUNCTIONS +// +// Driver entry point +// +EFI_STATUS +EFIAPI +InitializeQNCSmmDispatcher ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initializes the QNC SMM Dispatcher + +Arguments: + + ImageHandle - Pointer to the loaded image protocol for this driver + SystemTable - Pointer to the EFI System Table + +Returns: + Status - EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + QNCSmmPublishDispatchProtocols (); + + // + // Register a callback function to handle subsequent SMIs. This callback + // will be called by SmmCoreDispatcher. + // + Status = gSmst->SmiHandlerRegister (QNCSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle); + ASSERT_EFI_ERROR (Status); + + // + // Initialize Callback DataBase + // + InitializeListHead (&mPrivateData.CallbackDataBase); + + // + // Enable SMIs on the QNC now that we have a callback + // + QNCSmmInitHardware (); + + return EFI_SUCCESS; +} + +EFI_STATUS +SaveState ( + VOID + ) +/*++ + +Routine Description: + + Save Index registers to avoid corrupting the foreground environment + +Arguments: + None + +Returns: + Status - EFI_SUCCESS + +--*/ +{ + mPciAddress = IoRead32 (EFI_PCI_ADDRESS_PORT); + return EFI_SUCCESS; +} + +EFI_STATUS +RestoreState ( + VOID + ) +/*++ + +Routine Description: + + Restore Index registers to avoid corrupting the foreground environment + +Arguments: + None + +Returns: + Status - EFI_SUCCESS + +--*/ +{ + IoWrite32 (EFI_PCI_ADDRESS_PORT, mPciAddress); + return EFI_SUCCESS; +} + +EFI_STATUS +SmiInputValueDuplicateCheck ( + UINTN FedSwSmiInputValue + ) +/*++ + +Routine Description: + + Check the Fed SwSmiInputValue to see if there is a duplicated one in the database + +Arguments: + None + +Returns: + Status - EFI_SUCCESS, EFI_INVALID_PARAMETER + +--*/ +// GC_TODO: FedSwSmiInputValue - add argument and description to function comment +{ + + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + + if (RecordInDb->ProtocolType == SwType) { + if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) { + return EFI_INVALID_PARAMETER; + } + } + + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +QNCSmmCoreRegister ( + IN QNC_SMM_GENERIC_PROTOCOL *This, + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, + IN QNC_SMM_CONTEXT *RegisterContext, + OUT EFI_HANDLE *DispatchHandle + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +// GC_TODO: This - add argument and description to function comment +// GC_TODO: DispatchFunction - add argument and description to function comment +// GC_TODO: RegisterContext - add argument and description to function comment +// GC_TODO: DispatchHandle - add argument and description to function comment +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + QNC_SMM_QUALIFIED_PROTOCOL *Qualified; + INTN Index; + + // + // Check for invalid parameter + // + if (This == NULL || RegisterContext == NULL || DispatchHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Create database record and add to database + // + Record = (DATABASE_RECORD *) AllocateZeroPool (sizeof (DATABASE_RECORD)); + if (Record == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Gather information about the registration request + // + Record->Callback = DispatchFunction; + Record->CallbackContext = RegisterContext; + CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT)); + + Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This); + + Record->ProtocolType = Qualified->Type; + + CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions)); + // + // Perform linked list housekeeping + // + Record->Signature = DATABASE_RECORD_SIGNATURE; + + switch (Qualified->Type) { + // + // By the end of this switch statement, we'll know the + // source description the child is registering for + // + case SxType: + // + // Check the validity of Context Type and Phase + // + if ((Record->ChildContext.Sx.Type < SxS0) || + (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) || + (Record->ChildContext.Sx.Phase < SxEntry) || + (Record->ChildContext.Sx.Phase >= EfiMaximumPhase) + ) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc)); + // + // use default clear source function + // + break; + + case SwType: + if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) { + // + // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure. + // + Status = EFI_NOT_FOUND; + for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) { + Status = SmiInputValueDuplicateCheck (Index); + if (!EFI_ERROR (Status)) { + RegisterContext->Sw.SwSmiInputValue = Index; + break; + } + } + if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) { + Status = gSmst->SmmFreePool (Record); + return EFI_OUT_OF_RESOURCES; + } + // + // Update ChildContext again as SwSmiInputValue has been changed + // + CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT)); + } + + // + // Check the validity of Context Value + // + if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) { + goto Error; + } + + if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc)); + Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT); + // + // use default clear source function + // + break; + + case GpiType: + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc)); + // + // use default clear source function + // + break; + + case QNCnType: + // + // Check the validity of Context Type + // + if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc)); + Record->ClearSource = QNCSmmQNCnClearSource; + break; + + case PeriodicTimerType: + + Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc)); + if (EFI_ERROR (Status)) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT); + Record->ClearSource = QNCSmmPeriodicTimerClearSource; + break; + + default: + goto Error; + break; + }; + + if (Record->ClearSource == NULL) { + // + // Clear the SMI associated w/ the source using the default function + // + QNCSmmClearSource (&Record->SrcDesc); + } else { + // + // This source requires special handling to clear + // + Record->ClearSource (&Record->SrcDesc); + } + + QNCSmmEnableSource (&Record->SrcDesc); + + // + // Child's handle will be the address linked list link in the record + // + *DispatchHandle = (EFI_HANDLE) (&Record->Link); + + return EFI_SUCCESS; + +Error: + FreePool (Record); + // + // DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status )); + // + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +QNCSmmCoreUnRegister ( + IN QNC_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE DispatchHandle + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +// GC_TODO: This - add argument and description to function comment +// GC_TODO: DispatchHandle - add argument and description to function comment +// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment +// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + BOOLEAN SafeToDisable; + DATABASE_RECORD *RecordToDelete; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + if (DispatchHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + + RemoveEntryList (&RecordToDelete->Link); + RecordToDelete->Signature = 0; + + // + // See if we can disable the source, reserved for future use since this might + // not be the only criteria to disable + // + SafeToDisable = TRUE; + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) { + SafeToDisable = FALSE; + break; + } + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } + if (SafeToDisable) { + QNCSmmDisableSource( &RecordToDelete->SrcDesc ); +} + + FreePool (RecordToDelete); + + return EFI_SUCCESS; +} + +/** + This function is the main entry point for an SMM handler dispatch + or communicate-based callback. + + @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param RegisterContext Points to an optional handler context which was specified when the handler was registered. + @param CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +QNCSmmCoreDispatcher ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *RegisterContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + // + // Used to prevent infinite loops + // + UINTN EscapeCount; + + BOOLEAN ContextsMatch; + BOOLEAN ResetListSearch; + BOOLEAN EosSet; + BOOLEAN SxChildWasDispatched; + BOOLEAN ChildWasDispatched; + + DATABASE_RECORD *RecordInDb; + DATABASE_RECORD ActiveRecordInDb; + LIST_ENTRY *LinkInDb; + DATABASE_RECORD *RecordToExhaust; + LIST_ENTRY *LinkToExhaust; + + QNC_SMM_CONTEXT Context; + VOID *CommunicationBuffer; + UINTN BufferSize; + + EFI_STATUS Status; + UINT32 NewValue; + + QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER; + + EscapeCount = 100; + ContextsMatch = FALSE; + ResetListSearch = FALSE; + EosSet = FALSE; + SxChildWasDispatched = FALSE; + Status = EFI_WARN_INTERRUPT_SOURCE_PENDING; + ChildWasDispatched = FALSE; + + // + // Mark all child handlers as not processed + // + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + RecordInDb->Processed = FALSE; + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb); + } + + // + // Preserve Index registers + // + SaveState (); + + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) { + // + // We have children registered w/ us -- continue + // + while ((!EosSet) && (EscapeCount > 0)) { + EscapeCount--; + + // + // Reset this flag in order to be able to process multiple SMI Sources in one loop. + // + ResetListSearch = FALSE; + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + + while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + // + // Make a copy of the record that contains an active SMI source, + // because un-register maybe invoked in callback function and + // RecordInDb maybe released + // + CopyMem (&ActiveRecordInDb, RecordInDb, sizeof (ActiveRecordInDb)); + + // + // look for the first active source + // + if (!SourceIsActive (&RecordInDb->SrcDesc)) { + // + // Didn't find the source yet, keep looking + // + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + + } else { + // + // We found a source. If this is a sleep type, we have to go to + // appropriate sleep state anyway.No matter there is sleep child or not + // + if (RecordInDb->ProtocolType == SxType) { + SxChildWasDispatched = TRUE; + } + // + // "cache" the source description and don't query I/O anymore + // + CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource)); + LinkToExhaust = LinkInDb; + + // + // exhaust the rest of the queue looking for the same source + // + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) { + RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust); + LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, LinkToExhaust); + if (RecordToExhaust->Processed) { + // + // Record has already been processed. Continue with next child handler. + // + continue; + } + + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) { + // + // These source descriptions are equal, so this callback should be + // dispatched. + // + if (RecordToExhaust->ContextFunctions.GetContext != NULL) { + // + // This child requires that we get a calling context from + // hardware and compare that context to the one supplied + // by the child. + // + ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL); + + // + // Make sure contexts match before dispatching event to child + // + RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context); + ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext); + + } else { + // + // This child doesn't require any more calling context beyond what + // it supplied in registration. Simply pass back what it gave us. + // + ASSERT (RecordToExhaust->Callback != NULL); + ContextsMatch = TRUE; + } + + // + // Mark this child handler so it will not be processed again + // + RecordToExhaust->Processed = TRUE; + + if (ContextsMatch) { + + if (RecordToExhaust->BufferSize != 0) { + ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL); + + RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust); + + CommunicationBuffer = &RecordToExhaust->CommBuffer; + BufferSize = RecordToExhaust->BufferSize; + } else { + CommunicationBuffer = NULL; + BufferSize = 0; + } + + ASSERT (RecordToExhaust->Callback != NULL); + + RecordToExhaust->Callback ( + (EFI_HANDLE) & RecordToExhaust->Link, + RecordToExhaust->CallbackContext, + CommunicationBuffer, + &BufferSize + ); + + ChildWasDispatched = TRUE; + if (RecordToExhaust->ProtocolType == SxType) { + SxChildWasDispatched = TRUE; + } + } + // + // Can not use RecordInDb after this point because Callback may have unregistered RecordInDb + // Restart processing of SMI handlers from the begining of the linked list because the + // state of the linked listed may have been modified due to unregister actions in the Callback. + // + LinkToExhaust = GetFirstNode (&mPrivateData.CallbackDataBase); + } + } + + if (ActiveRecordInDb.ClearSource == NULL) { + // + // Clear the SMI associated w/ the source using the default function + // + QNCSmmClearSource (&ActiveSource); + } else { + // + // This source requires special handling to clear + // + ActiveRecordInDb.ClearSource (&ActiveSource); + } + + if (ChildWasDispatched) { + // + // The interrupt was handled and quiesced + // + Status = EFI_SUCCESS; + } else { + // + // The interrupt was not handled but quiesced + // + Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED; + } + + // + // Queue is empty, reset the search + // + ResetListSearch = TRUE; + + } + } + EosSet = QNCSmmSetAndCheckEos (); + } + } + // + // If you arrive here, there are two possible reasons: + // (1) you've got problems with clearing the SMI status bits in the + // ACPI table. If you don't properly clear the SMI bits, then you won't be able to set the + // EOS bit. If this happens too many times, the loop exits. + // (2) there was a SMM communicate for callback messages that was received prior + // to this driver. + // If there is an asynchronous SMI that occurs while processing the Callback, let + // all of the drivers (including this one) have an opportunity to scan for the SMI + // and handle it. + // If not, we don't want to exit and have the foreground app. clear EOS without letting + // these other sources get serviced. + // + ASSERT (EscapeCount > 0); + + // + // Restore Index registers + // + RestoreState (); + + if (SxChildWasDispatched) { + // + // A child of the SmmSxDispatch protocol was dispatched during this call; + // put the system to sleep. + // + QNCSmmSxGoToSleep (); + } + + // + // Ensure that SMI signal pin indicator is clear at the end of SMM handling. + // + NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG); + NewValue &= ~(HLEGACY_SMI_PIN_VALUE); + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue); + + return Status; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf new file mode 100644 index 0000000000..dec3c5043a --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf @@ -0,0 +1,81 @@ +## @file +# Component description file for QuarkNcSocId SmmDispatcher module. +# +# This driver is responsible for the registration of child drivers +# and the abstraction of the ICH SMI sources. +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = QNCSmmDispatcher + FILE_GUID = 2480271C-09C6-4f36-AD75-5E1390BD9929 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = InitializeQNCSmmDispatcher + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + QNC/QNCSmmPeriodicTimer.c + QNC/QNCSmmQncn.c + QNC/QNCSmmSx.c + QNC/QNCSmmSw.c + QNC/QNCSmmGpi.c + QNC/QNCSmmHelpers.c + QNCSmmHelpers.c + QNCSmmCore.c + QNCSmmHelpers.h + QNCxSmmHelpers.h + QNCSmmRegisters.h + QNCSmm.h + CommonHeader.h + +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + SmmServicesTableLib + UefiBootServicesTableLib + DxeServicesTableLib + MemoryAllocationLib + PciLib + PcdLib + BaseMemoryLib + DebugLib + BaseLib + IoLib + DevicePathLib + S3IoLib + QNCAccessLib + +[Protocols] + gEfiSmmCpuProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiSmmReadyToLockProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiSmmPeriodicTimerDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSmmPowerButtonDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSmmIchnDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSmmGpiDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSmmSwDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSmmSxDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSmmUsbDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiSmmIoTrapDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED + +[Pcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress + +[Depex] + gEfiSmmCpuProtocolGuid AND gEfiPciRootBridgeIoProtocolGuid diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c new file mode 100644 index 0000000000..38729c94ca --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c @@ -0,0 +1,367 @@ +/** @file + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmm.h" +#include "QNCSmmHelpers.h" + +// +// #define BIT_ZERO 0x00000001 +// +CONST UINT32 BIT_ZERO = 0x00000001; + +// +// ///////////////////////////////////////////////////////////////////////////// +// SUPPORT / HELPER FUNCTIONS (QNC version-independent) +// +BOOLEAN +CompareEnables ( + CONST IN QNC_SMM_SOURCE_DESC *Src1, + CONST IN QNC_SMM_SOURCE_DESC *Src2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Src1 - GC_TODO: add argument description + Src2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + BOOLEAN IsEqual; + UINTN loopvar; + + IsEqual = TRUE; + for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) { + // + // It's okay to compare a NULL bit description to a non-NULL bit description. + // They are unequal and these tests will generate the correct result. + // + if (Src1->En[loopvar].Bit != Src2->En[loopvar].Bit || + Src1->En[loopvar].Reg.Type != Src2->En[loopvar].Reg.Type || + Src1->En[loopvar].Reg.Data.raw != Src2->En[loopvar].Reg.Data.raw + ) { + IsEqual = FALSE; + break; + // + // out of for loop + // + } + } + + return IsEqual; +} + +BOOLEAN +CompareStatuses ( + CONST IN QNC_SMM_SOURCE_DESC *Src1, + CONST IN QNC_SMM_SOURCE_DESC *Src2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Src1 - GC_TODO: add argument description + Src2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + BOOLEAN IsEqual; + UINTN loopvar; + + IsEqual = TRUE; + + for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) { + // + // It's okay to compare a NULL bit description to a non-NULL bit description. + // They are unequal and these tests will generate the correct result. + // + if (Src1->Sts[loopvar].Bit != Src2->Sts[loopvar].Bit || + Src1->Sts[loopvar].Reg.Type != Src2->Sts[loopvar].Reg.Type || + Src1->Sts[loopvar].Reg.Data.raw != Src2->Sts[loopvar].Reg.Data.raw + ) { + IsEqual = FALSE; + break; + // + // out of for loop + // + } + } + + return IsEqual; +} + +BOOLEAN +CompareSources ( + CONST IN QNC_SMM_SOURCE_DESC *Src1, + CONST IN QNC_SMM_SOURCE_DESC *Src2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Src1 - GC_TODO: add argument description + Src2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, Src2)); +} + +BOOLEAN +SourceIsActive ( + CONST IN QNC_SMM_SOURCE_DESC *Src + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Src - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + BOOLEAN IsActive; + UINTN loopvar; + + BOOLEAN SciEn; + + IsActive = TRUE; + + SciEn = QNCSmmGetSciEn (); + + if ((Src->Flags & QNC_SMM_SCI_EN_DEPENDENT) && (SciEn)) { + // + // This source is dependent on SciEn, and SciEn == 1. An ACPI OS is present, + // so we shouldn't do anything w/ this source until SciEn == 0. + // + IsActive = FALSE; + + } else { + // + // Read each bit desc from hardware and make sure it's a one + // + for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) { + + if (!IS_BIT_DESC_NULL (Src->En[loopvar])) { + + if (ReadBitDesc (&Src->En[loopvar]) == 0) { + IsActive = FALSE; + break; + // + // out of for loop + // + } + + } + } + + if (IsActive) { + // + // Read each bit desc from hardware and make sure it's a one + // + for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) { + + if (!IS_BIT_DESC_NULL (Src->Sts[loopvar])) { + + if (ReadBitDesc (&Src->Sts[loopvar]) == 0) { + IsActive = FALSE; + break; + // + // out of for loop + // + } + + } + } + } + } + + return IsActive; +} + +VOID +QNCSmmEnableSource ( + CONST QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + UINTN loopvar; + + // + // Set enables to 1 by writing a 1 + // + for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) { + if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) { + WriteBitDesc (&SrcDesc->En[loopvar], 1); + } + } + + QNCSmmClearSource (SrcDesc); + +} + +VOID +QNCSmmDisableSource ( + CONST QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + UINTN loopvar; + + for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) { + if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) { + WriteBitDesc (&SrcDesc->En[loopvar], 0); + } + } +} + +VOID +QNCSmmClearSource ( + CONST QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + UINTN loopvar; + BOOLEAN ValueToWrite; + + ValueToWrite = + ((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE; + + for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) { + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) { + WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite); + } + } +} + +VOID +QNCSmmClearSourceAndBlock ( + CONST QNC_SMM_SOURCE_DESC *SrcDesc + ) +// GC_TODO: function comment should start with '/*++' +/* + Sets the source to a 1 or 0 and then waits for it to clear. + Be very careful when calling this function -- it will not + ASSERT. An acceptable case to call the function is when + waiting for the NEWCENTURY_STS bit to clear (which takes + 3 RTCCLKs). +*/ +// GC_TODO: function comment should end with '--*/' +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: SrcDesc - add argument and description to function comment +{ + UINTN loopvar; + BOOLEAN IsSet; + BOOLEAN ValueToWrite; + + ValueToWrite = + ((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE; + + for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) { + + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) { + // + // Write the bit + // + WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite); + + // + // Don't return until the bit actually clears. + // + IsSet = TRUE; + while (IsSet) { + IsSet = ReadBitDesc (&SrcDesc->Sts[loopvar]); + // + // IsSet will eventually clear -- or else we'll have + // an infinite loop. + // + } + } + } +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h new file mode 100644 index 0000000000..0cd26da904 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h @@ -0,0 +1,219 @@ +/** @file + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef QNC_SMM_HELPERS_H +#define QNC_SMM_HELPERS_H + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmm.h" +#include "QNCxSmmHelpers.h" + +// +// ///////////////////////////////////////////////////////////////////////////// +// SUPPORT / HELPER FUNCTIONS (QNC version-independent) +// +VOID +QNCSmmPublishDispatchProtocols ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +CompareEnables ( + CONST IN QNC_SMM_SOURCE_DESC *Src1, + CONST IN QNC_SMM_SOURCE_DESC *Src2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Src1 - GC_TODO: add argument description + Src2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +CompareStatuses ( + CONST IN QNC_SMM_SOURCE_DESC *Src1, + CONST IN QNC_SMM_SOURCE_DESC *Src2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Src1 - GC_TODO: add argument description + Src2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +CompareSources ( + CONST IN QNC_SMM_SOURCE_DESC *Src1, + CONST IN QNC_SMM_SOURCE_DESC *Src2 + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Src1 - GC_TODO: add argument description + Src2 - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +SourceIsActive ( + CONST IN QNC_SMM_SOURCE_DESC *Src + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Src - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +QNCSmmEnableSource ( + CONST QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +QNCSmmDisableSource ( + CONST QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +QNCSmmClearSource ( + CONST QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +QNCSmmClearSourceAndBlock ( + CONST QNC_SMM_SOURCE_DESC *SrcDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SrcDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h new file mode 100644 index 0000000000..aec0c70283 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h @@ -0,0 +1,13 @@ +/** @file + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef QNC_SMM_REGISTERS_H +#define QNC_SMM_REGISTERS_H +#include "CommonHeader.h" + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h new file mode 100644 index 0000000000..3f89b6411f --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h @@ -0,0 +1,178 @@ +/** @file + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef QNCX_SMM_HELPERS_H +#define QNCX_SMM_HELPERS_H + +// +// Include common header file for this module. +// +#include "CommonHeader.h" + +#include "QNCSmm.h" + +EFI_STATUS +QNCSmmInitHardware ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +EFI_STATUS +QNCSmmEnableGlobalSmiBit ( + VOID + ) +/*++ + +Routine Description: + + Enables the QNC to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + +Arguments: + + None + +Returns: + + EFI_SUCCESS. + Asserts, otherwise. + +--*/ +; + +EFI_STATUS +QNCSmmClearSmi ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +QNCSmmSetAndCheckEos ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +BOOLEAN +QNCSmmGetSciEn ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +// +// /////////////////////////////////////////////////////////////////////////// +// +// These may or may not need to change w/ the QNC version; +// they're here because they're highly IA-32 dependent. +// +BOOLEAN +ReadBitDesc ( + CONST QNC_SMM_BIT_DESC *BitDesc + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + BitDesc - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +VOID +WriteBitDesc ( + CONST QNC_SMM_BIT_DESC *BitDesc, + CONST BOOLEAN ValueToWrite + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + BitDesc - GC_TODO: add argument description + ValueToWrite - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c new file mode 100644 index 0000000000..637792d147 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c @@ -0,0 +1,376 @@ +/** @file +This is the driver that publishes the SMM Access Ppi +instance for the Quark SOC. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf new file mode 100644 index 0000000000..34d90b26ea --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf @@ -0,0 +1,45 @@ +## @file +# Component description file for SmmAccessPei module +# +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] +INF_VERSION = 0x00010005 +BASE_NAME = SmmAccessPei +FILE_GUID = B4E0CDFC-30CD-4b29-A445-B0AA95A532E4 +MODULE_TYPE = PEIM +VERSION_STRING = 1.0 +ENTRY_POINT = SmmAccessPeiEntryPoint + +[Sources] + SmmAccessPei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + PeimEntryPoint + BaseMemoryLib + MemoryAllocationLib + DebugLib + HobLib + PeiServicesLib + PciLib + SmmLib + +[Guids] + gEfiSmmPeiSmramMemoryReserveGuid # ALWAYS_CONSUMED + +[Ppis] + gPeiSmmAccessPpiGuid # ALWAYS_PRODUCED + gEfiPeiMemoryDiscoveredPpiGuid # ALWAYS_CONSUMED + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c new file mode 100644 index 0000000000..243e4c9e99 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c @@ -0,0 +1,274 @@ +/** @file +This module provides an implementation of the SMM Control PPI for use with +the QNC. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#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 GPE0BLK_Base; + + // + // Get GPE0BLK_Base + // + GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress); + + // + // Clear the Power Button Override Status Bit, it gates EOS from being set. + // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing. + // + + // + // Clear the APM SMI Status Bit + // + IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM); + + // + // Set the EOS Bit + // + IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS); + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +SmmTrigger ( + IN UINT8 Data + ) +/*++ + +Routine Description: + + Trigger the software SMI + +Arguments: + + Data The value to be set on the software SMI data port + +Returns: + + EFI_SUCCESS Function completes successfully + +--*/ +{ + UINT16 GPE0BLK_Base; + UINT32 NewValue; + + // + // Get GPE0BLK_Base + // + GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress); + + // + // Enable the APMC SMI + // + IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM); + + // + // Enable SMI globally + // + NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); + NewValue |= SMI_EN; + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue); + + + // + // Generate the APMC SMI + // + IoWrite8 (PcdGet16 (PcdSmmActivationPort), Data); + + return EFI_SUCCESS; +} + +/** + Generates an SMI using the parameters passed in. + + @param PeiServices Describes the list of possible PEI Services. + @param This A pointer to an instance of + EFI_SMM_CONTROL_PPI + @param ArgumentBuffer The argument buffer + @param ArgumentBufferSize The size of the argument buffer + @param Periodic TRUE to indicate a periodical SMI + @param ActivationInterval Interval of the periodical SMI + + @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1 + @retval EFI_SUCCESS SMI generated + +**/ +EFI_STATUS +EFIAPI +PeiActivate ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_SMM_CONTROL_PPI *This, + IN OUT INT8 *ArgumentBuffer OPTIONAL, + IN OUT UINTN *ArgumentBufferSize OPTIONAL, + IN BOOLEAN Periodic OPTIONAL, + IN UINTN ActivationInterval OPTIONAL + ) +{ + INT8 Data; + EFI_STATUS Status; + // + // Periodic SMI not supported. + // + if (Periodic) { + DEBUG ((DEBUG_WARN, "Invalid parameter\n")); + return EFI_INVALID_PARAMETER; + } + + if (ArgumentBuffer == NULL) { + Data = 0xFF; + } else { + if (ArgumentBufferSize == NULL || *ArgumentBufferSize != 1) { + return EFI_INVALID_PARAMETER; + } + + Data = *ArgumentBuffer; + } + // + // Clear any pending the APM SMI + // + Status = SmmClear (); + if (EFI_ERROR (Status)) { + return Status; + } + + return SmmTrigger (Data); +} + +/** + Clears an SMI. + + @param PeiServices Describes the list of possible PEI Services. + @param This Pointer to an instance of EFI_SMM_CONTROL_PPI + @param Periodic TRUE to indicate a periodical SMI + + @return Return value from SmmClear() + +**/ +EFI_STATUS +EFIAPI +PeiDeactivate ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_SMM_CONTROL_PPI *This, + IN BOOLEAN Periodic OPTIONAL + ) +{ + if (Periodic) { + return EFI_INVALID_PARAMETER; + } + return SmmClear (); +} + +/** + This is the constructor for the SMM Control Ppi. + + This function installs EFI_SMM_CONTROL_PPI. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_UNSUPPORTED There's no Intel ICH on this platform + @return The status returned from InstallPpi(). + +--*/ +EFI_STATUS +EFIAPI +SmmControlPeiEntry ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf new file mode 100644 index 0000000000..a790641013 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf @@ -0,0 +1,51 @@ +## @file +# Component description file for SmmControlPei module. +# +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmControlPei + FILE_GUID = 60EC7720-512B-4490-9FD1-A336769AE01F + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = SmmControlPeiEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SmmControlPei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + PeimEntryPoint + DebugLib + PeiServicesLib + PcdLib + IoLib + PciLib + QNCAccessLib + +[Ppis] + gPeiSmmControlPpiGuid # ALWAYS_PRODUCED + +[Pcd] + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort + +[Depex] + TRUE diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c new file mode 100644 index 0000000000..cbcd63c036 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.c @@ -0,0 +1,927 @@ +/** @file +PCH SPI Common Driver implements the SPI Host Controller Compatibility Interface. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PchSpi.h" + +VOID +FillOutPublicInfoStruct ( + SPI_INSTANCE *SpiInstance + ) +/*++ + +Routine Description: + + Fillout SpiInstance->InitInfo; + +Arguments: + + SpiInstance - Pointer to SpiInstance to initialize + +Returns: + + NONE + +--*/ +{ + UINT8 Index; + + SpiInstance->InitInfo.InitTable = &SpiInstance->SpiInitTable; + + // + // Give invalid index in case operation not supported. + // + SpiInstance->InitInfo.JedecIdOpcodeIndex = 0xff; + SpiInstance->InitInfo.OtherOpcodeIndex = 0xff; + SpiInstance->InitInfo.WriteStatusOpcodeIndex = 0xff; + SpiInstance->InitInfo.ProgramOpcodeIndex = 0xff; + SpiInstance->InitInfo.ReadOpcodeIndex = 0xff; + SpiInstance->InitInfo.EraseOpcodeIndex = 0xff; + SpiInstance->InitInfo.ReadStatusOpcodeIndex = 0xff; + SpiInstance->InitInfo.FullChipEraseOpcodeIndex = 0xff; + for (Index = 0; Index < SPI_NUM_OPCODE; Index++) { + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) { + SpiInstance->InitInfo.JedecIdOpcodeIndex = Index; + } + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationOther) { + SpiInstance->InitInfo.OtherOpcodeIndex = Index; + } + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) { + SpiInstance->InitInfo.WriteStatusOpcodeIndex = Index; + } + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_1_Byte || + SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_64_Byte) { + SpiInstance->InitInfo.ProgramOpcodeIndex = Index; + } + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadData || + SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFastRead || + SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDualOutputFastRead) { + SpiInstance->InitInfo.ReadOpcodeIndex = Index; + } + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_256_Byte || + SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_4K_Byte || + SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_8K_Byte || + SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_64K_Byte) { + SpiInstance->InitInfo.EraseOpcodeIndex = Index; + } + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadStatus) { + SpiInstance->InitInfo.ReadStatusOpcodeIndex = Index; + } + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFullChipErase) { + SpiInstance->InitInfo.FullChipEraseOpcodeIndex = Index; + } + } +} + +EFI_STATUS +SpiProtocolConstructor ( + SPI_INSTANCE *SpiInstance + ) +/*++ + +Routine Description: + + Initialize an SPI protocol instance. + The function will assert in debug if PCH RCBA has not been initialized + +Arguments: + + SpiInstance - Pointer to SpiInstance to initialize + +Returns: + + EFI_SUCCESS The protocol instance was properly initialized + EFI_UNSUPPORTED The PCH is not supported by this module + +--*/ +{ + SpiInstance->InitDone = FALSE; // Indicate NOT READY. + + // + // Check if the current PCH is known and supported by this code + // + if (!IsQncSupported ()) { + DEBUG ((DEBUG_ERROR, "PCH SPI Protocol not supported due to no proper QNC LPC found!\n")); + return EFI_UNSUPPORTED; + } + // + // Initialize the SPI protocol instance + // + SpiInstance->Signature = PCH_SPI_PRIVATE_DATA_SIGNATURE; + SpiInstance->Handle = NULL; + SpiInstance->SpiProtocol.Init = SpiProtocolInit; + SpiInstance->SpiProtocol.Lock = SpiProtocolLock; + SpiInstance->SpiProtocol.Execute = SpiProtocolExecute; + SpiInstance->SpiProtocol.Info = SpiProtocolInfo; + + // + // Sanity check to ensure PCH RCBA initialization has occurred previously. + // + SpiInstance->PchRootComplexBar = MmioRead32 ( + PciDeviceMmBase (PCI_BUS_NUMBER_QNC, + PCI_DEVICE_NUMBER_QNC_LPC, + PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_RCBA + ) & B_QNC_LPC_RCBA_MASK; + ASSERT (SpiInstance->PchRootComplexBar != 0); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UnlockFlashComponents ( + IN EFI_SPI_PROTOCOL *This, + IN UINT8 UnlockCmdOpcodeIndex + ) +/*++ + +Routine Description: + + Issue unlock command to disable block protection, this only needs to be done once per SPI power on + +Arguments: + + This A pointer to "EFI_SPI_PROTOCOL" for issuing commands + UnlockCmdOpcodeIndex The index of the Unlock command + +Returns: + + EFI_SUCCESS UnLock operation succeed. + EFI_DEVICE_ERROR Device error, operation failed. + +--*/ +{ + EFI_STATUS Status; + SPI_INSTANCE *SpiInstance; + UINT8 SpiStatus; + + if (UnlockCmdOpcodeIndex >= SPI_NUM_OPCODE) { + return EFI_UNSUPPORTED; + } + + SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This); + + // + // Issue unlock command to disable block protection, this only needs to be done once per SPI power on + // + SpiStatus = 0; + // + // Issue unlock command to the flash component 1 at first + // + Status = SpiProtocolExecute ( + This, + UnlockCmdOpcodeIndex, + SpiInstance->SpiInitTable.PrefixOpcode[0] == PCH_SPI_COMMAND_WRITE_ENABLE ? 0 : 1, + TRUE, + TRUE, + TRUE, + (UINTN) 0, + sizeof (SpiStatus), + &SpiStatus, + EnumSpiRegionAll + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Unlock flash component 1 fail!\n")); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiProtocolInit ( + IN EFI_SPI_PROTOCOL *This, + IN SPI_INIT_TABLE *InitTable + ) +/*++ + +Routine Description: + + Initialize the host controller to execute SPI command. + +Arguments: + + This Pointer to the EFI_SPI_PROTOCOL instance. + InitTable Initialization data to be programmed into the SPI host controller. + +Returns: + + EFI_SUCCESS Initialization completed. + EFI_ACCESS_DENIED The SPI static configuration interface has been locked-down. + EFI_INVALID_PARAMETER Bad input parameters. + EFI_UNSUPPORTED Can't get Descriptor mode VSCC values +--*/ +{ + EFI_STATUS Status; + UINT8 Index; + UINT16 OpcodeType; + SPI_INSTANCE *SpiInstance; + UINTN PchRootComplexBar; + UINT8 UnlockCmdOpcodeIndex; + UINT8 FlashPartId[3]; + + SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This); + PchRootComplexBar = SpiInstance->PchRootComplexBar; + + if (InitTable != NULL) { + // + // Copy table into SPI driver Private data structure + // + CopyMem ( + &SpiInstance->SpiInitTable, + InitTable, + sizeof (SPI_INIT_TABLE) + ); + } else { + return EFI_INVALID_PARAMETER; + } + // + // Check if the SPI interface has been locked-down. + // + if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) { + ASSERT_EFI_ERROR (EFI_ACCESS_DENIED); + return EFI_ACCESS_DENIED; + } + // + // Clear all the status bits for status regs. + // + MmioOr16 ( + (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS), + (UINT16) ((B_QNC_RCRB_SPIS_CDS | B_QNC_RCRB_SPIS_BAS)) + ); + MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS); + + // + // Set the Prefix Opcode registers. + // + MmioWrite16 ( + PchRootComplexBar + R_QNC_RCRB_SPIPREOP, + (SpiInstance->SpiInitTable.PrefixOpcode[1] << 8) | InitTable->PrefixOpcode[0] + ); + MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIPREOP); + + // + // Set Opcode Type Configuration registers. + // + for (Index = 0, OpcodeType = 0; Index < SPI_NUM_OPCODE; Index++) { + switch (SpiInstance->SpiInitTable.OpcodeMenu[Index].Type) { + case EnumSpiOpcodeRead: + OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_READ << (Index * 2)); + break; + case EnumSpiOpcodeWrite: + OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_WRITE << (Index * 2)); + break; + case EnumSpiOpcodeWriteNoAddr: + OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE << (Index * 2)); + break; + default: + OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_READ << (Index * 2)); + break; + } + } + MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE, OpcodeType); + MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE); + + // + // Setup the Opcode Menu registers. + // + UnlockCmdOpcodeIndex = SPI_NUM_OPCODE; + for (Index = 0; Index < SPI_NUM_OPCODE; Index++) { + MmioWrite8 ( + PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index, + SpiInstance->SpiInitTable.OpcodeMenu[Index].Code + ); + MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index); + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) { + Status = SpiProtocolExecute ( + This, + Index, + 0, + TRUE, + TRUE, + FALSE, + (UINTN) 0, + 3, + FlashPartId, + EnumSpiRegionDescriptor + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (FlashPartId[0] != SpiInstance->SpiInitTable.VendorId || + FlashPartId[1] != SpiInstance->SpiInitTable.DeviceId0 || + FlashPartId[2] != SpiInstance->SpiInitTable.DeviceId1) { + return EFI_INVALID_PARAMETER; + } + } + + if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) { + UnlockCmdOpcodeIndex = Index; + } + } + + Status = UnlockFlashComponents ( + This, + UnlockCmdOpcodeIndex + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Unlock flash components fail!\n")); + } + + SpiPhaseInit (); + FillOutPublicInfoStruct (SpiInstance); + SpiInstance->InitDone = TRUE; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiProtocolLock ( + IN EFI_SPI_PROTOCOL *This + ) +/*++ + +Routine Description: + + Lock the SPI Static Configuration Interface. + Once locked, the interface can not be changed and can only be clear by system reset. + +Arguments: + + This Pointer to the EFI_SPI_PROTOCOL instance. + +Returns: + + EFI_SUCCESS Lock operation succeed. + EFI_DEVICE_ERROR Device error, operation failed. + EFI_ACCESS_DENIED The interface has already been locked. + +--*/ +{ + SPI_INSTANCE *SpiInstance; + UINTN PchRootComplexBar; + + SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This); + PchRootComplexBar = SpiInstance->PchRootComplexBar; + + // + // Check if the SPI interface has been locked-down. + // + if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) { + return EFI_ACCESS_DENIED; + } + + // + // Lock-down the configuration interface. + // + MmioOr16 ((UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS), (UINT16) (B_QNC_RCRB_SPIS_SCL)); + + // + // Verify if it's really locked. + // + if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) == 0) { + return EFI_DEVICE_ERROR; + } else { + // + // Save updated register in S3 Boot script. + // + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint16, + (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS), + 1, + (VOID *) (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS) + ); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiProtocolExecute ( + IN EFI_SPI_PROTOCOL *This, + IN UINT8 OpcodeIndex, + IN UINT8 PrefixOpcodeIndex, + IN BOOLEAN DataCycle, + IN BOOLEAN Atomic, + IN BOOLEAN ShiftOut, + IN UINTN Address, + IN UINT32 DataByteCount, + IN OUT UINT8 *Buffer, + IN SPI_REGION_TYPE SpiRegionType + ) +/*++ + +Routine Description: + + Execute SPI commands from the host controller. + This function would be called by runtime driver, please do not use any MMIO marco here + +Arguments: + + This Pointer to the EFI_SPI_PROTOCOL instance. + OpcodeIndex Index of the command in the OpCode Menu. + PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence. + DataCycle TRUE if the SPI cycle contains data + Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed. + ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in. + Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform + Region, this value specifies the offset from the Region Base; for BIOS Region, + this value specifies the offset from the start of the BIOS Image. In Non + Descriptor Mode, this value specifies the offset from the start of the BIOS Image. + Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor + Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is + supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or + the flash (in Non Descriptor Mode) + DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the + data transfer into multiple operations. This function ensures each operation does + not cross 256 byte flash address boundary. + *NOTE: if there is some SPI chip that has a stricter address boundary requirement + (e.g., its write page size is < 256 byte), then the caller cannot rely on this + function to cut the data transfer at proper address boundaries, and it's the + caller's reponsibility to pass in a properly cut DataByteCount parameter. + Buffer Pointer to caller-allocated buffer containing the dada received or sent during the + SPI cycle. + SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe, + EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in + Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode + and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative + to base of the 1st flash device (i.e., it is a Flash Linear Address). + +Returns: + + EFI_SUCCESS Command succeed. + EFI_INVALID_PARAMETER The parameters specified are not valid. + EFI_UNSUPPORTED Command not supported. + EFI_DEVICE_ERROR Device error, command aborts abnormally. + +--*/ +{ + EFI_STATUS Status; + UINT16 BiosCtlSave; + UINT32 SmiEnSave; + + BiosCtlSave = 0; + SmiEnSave = 0; + + // + // Check if the parameters are valid. + // + if ((OpcodeIndex >= SPI_NUM_OPCODE) || (PrefixOpcodeIndex >= SPI_NUM_PREFIX_OPCODE)) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure it's safe to program the command. + // + if (!WaitForSpiCycleComplete (This, FALSE)) { + return EFI_DEVICE_ERROR; + } + + // + // Acquire access to the SPI interface is not required any more. + // + // + // Disable SMIs to make sure normal mode flash access is not interrupted by an SMI + // whose SMI handler accesses flash (e.g. for error logging) + // + SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN)); + + // + // Save BIOS Ctrl register + // + BiosCtlSave = PciRead16 ( + PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, + PCI_DEVICE_NUMBER_QNC_LPC, + PCI_FUNCTION_NUMBER_QNC_LPC, + R_QNC_LPC_BIOS_CNTL) + ) & (B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP); + + // + // Enable flash writing + // + PciOr16 ( + PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, + PCI_DEVICE_NUMBER_QNC_LPC, + PCI_FUNCTION_NUMBER_QNC_LPC, + R_QNC_LPC_BIOS_CNTL), + (UINT16) (B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP) + ); + + // + // If shifts the data out, disable Prefetching and Caching. + // + if (ShiftOut) { + PciAndThenOr16 ( + PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, + PCI_DEVICE_NUMBER_QNC_LPC, + PCI_FUNCTION_NUMBER_QNC_LPC, + R_QNC_LPC_BIOS_CNTL), + (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE)), + (UINT16) ((B_QNC_LPC_BIOS_CNTL_BCD)) + ); + } + // + // Sends the command to the SPI interface to execute. + // + Status = SendSpiCmd ( + This, + OpcodeIndex, + PrefixOpcodeIndex, + DataCycle, + Atomic, + ShiftOut, + Address, + DataByteCount, + Buffer, + SpiRegionType + ); + + // + // Restore BIOS Ctrl register + // + PciAndThenOr16 ( + PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC, + PCI_DEVICE_NUMBER_QNC_LPC, + PCI_FUNCTION_NUMBER_QNC_LPC, + R_QNC_LPC_BIOS_CNTL), + (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)), + (UINT16) (BiosCtlSave) + ); + // + // Restore SMIs. + // + QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, SmiEnSave); + + return Status; +} + +VOID +SpiOffset2Physical ( + IN EFI_SPI_PROTOCOL *This, + IN UINTN SpiRegionOffset, + IN SPI_REGION_TYPE SpiRegionType, + OUT UINTN *HardwareSpiAddress, + OUT UINTN *BaseAddress, + OUT UINTN *LimitAddress + ) +/*++ + +Routine Description: + + Convert SPI offset to Physical address of SPI hardware + +Arguments: + + This Pointer to the EFI_SPI_PROTOCOL instance. + SpiRegionOffset In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform + Region, this value specifies the offset from the Region Base; for BIOS Region, + this value specifies the offset from the start of the BIOS Image. In Non + Descriptor Mode, this value specifies the offset from the start of the BIOS Image. + Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor + Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is + supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or + the flash (in Non Descriptor Mode) + BaseAddress Base Address of the region. + SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe, + EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in + Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode + and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative + to base of the 1st flash device (i.e., it is a Flash Linear Address). + HardwareSpiAddress Return absolution SPI address (i.e., Flash Linear Address) + BaseAddress Return base address of the region type + LimitAddress Return limit address of the region type + +Returns: + + EFI_SUCCESS Command succeed. + +--*/ +{ + SPI_INSTANCE *SpiInstance; + + SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This); + + if (SpiRegionType == EnumSpiRegionAll) { + // + // EnumSpiRegionAll indicates address is relative to flash device (i.e., address is Flash + // Linear Address) + // + *HardwareSpiAddress = SpiRegionOffset; + } else { + // + // Otherwise address is relative to BIOS image + // + *HardwareSpiAddress = SpiRegionOffset + SpiInstance->SpiInitTable.BiosStartOffset; + } +} + +EFI_STATUS +SendSpiCmd ( + IN EFI_SPI_PROTOCOL *This, + IN UINT8 OpcodeIndex, + IN UINT8 PrefixOpcodeIndex, + IN BOOLEAN DataCycle, + IN BOOLEAN Atomic, + IN BOOLEAN ShiftOut, + IN UINTN Address, + IN UINT32 DataByteCount, + IN OUT UINT8 *Buffer, + IN SPI_REGION_TYPE SpiRegionType + ) +/*++ + +Routine Description: + + This function sends the programmed SPI command to the slave device. + +Arguments: + + OpcodeIndex Index of the command in the OpCode Menu. + PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence. + DataCycle TRUE if the SPI cycle contains data + Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed. + ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in. + Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform + Region, this value specifies the offset from the Region Base; for BIOS Region, + this value specifies the offset from the start of the BIOS Image. In Non + Descriptor Mode, this value specifies the offset from the start of the BIOS Image. + Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor + Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is + supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or + the flash (in Non Descriptor Mode) + DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the + data transfer into multiple operations. This function ensures each operation does + not cross 256 byte flash address boundary. + *NOTE: if there is some SPI chip that has a stricter address boundary requirement + (e.g., its write page size is < 256 byte), then the caller cannot rely on this + function to cut the data transfer at proper address boundaries, and it's the + caller's reponsibility to pass in a properly cut DataByteCount parameter. + Buffer Data received or sent during the SPI cycle. + SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe, + EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in + Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode + and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative + to base of the 1st flash device (i.e., it is a Flash Linear Address). + +Returns: + + EFI_SUCCESS SPI command completes successfully. + EFI_DEVICE_ERROR Device error, the command aborts abnormally. + EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode + EFI_INVALID_PARAMETER The parameters specified are not valid. + +--*/ +{ + UINT32 Index; + SPI_INSTANCE *SpiInstance; + UINTN HardwareSpiAddr; + UINTN SpiBiosSize; + UINTN BaseAddress; + UINTN LimitAddress; + UINT32 SpiDataCount; + UINT8 OpCode; + UINTN PchRootComplexBar; + + SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This); + PchRootComplexBar = SpiInstance->PchRootComplexBar; + SpiBiosSize = SpiInstance->SpiInitTable.BiosSize; + OpCode = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + OpcodeIndex); + + // + // Check if the value of opcode register is 0 or the BIOS Size of SpiInitTable is 0 + // + if (OpCode == 0 || SpiBiosSize == 0) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + SpiOffset2Physical (This, Address, SpiRegionType, &HardwareSpiAddr, &BaseAddress, &LimitAddress); + // + // Have direct access to BIOS region in Descriptor mode, + // + if (SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex].Type == EnumSpiOpcodeRead && + SpiRegionType == EnumSpiRegionBios) { + CopyMem ( + Buffer, + (UINT8 *) ((HardwareSpiAddr - BaseAddress) + (UINT32) (~(SpiBiosSize - 1))), + DataByteCount + ); + return EFI_SUCCESS; + } + // + // DEBUG((EFI_D_ERROR, "SPIADDR %x, %x, %x, %x\n", Address, HardwareSpiAddr, BaseAddress, + // LimitAddress)); + // + if ((DataCycle == FALSE) && (DataByteCount > 0)) { + DataByteCount = 0; + } + + do { + // + // Trim at 256 byte boundary per operation, + // - PCH SPI controller requires trimming at 4KB boundary + // - Some SPI chips require trimming at 256 byte boundary for write operation + // - Trimming has limited performance impact as we can read / write atmost 64 byte + // per operation + // + if (HardwareSpiAddr + DataByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 - 1))) { + SpiDataCount = (((UINT32) (HardwareSpiAddr) + BIT8) &~(BIT8 - 1)) - (UINT32) (HardwareSpiAddr); + } else { + SpiDataCount = DataByteCount; + } + // + // Calculate the number of bytes to shift in/out during the SPI data cycle. + // Valid settings for the number of bytes duing each data portion of the + // PCH SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64 + // + if (SpiDataCount >= 64) { + SpiDataCount = 64; + } else if ((SpiDataCount &~0x07) != 0) { + SpiDataCount = SpiDataCount &~0x07; + } + // + // If shifts data out, load data into the SPI data buffer. + // + if (ShiftOut) { + for (Index = 0; Index < SpiDataCount; Index++) { + MmioWrite8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index, Buffer[Index]); + MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index); + } + } + + MmioWrite32 ( + (PchRootComplexBar + R_QNC_RCRB_SPIA), + (UINT32) (HardwareSpiAddr & B_QNC_RCRB_SPIA_MASK) + ); + MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIA); + + // + // Execute the command on the SPI compatible mode + // + + // + // Clear error flags + // + MmioOr16 ((PchRootComplexBar + R_QNC_RCRB_SPIS), B_QNC_RCRB_SPIS_BAS); + + // + // Initialte the SPI cycle + // + if (DataCycle) { + MmioWrite16 ( + (PchRootComplexBar + R_QNC_RCRB_SPIC), + ( (UINT16) (B_QNC_RCRB_SPIC_DC) | (UINT16) (((SpiDataCount - 1) << 8) & B_QNC_RCRB_SPIC_DBC) | + (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) | + (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) | + (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) | + (UINT16) (B_QNC_RCRB_SPIC_SCGO))); + } else { + MmioWrite16 ( + (PchRootComplexBar + R_QNC_RCRB_SPIC), + ( (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) | + (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) | + (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) | + (UINT16) (B_QNC_RCRB_SPIC_SCGO))); + } + + MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIC); + + // + // end of command execution + // + // Wait the SPI cycle to complete. + // + if (!WaitForSpiCycleComplete (This, TRUE)) { + return EFI_DEVICE_ERROR; + } + // + // If shifts data in, get data from the SPI data buffer. + // + if (!ShiftOut) { + for (Index = 0; Index < SpiDataCount; Index++) { + Buffer[Index] = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index); + } + } + + HardwareSpiAddr += SpiDataCount; + Buffer += SpiDataCount; + DataByteCount -= SpiDataCount; + } while (DataByteCount > 0); + + return EFI_SUCCESS; +} + +BOOLEAN +WaitForSpiCycleComplete ( + IN EFI_SPI_PROTOCOL *This, + IN BOOLEAN ErrorCheck + ) +/*++ + +Routine Description: + + Wait execution cycle to complete on the SPI interface. Check both Hardware + and Software Sequencing status registers + +Arguments: + + This - The SPI protocol instance + UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation + ErrorCheck - TRUE if the SpiCycle needs to do the error check + +Returns: + + TRUE SPI cycle completed on the interface. + FALSE Time out while waiting the SPI cycle to complete. + It's not safe to program the next command on the SPI interface. + +--*/ +{ + UINT64 WaitTicks; + UINT64 WaitCount; + UINT16 Data16; + SPI_INSTANCE *SpiInstance; + UINTN PchRootComplexBar; + + SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This); + PchRootComplexBar = SpiInstance->PchRootComplexBar; + + // + // Convert the wait period allowed into to tick count + // + WaitCount = WAIT_TIME / WAIT_PERIOD; + + // + // Wait for the SPI cycle to complete. + // + for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) { + Data16 = MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS); + if ((Data16 & B_QNC_RCRB_SPIS_SCIP) == 0) { + MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIS, (B_QNC_RCRB_SPIS_BAS | B_QNC_RCRB_SPIS_CDS)); + if ((Data16 & B_QNC_RCRB_SPIS_BAS) && (ErrorCheck == TRUE)) { + return FALSE; + } else { + return TRUE; + } + } + + MicroSecondDelay (WAIT_PERIOD); + } + + return FALSE; +} + +EFI_STATUS +EFIAPI +SpiProtocolInfo ( + IN EFI_SPI_PROTOCOL *This, + OUT SPI_INIT_INFO **InitInfoPtr + ) +/*++ + +Routine Description: + + Return info about SPI host controller, to help callers usage of Execute + service. + + If 0xff is returned as an opcode index in init info struct + then device does not support the operation. + +Arguments: + + This Pointer to the EFI_SPI_PROTOCOL instance. + InitInfoPtr Pointer to init info written to this memory location. + +Returns: + + EFI_SUCCESS Information returned. + EFI_INVALID_PARAMETER Invalid parameter. + EFI_NOT_READY Required resources not setup. + Others Unexpected error happened. + +--*/ +{ + SPI_INSTANCE *SpiInstance; + + if (This == NULL || InitInfoPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This); + if (SpiInstance->Signature != PCH_SPI_PRIVATE_DATA_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + if (!SpiInstance->InitDone) { + *InitInfoPtr = NULL; + return EFI_NOT_READY; + } + *InitInfoPtr = &SpiInstance->InitInfo; + return EFI_SUCCESS; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h new file mode 100644 index 0000000000..1e3a50d30c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Common/SpiCommon.h @@ -0,0 +1,317 @@ +/** @file +Header file for the PCH SPI Common Driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef _SPI_COMMON_H_ +#define _SPI_COMMON_H_ + +#include "Protocol/Spi.h" +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf new file mode 100644 index 0000000000..c20c12c91d --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf @@ -0,0 +1,84 @@ +## @file +# Component description file for the SPI Runtime driver. +# +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PchSpiRuntime + FILE_GUID = C194C6EA-B68C-4981-B64B-9BD271474B20 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InstallPchSpi + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +################################################################################ +# +# Sources Section - list of files that are required for the build to succeed. +# +################################################################################ +[Sources] + RuntimeDxe/PchSpi.h + RuntimeDxe/PchSpi.c + Common/SpiCommon.c + Common/SpiCommon.h + +################################################################################ +# +# Package Dependency Section - list of Package files that are required for +# this module. +# +################################################################################ +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +################################################################################ +# +# Library Class Section - list of Library Classes that are required for +# this module. +# +################################################################################ +[LibraryClasses] + UefiRuntimeServicesTableLib + UefiRuntimeLib + UefiBootServicesTableLib + UefiDriverEntryPoint + IntelQNCLib + QNCAccessLib + TimerLib + DxeServicesTableLib + UefiLib + DebugLib + MemoryAllocationLib + S3BootScriptLib + PciExpressLib + +################################################################################ +# +# Protocol C Name Section - list of Protocol and Protocol Notify C Names +# that this module uses or produces. +# +################################################################################ +[Protocols] + gEfiSpiProtocolGuid + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress + gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioSize + +[Depex] + TRUE diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf new file mode 100644 index 0000000000..13b2f77e0a --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf @@ -0,0 +1,50 @@ +## @file +# Spi smm driver +# +# Component description file for the SPI SMM driver. +# +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[defines] + INF_VERSION = 0x00010005 + BASE_NAME = PchSpiSmm + FILE_GUID = 27F4917B-A707-4aad-9676-26DF168CBF0D + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = InstallPchSpi + +[Sources] + Smm/PchSpi.h + Smm/PchSpi.c + Common/SpiCommon.c + Common/SpiCommon.h + +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + DebugLib + IoLib + IntelQNCLib + QNCAccessLib + TimerLib + S3BootScriptLib + UefiDriverEntryPoint + UefiBootServicesTableLib + BaseLib + SmmServicesTableLib + +[Protocols] + gEfiSmmSpiProtocolGuid # PRODUCES + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress + +[Depex] + gEfiSmmBase2ProtocolGuid diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c new file mode 100644 index 0000000000..393d60b29e --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.c @@ -0,0 +1,205 @@ +/** @file +PCH SPI Runtime Driver implements the SPI Host Controller Compatibility Interface. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "PchSpi.h" + +extern EFI_GUID gEfiEventVirtualAddressChangeGuid; + +// +// Global variables +// +SPI_INSTANCE *mSpiInstance; +CONST UINT32 mSpiRegister[] = { + R_QNC_RCRB_SPIS, + R_QNC_RCRB_SPIPREOP, + R_QNC_RCRB_SPIOPMENU, + R_QNC_RCRB_SPIOPMENU + 4 + }; + +// +// Function implementations +// +VOID +PchSpiVirtualddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Fixup internal data pointers so that the services can be called in virtual mode. + +Arguments: + + Event The event registered. + Context Event context. Not used in this event handler. + +Returns: + + None. + +--*/ +{ + gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->PchRootComplexBar)); + gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Init)); + gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Lock)); + gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Execute)); + gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance)); +} + +EFI_STATUS +EFIAPI +InstallPchSpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Entry point for the SPI host controller driver. + +Arguments: + + ImageHandle Image handle of this driver. + SystemTable Global system service table. + +Returns: + + EFI_SUCCESS Initialization complete. + EFI_UNSUPPORTED The chipset is unsupported by this driver. + EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver. + EFI_DEVICE_ERROR Device error, driver exits abnormally. + +--*/ +{ + EFI_STATUS Status; + UINT64 BaseAddress; + UINT64 Length; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdMemorySpaceDescriptor; + UINT64 Attributes; + EFI_EVENT Event; + + DEBUG ((DEBUG_INFO, "InstallPchSpi() Start\n")); + + // + // Allocate Runtime memory for the SPI protocol instance. + // + mSpiInstance = AllocateRuntimeZeroPool (sizeof (SPI_INSTANCE)); + if (mSpiInstance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Initialize the SPI protocol instance + // + Status = SpiProtocolConstructor (mSpiInstance); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Install the EFI_SPI_PROTOCOL interface + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &(mSpiInstance->Handle), + &gEfiSpiProtocolGuid, + &(mSpiInstance->SpiProtocol), + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (mSpiInstance); + return EFI_DEVICE_ERROR; + } + // + // Set RCBA space in GCD to be RUNTIME so that the range will be supported in + // virtual address mode in EFI aware OS runtime. + // It will assert if RCBA Memory Space is not allocated + // The caller is responsible for the existence and allocation of the RCBA Memory Spaces + // + BaseAddress = (EFI_PHYSICAL_ADDRESS) (mSpiInstance->PchRootComplexBar); + Length = PcdGet64 (PcdRcbaMmioSize); + + Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdMemorySpaceDescriptor); + ASSERT_EFI_ERROR (Status); + + Attributes = GcdMemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME; + + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + BaseAddress, + Length, + EFI_MEMORY_RUNTIME | EFI_MEMORY_UC + ); + ASSERT_EFI_ERROR(Status); + + Status = gDS->SetMemorySpaceAttributes ( + BaseAddress, + Length, + Attributes + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PchSpiVirtualddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "InstallPchSpi() End\n")); + + return EFI_SUCCESS; +} + +VOID +EFIAPI +SpiPhaseInit ( + VOID + ) +/*++ +Routine Description: + + This function is a a hook for Spi Dxe phase specific initialization + +Arguments: + + None + +Returns: + + None + +--*/ +{ + UINTN Index; + + // + // Disable SMM BIOS write protect if it's not a SMM protocol + // + MmioAnd8 ( + PciDeviceMmBase (PCI_BUS_NUMBER_QNC, + PCI_DEVICE_NUMBER_QNC_LPC, + PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_BIOS_CNTL, + (UINT8) (~B_QNC_LPC_BIOS_CNTL_SMM_BWP) + ); + + // + // Save SPI Registers for S3 resume usage + // + for (Index = 0; Index < sizeof (mSpiRegister) / sizeof (UINT32); Index++) { + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint32, + (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]), + 1, + (VOID *) (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]) + ); + } +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h new file mode 100644 index 0000000000..33d64297f5 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/RuntimeDxe/PchSpi.h @@ -0,0 +1,79 @@ +/** @file +Header file for the PCH SPI Runtime Driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PCH_SPI_H_ +#define _PCH_SPI_H_ + +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c new file mode 100644 index 0000000000..fe5cde3de7 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.c @@ -0,0 +1,123 @@ +/** @file + +PCH SPI SMM Driver implements the SPI Host Controller Compatibility Interface. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ +#include "PchSpi.h" + +SPI_INSTANCE *mSpiInstance; + +CONST UINT32 mSpiRegister[] = { + R_QNC_RCRB_SPIS, + R_QNC_RCRB_SPIPREOP, + R_QNC_RCRB_SPIOPMENU, + R_QNC_RCRB_SPIOPMENU + 4 + }; + +EFI_STATUS +EFIAPI +InstallPchSpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Entry point for the SPI host controller driver. + +Arguments: + + ImageHandle Image handle of this driver. + SystemTable Global system service table. + +Returns: + + EFI_SUCCESS Initialization complete. + EFI_UNSUPPORTED The chipset is unsupported by this driver. + EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver. + EFI_DEVICE_ERROR Device error, driver exits abnormally. + +--*/ +{ + EFI_STATUS Status; + + // + // Allocate pool for SPI protocol instance + // + Status = gSmst->SmmAllocatePool ( + EfiRuntimeServicesData, // MemoryType don't care + sizeof (SPI_INSTANCE), + (VOID **) &mSpiInstance + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (mSpiInstance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + ZeroMem ((VOID *) mSpiInstance, sizeof (SPI_INSTANCE)); + // + // Initialize the SPI protocol instance + // + Status = SpiProtocolConstructor (mSpiInstance); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Install the SMM EFI_SPI_PROTOCOL interface + // + Status = gSmst->SmmInstallProtocolInterface ( + &(mSpiInstance->Handle), + &gEfiSmmSpiProtocolGuid, + EFI_NATIVE_INTERFACE, + &(mSpiInstance->SpiProtocol) + ); + if (EFI_ERROR (Status)) { + gSmst->SmmFreePool (mSpiInstance); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +VOID +EFIAPI +SpiPhaseInit ( + VOID + ) +/*++ +Routine Description: + + This function is a a hook for Spi Smm phase specific initialization + +Arguments: + + None + +Returns: + + None + +--*/ +{ + UINTN Index; + + // + // Save SPI Registers for S3 resume usage + // + for (Index = 0; Index < sizeof (mSpiRegister) / sizeof (UINT32); Index++) { + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint32, + (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]), + 1, + (VOID *) (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]) + ); + } +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h new file mode 100644 index 0000000000..a016a0e7c4 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkNorthCluster/Spi/Smm/PchSpi.h @@ -0,0 +1,47 @@ +/** @file +Header file for the PCH SPI SMM Driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PCH_SPI_H_ +#define _PCH_SPI_H_ + +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec b/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec new file mode 100644 index 0000000000..22cb0a2d79 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dec @@ -0,0 +1,234 @@ +## @file +# INTEL Quark SoC Module Package Reference Implementations +# +# This Module provides FRAMEWORK reference implementation for INTEL Quark SoC. +# Copyright (c) 2013-2015 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = QuarkSocPkg + PACKAGE_GUID = 28DECF17-6C75-448f-87DC-BDE4BD579919 + PACKAGE_VERSION = 0.1 + + + +################################################################################ +# +# Include Section - list of Include Paths that are provided by this package. +# Comments are used for Keywords and Module Types. +# +# Supported Module Types: +# SEC PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER BASE +# +################################################################################ +[Includes] + # + # North Cluster + # + QuarkNorthCluster/Include + QuarkNorthCluster/MemoryInit/Pei + + # + # South Cluster + # + QuarkSouthCluster/Include + +################################################################################ +# +# Library Class Header section - list of Library Class header files that are +# provided by this package. +# +################################################################################ +[LibraryClasses] + # + # North Cluster + # + QNCAccessLib|QuarkNorthCluster/Include/Library/QNCAccessLib.h + IntelQNCLib|QuarkNorthCluster/Include/Library/IntelQNCLib.h + IohLib|QuarkSouthCluster/Include/Library/IohLib.h + I2cLib|QuarkSouthCluster/Include/Library/I2cLib.h + +################################################################################ +# +# Global Guid Definition section - list of Global Guid C Name Data Structures +# that are provided by this package. +# +################################################################################ +[Guids] + # + # North Cluster + # + gEfiQuarkNcSocIdTokenSpaceGuid = { 0xca452c6a, 0xdf0c, 0x4dc9, { 0x82, 0xfb, 0xea, 0xe2, 0xab, 0x31, 0x29, 0x46 }} + gQncS3CodeInLockBoxGuid = { 0x1f18c5b3, 0x29ed, 0x4d9e, {0xa5, 0x4, 0x6d, 0x97, 0x8e, 0x7e, 0xd5, 0x69}} + gQncS3ContextInLockBoxGuid = { 0xe5769ea9, 0xe706, 0x454b, {0x95, 0x7f, 0xaf, 0xc6, 0xdb, 0x4b, 0x8a, 0xd}} + + # + # South Cluster + # + gEfiQuarkSCSocIdTokenSpaceGuid = { 0xef251b71, 0xceed, 0x484e, { 0x82, 0xe3, 0x3a, 0x1f, 0x34, 0xf5, 0x12, 0xe2 }} + +################################################################################ +# +# Global Ppi Definition section - list of Global Ppi C Name Data Structures +# that are provided by this package. +# +################################################################################ +[Ppis] + # + # North Cluster + # + gQNCMemoryInitPpiGuid = { 0x21ff1fee, 0xd33a, 0x4fce, { 0xa6, 0x5e, 0x95, 0x5e, 0xa3, 0xc4, 0x1f, 0x40}} + +################################################################################ +# +# Global Protocols Definition section - list of Global Protocols C Name Data +# Structures that are provided by this package. +# +################################################################################ +[Protocols] + # + # North Cluster + # + gEfiPlatformPolicyProtocolGuid = { 0x2977064F, 0xAB96, 0x4FA9, { 0x85, 0x45, 0xF9, 0xC4, 0x02, 0x51, 0xE0, 0x7F }} + gEfiSmmIchnDispatch2ProtocolGuid = { 0xadf3a128, 0x416d, 0x4060, { 0x8d, 0xdf, 0x30, 0xa1, 0xd7, 0xaa, 0xb6, 0x99 }} + gEfiSpiProtocolGuid = { 0x1156efc6, 0xea32, 0x4396, { 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 }} + gEfiSmmSpiProtocolGuid = { 0xD9072C35, 0xEB8F, 0x43ad, { 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 }} + gEfiQncS3SupportProtocolGuid = { 0xe287d20b, 0xd897, 0x4e1e, { 0xa5, 0xd9, 0x97, 0x77, 0x63, 0x93, 0x6a, 0x4 }} + + # + # South Cluster + # + gEfiSDHostIoProtocolGuid = {0xb63f8ec7, 0xa9c9, 0x4472, {0xa4, 0xc0, 0x4d, 0x8b, 0xf3, 0x65, 0xcc, 0x51}} + +################################################################################ +# +# PCD Declarations section - list of all PCDs Declared by this Package +# Only this package should be providing the +# declaration, other packages should not. +# +################################################################################ + +[PcdsFeatureFlag] + # + # North Cluster + # + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed|TRUE|BOOLEAN|0x10000001 + + # + # South Cluster + # + gEfiQuarkSCSocIdTokenSpaceGuid.PcdEhciRecoveryEnabled|FALSE|BOOLEAN|0x10000003 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdI2CFastModeEnabled|FALSE|BOOLEAN|0x10000005 + + # + # Feature Flag equivalent to linux SDHCI_QUIRK_NO_HISPD_BIT to stop + # setting of SD HCI hi_spd_en bit in HOST_CTL register. + # + # Alway TRUE ie high speed enable bit must never + # be set so we stay within SD interface Setup/Hold time. + # + gEfiQuarkSCSocIdTokenSpaceGuid.PcdSdHciQuirkNoHiSpd|TRUE|BOOLEAN|0x10000004 + +[PcdsFixedAtBuild] + # + # North Cluster + # + + # Values of Io Port Base Address, MMIO base address and space size. + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress|0x1000|UINT16|0x10000200 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoBaseAddress|0x1010|UINT16|0x10000201 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoLVL2|0x1014|UINT16|0x10000202 + + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress|0x1080|UINT16|0x10000205 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress|0x1100|UINT16|0x10000206 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress|0x1040|UINT16|0x10000207 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdWdtbaIoBaseAddress|0x1140|UINT16|0x10000209 + + gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioBaseAddress|0xFED1C000|UINT64|0x1000020B + gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicBaseAddress|0xFEC00000|UINT64|0x1000020C + + gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicSize|0x1000|UINT64|0x1000020D + gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioSize|0x4000|UINT64|0x1000020E + + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciExpressSize|0x02000000|UINT64|0x1000020F + gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetBaseAddress|0xFED00000|UINT64|0x10000210 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetSize|0x400|UINT64|0x10000211 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdTSegSize|0x200000|UINT32|0x10000212 + + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeIoBase|0x2000|UINT16|0x10000214 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeIoSize|0xE000|UINT16|0x10000215 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory32Base|0x90000000|UINT32|0x1000021B + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory32Size|0x20000000|UINT32|0x1000021C + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory64Base|0xB0000000|UINT64|0x1000021D + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory64Size|0x30000000|UINT64|0x1000021E + + # Values for programming Interrupt Route Configuration Registers: + # Indicates which interrupt routing is connected to the INTA/B/C/D pins reported in the + # "DxIP" register fields. This will be the internal routing, the device interrupt is connected + # to the interrupt controller. + gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent0IR|0x0000|UINT16|0x10000223 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent1IR|0x7654|UINT16|0x10000224 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent2IR|0x0000|UINT16|0x10000225 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent3IR|0x3210|UINT16|0x10000226 + + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort|0xb2|UINT16|0x10000232 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort|0xb3|UINT16|0x10000233 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationData|0x55|UINT8|0x10000234 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrNum|0x0|UINT32|0x10000235 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrTable|0x0|UINT64|0x10000236 + + gEfiQuarkNcSocIdTokenSpaceGuid.PcdESramMemorySize|0x00080000|UINT32|0x10000240 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables|0x03|UINT32|0x10000237 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdPcieRootPortConfiguration|{0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00}|VOID*|0x10000239 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkMicrocodeFile |{ 0x8B, 0xEA, 0x5E, 0xD7, 0xD2, 0x23, 0xD4, 0x4E, 0xBC, 0x4F, 0x57, 0x51, 0xD4, 0xA1, 0x8D, 0xCF }|VOID*|0x1000023A + + # + # South Cluster + # + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohI2cMmioBase|0xA001F000|UINT64|0x20000005 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiP2PMemoryBaseAddress|0xA0000000|UINT32|0x20000006 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiQNCUsbControllerMemoryBaseAddress|0xA0010000|UINT32|0x20000007 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioMmioBase|0xA0020000|UINT64|0x20000008 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohMac0MmioBase|0xA0024000|UINT64|0x20000009 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohMac1MmioBase|0xA0028000|UINT64|0x2000000A + + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartBusNumber|0x00|UINT8|0x20000013 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartDevNumber|0x14|UINT8|0x20000014 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartFunctionNumber|0x5|UINT8|0x20000001 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber|0x00|UINT8|0x20000029 + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioDevNumber|0x15|UINT8|0x2000002A + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioFunctionNumber|0x2|UINT8|0x2000002B + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBarRegister|0x14|UINT8|0x2000002D + +[PcdsDynamic, PcdsDynamicEx] + # + # North Cluster + # + gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxAddress|0|UINT64|0x30000026 + gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxSize|0|UINT64|0x30000027 + + ## Intel(R) Quark(TM) Soc X1000 processor MRC Parameters. Default is for Galileo Gen 2 platform.

+ # @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/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc b/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc new file mode 100644 index 0000000000..e743a5e272 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSocPkg.dsc @@ -0,0 +1,254 @@ +## @file +# INTEL Quark SoC Module Package Reference Implementations +# +# This DSC file is used for Package Level build. +# +# This Module provides FRAMEWORK reference implementation for INTEL Quark SoC. +# Copyright (c) 2013-2016 Intel Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = QuarkSocPkg + PLATFORM_GUID = 5F9864F4-EAFB-4ded-A41A-CA501EE50502 + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/QuarkSocPkg + SUPPORTED_ARCHITECTURES = IA32 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + +################################################################################ +# +# SKU Identification section - list of all SKU IDs supported by this +# Platform. +# +################################################################################ +[SkuIds] + 0|DEFAULT # The entry: 0|DEFAULT is reserved and always required. + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ +[LibraryClasses] + # + # Entry point + # + PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + # + # Basic + # + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf + PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf + PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf + PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf + CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf + PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf +!if $(CFG_SOURCE_DEBUG) == 1 + PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf +!else + PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf +!endif + # + # UEFI & PI + # + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf + # + # Framework + # + S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf + S3IoLib|MdePkg/Library/BaseS3IoLib/BaseS3IoLib.inf + S3PciLib|MdePkg/Library/BaseS3PciLib/BaseS3PciLib.inf + # + # Generic Modules + # + OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf + + # + # CPU + # + MtrrLib|QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf + # + # Quark North Cluster + # + SmmLib|QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf + SmbusLib|QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf + TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf + ResetSystemLib|QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf + IntelQNCLib|QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf + QNCAccessLib|QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf + # + # Quark South Cluster + # + IohLib|QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf + SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf + PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf + # + # Misc + # + DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf +!if $(CFG_SOURCE_DEBUG) == TRUE + DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf +!else + DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf +!endif + +[LibraryClasses.IA32.PEIM,LibraryClasses.IA32.PEI_CORE] + # + # SEC and PEI phase common + # + PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf + MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf + LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf + PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf +!if $(CFG_SOURCE_DEBUG) == TRUE + DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf +!endif + TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf + +[LibraryClasses.IA32.SEC] + # + # SEC specific phase + # + ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf + +[LibraryClasses.IA32] + # + # DXE phase common + # + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf +!if $(CFG_SOURCE_DEBUG) == 1 + DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf +!endif + +[LibraryClasses.IA32.DXE_SMM_DRIVER] + SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf + MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf + LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf +!if $(CFG_SOURCE_DEBUG) == TRUE + DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf +!endif + +[LibraryClasses.IA32.SMM_CORE] + ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf + +[LibraryClasses.IA32.DXE_RUNTIME_DRIVER] + ReportStatusCodeLib|MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf + +[LibraryClasses.IA32.UEFI_DRIVER,LibraryClasses.IA32.UEFI_APPLICATION] + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform +# +################################################################################ + +[PcdsFixedAtBuild] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl|0x03 + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl|0x07 + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable|FALSE + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|44236800 + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0x14, 0x05, 0x84, 0x00, 0xFF} + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride|4 + + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber |0 + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber |31 + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber |0 + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset|0x4b + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask |0x80 + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset |0x48 + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress |0x1000 + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset |0x0008 + +[PcdsFeatureFlag] + +################################################################################ +# +# Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform +# +################################################################################ + +[PcdsDynamicDefault.common.DEFAULT] + +################################################################################################### +# +# Components Section - list of the modules and components that will be processed by compilation +# tools and the EDK II tools to generate PE32/PE32+/Coff image files. +# +# Note: The EDK II DSC file is not used to specify how compiled binary images get placed +# into firmware volume images. This section is just a list of modules to compile from +# source into UEFI-compliant binaries. +# It is the FDF file that contains information on combining binary files into firmware +# volume images, whose concept is beyond UEFI and is described in PI specification. +# Binary modules do not need to be listed in this section, as they should be +# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi), +# Logo (Logo.bmp), and etc. +# There may also be modules listed in this section that are not required in the FDF file, +# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be +# generated for it, but the binary will not be put into any firmware volume. +# +################################################################################################### + +[Components] + QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf + QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf + QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf + QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf + QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf + QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf { + + 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/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h new file mode 100644 index 0000000000..f038c34238 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/CEATA.h @@ -0,0 +1,114 @@ +/** @file + +Header file for chipset CE-AT spec. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _CE_ATA_H +#define _CE_ATA_H + +#pragma pack(1) + + +#define DATA_UNIT_SIZE 512 + + +#define CMD60 60 +#define CMD61 61 + + +#define RW_MULTIPLE_REGISTER CMD60 +#define RW_MULTIPLE_BLOCK CMD61 + + +#define CE_ATA_SIG_CE 0xCE +#define CE_ATA_SIG_AA 0xAA + + +#define Reg_Features_Exp 01 +#define Reg_SectorCount_Exp 02 +#define Reg_LBALow_Exp 03 +#define Reg_LBAMid_Exp 04 +#define Reg_LBAHigh_Exp 05 +#define Reg_Control 06 +#define Reg_Features_Error 09 +#define Reg_SectorCount 10 +#define Reg_LBALow 11 +#define Reg_LBAMid 12 +#define Reg_LBAHigh 13 +#define Reg_Device_Head 14 +#define Reg_Command_Status 15 + +#define Reg_scrTempC 0x80 +#define Reg_scrTempMaxP 0x84 +#define Reg_scrTempMinP 0x88 +#define Reg_scrStatus 0x8C +#define Reg_scrReallocsA 0x90 +#define Reg_scrERetractsA 0x94 +#define Reg_scrCapabilities 0x98 +#define Reg_scrControl 0xC0 + + + +typedef struct { + UINT8 Reserved0; + UINT8 Features_Exp; + UINT8 SectorCount_Exp; + UINT8 LBALow_Exp; + UINT8 LBAMid_Exp; + UINT8 LBAHigh_Exp; + UINT8 Control; + UINT8 Reserved1[2]; + UINT8 Features_Error; + UINT8 SectorCount; + UINT8 LBALow; + UINT8 LBAMid; + UINT8 LBAHigh; + UINT8 Device_Head; + UINT8 Command_Status; +}TASK_FILE; + + +// +//Reduced ATA command set +// +#define IDENTIFY_DEVICE 0xEC +#define READ_DMA_EXT 0x25 +#define WRITE_DMA_EXT 0x35 +#define STANDBY_IMMEDIATE 0xE0 +#define FLUSH_CACHE_EXT 0xEA + + + +typedef struct { + UINT16 Reserved0[10]; + UINT16 SerialNumber[10]; + UINT16 Reserved1[3]; + UINT16 FirmwareRevision[4]; + UINT16 ModelNumber[20]; + UINT16 Reserved2[33]; + UINT16 MajorVersion; + UINT16 Reserved3[19]; + UINT16 MaximumLBA[4]; + UINT16 Reserved4[2]; + UINT16 Sectorsize; + UINT16 Reserved5; + UINT16 DeviceGUID[4]; + UINT16 Reserved6[94]; + UINT16 Features; + UINT16 MaxWritesPerAddress; + UINT16 Reserved7[47]; + UINT16 IntegrityWord; +}IDENTIFY_DEVICE_DATA; + + + + + +#pragma pack() + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h new file mode 100644 index 0000000000..e2a3c313fc --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/I2cRegs.h @@ -0,0 +1,95 @@ +/** @file +Include file for I2C DXE Driver register definitions (PCIe config. space and memory space). + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _I2C_REGS_H_ +#define _I2C_REGS_H_ + + +//---------------------------------------------------------------------------- +/// I2C Device Address +//---------------------------------------------------------------------------- +typedef struct { + /// + /// The I2C hardware address to which the I2C device is preassigned or allocated. + /// + UINTN I2CDeviceAddress : 10; +} EFI_I2C_DEVICE_ADDRESS; + +//---------------------------------------------------------------------------- +/// I2C Addressing Mode (7-bit or 10 bit) +//---------------------------------------------------------------------------- +typedef enum _EFI_I2C_ADDR_MODE { + EfiI2CSevenBitAddrMode, + EfiI2CTenBitAddrMode, +} EFI_I2C_ADDR_MODE; + + +//---------------------------------------------------------------------------- +// I2C Controller B:D:F +//---------------------------------------------------------------------------- +#define I2C_Bus 0x00 +#define I2C_Device 0x15 +#define I2C_Func 0x02 + +//---------------------------------------------------------------------------- +// Memory Mapped Registers +//---------------------------------------------------------------------------- +#define I2C_REG_CON 0x00 // Control Register +#define B_I2C_REG_CON_SPEED (BIT2+BIT1) // standard mode (01) or fast mode (10) +#define B_I2C_REG_CON_10BITADD_MASTER (BIT4) // 7-bit addressing (0) or 10-bit addressing (1) +#define I2C_REG_TAR 0x04 // Master Target Address Register +#define B_I2C_REG_TAR (BIT9+BIT8+BIT7+BIT6+BIT5+BIT4+BIT3+BIT2+BIT1+BIT0) // Master Target Address bits +#define I2C_REG_DATA_CMD 0x10 // Data Buffer and Command Register +#define B_I2C_REG_DATA_CMD_RW (BIT8) // Data Buffer and Command Register Read/Write bit +#define B_I2C_REG_DATA_CMD_STOP (BIT9) // Data Buffer and Command Register STOP bit +#define B_I2C_REG_DATA_CMD_RESTART (BIT10) // Data Buffer and Command Register RESTART bit +#define I2C_REG_SS_SCL_HCNT 0x14 // Standard Speed Clock SCL High Count Register +#define I2C_REG_SS_SCL_LCNT 0x18 // Standard Speed Clock SCL Low Count Register +#define I2C_REG_FS_SCL_HCNT 0x1C // Fast Speed Clock SCL High Count Register +#define I2C_REG_FS_SCL_LCNT 0x20 // Fast Speed Clock SCL Low Count Register +#define I2C_REG_INTR_STAT 0x2C // Interrupt Status Register +#define B_I2C_REG_INTR_STAT_STOP_DET (BIT9) // Interrupt Status Register STOP_DET signal status +#define I2C_REG_INTR_MASK 0x30 // Interrupt Status Mask Register +#define I2C_REG_RAW_INTR_STAT 0x34 // Raw Interrupt Status Register +#define I2C_REG_RAW_INTR_STAT_STOP_DET (BIT9) // Raw Interrupt Status Register STOP_DET signal status. +#define I2C_REG_RAW_INTR_STAT_TX_ABRT (BIT6) // Raw Interrupt Status Register TX Abort status. +#define I2C_REG_RAW_INTR_STAT_TX_OVER (BIT3) // Raw Interrupt Status Register TX Overflow signal status. +#define I2C_REG_RAW_INTR_STAT_RX_OVER (BIT1) // Raw Interrupt Status Register RX Overflow signal status. +#define I2C_REG_RAW_INTR_STAT_RX_UNDER (BIT0) // Raw Interrupt Status Register RX Underflow signal status. +#define I2C_REG_RX_TL 0x38 // Receive FIFO Threshold Level Register +#define I2C_REG_TX_TL 0x3C // Transmit FIFO Threshold Level Register +#define I2C_REG_CLR_INT 0x40 // Clear Combined and Individual Interrupt Register +#define I2C_REG_CLR_RX_UNDER 0x44 // Clear RX Under Interrupt Register +#define I2C_REG_CLR_RX_OVER 0x48 // Clear RX Over Interrupt Register +#define I2C_REG_CLR_TX_OVER 0x4C // Clear TX Over Interrupt Register +#define I2C_REG_CLR_RD_REQ 0x50 // Clear RD REQ Interrupt Register +#define I2C_REG_CLR_TX_ABRT 0x54 // Clear TX ABRT Interrupt Register +#define I2C_REG_CLR_ACTIVITY 0x5C // Clear Activity Interrupt Register +#define I2C_REG_CLR_STOP_DET 0x60 // Clear STOP DET Interrupt Register +#define B_I2C_REG_CLR_STOP_DET (BIT0) // Clear STOP DET Interrupt Register +#define I2C_REG_CLR_START_DET 0x64 // Clear START DET Interrupt Register +#define B_I2C_REG_CLR_START_DET (BIT0) // Clear START DET Interrupt Register +#define I2C_REG_ENABLE 0x6C // Enable Register +#define B_I2C_REG_ENABLE (BIT0) // Enable (1) or disable (0) I2C Controller +#define I2C_REG_STATUS 0x70 // Status Register +#define I2C_REG_TXFLR 0x74 // Transmit FIFO Level Register +#define B_I2C_REG_TXFLR (BIT3+BIT2+BIT1+BIT0) // Transmit FIFO Level Register bits +#define I2C_REG_RXFLR 0x78 // Receive FIFO Level Register +#define B_I2C_REG_RXFLR (BIT3+BIT2+BIT1+BIT0) // Receive FIFO Level Register bits +#define I2C_REG_SDA_HOLD 0x7C // SDA HOLD Register +#define I2C_REG_TX_ABRT_SOURCE 0x80 // Transmit Abort Source Register +#define I2C_REG_ENABLE_STATUS 0x9C // Enable Status Register +#define I2C_REG_FS_SPKLEN 0xA0 // SS and FS Spike Suppression Limit Register + +// +// Features. +// +#define I2C_FIFO_SIZE 16 + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h new file mode 100644 index 0000000000..f6066e8d10 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Ioh.h @@ -0,0 +1,248 @@ +/** @file +Header file for QuarkSCSocId Ioh. +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ +#ifndef _IOH_H_ +#define _IOH_H_ + +#ifndef BIT0 +#define BIT0 0x01 +#define BIT1 0x02 +#define BIT2 0x04 +#define BIT3 0x08 +#define BIT4 0x10 +#define BIT5 0x20 +#define BIT6 0x40 +#define BIT7 0x80 +#define BIT8 0x100 +#define BIT9 0x200 +#define BIT00 0x00000001 +#define BIT01 0x00000002 +#define BIT02 0x00000004 +#define BIT03 0x00000008 +#define BIT04 0x00000010 +#define BIT05 0x00000020 +#define BIT06 0x00000040 +#define BIT07 0x00000080 +#define BIT08 0x00000100 +#define BIT09 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 +#endif + +#define IOH_PCI_CFG_ADDRESS(bus,dev,func,reg) \ + ((UINT32) ( (((UINTN)bus) << 24) + (((UINTN)dev) << 16) + \ + (((UINTN)func) << 8) + ((UINTN)reg) ))& 0x00000000ffffffff + +//---------------------------------------------------------------------------- + +#define INTEL_VENDOR_ID 0x8086 // Intel Vendor ID + +//---------------------------------------------------------------------------- +// Pci Configuration Map Register Offsets +//---------------------------------------------------------------------------- +#define PCI_REG_VID 0x00 // Vendor ID Register +#define PCI_REG_DID 0x02 // Device ID Register +#define PCI_REG_PCICMD 0x04 // PCI Command Register +#define PCI_REG_PCISTS 0x06 // PCI Status Register +#define PCI_REG_RID 0x08 // PCI Revision ID Register +#define PCI_REG_PI 0x09 // Programming Interface +#define PCI_REG_SCC 0x0a // Sub Class Code Register +#define PCI_REG_BCC 0x0b // Base Class Code Register +#define PCI_REG_PMLT 0x0d // Primary Master Latnecy Timer +#define PCI_REG_HDR 0x0e // Header Type Register +#define PCI_REG_PBUS 0x18 // Primary Bus Number Register +#define PCI_REG_SBUS 0x19 // Secondary Bus Number Register +#define PCI_REG_SUBUS 0x1a // Subordinate Bus Number Register +#define PCI_REG_SMLT 0x1b // Secondary Master Latnecy Timer +#define PCI_REG_IOBASE 0x1c // I/O base Register +#define PCI_REG_IOLIMIT 0x1d // I/O Limit Register +#define PCI_REG_SECSTATUS 0x1e // Secondary Status Register +#define PCI_REG_MEMBASE 0x20 // Memory Base Register +#define PCI_REG_MEMLIMIT 0x22 // Memory Limit Register +#define PCI_REG_PRE_MEMBASE 0x24 // Prefretchable memory Base register +#define PCI_REG_PRE_MEMLIMIT 0x26 // Prefretchable memory Limit register +#define PCI_REG_SVID0 0x2c // Subsystem Vendor ID low byte +#define PCI_REG_SVID1 0x2d // Subsystem Vendor ID high byte +#define PCI_REG_SID0 0x2e // Subsystem ID low byte +#define PCI_REG_SID1 0x2f // Subsystem ID high byte +#define PCI_REG_IOBASE_U 0x30 // I/O base Upper Register +#define PCI_REG_IOLIMIT_U 0x32 // I/O Limit Upper Register +#define PCI_REG_INTLINE 0x3c // Interrupt Line Register +#define PCI_REG_BRIDGE_CNTL 0x3e // Bridge Control Register + +//--------------------------------------------------------------------------- +// QuarkSCSocId Packet Hub definitions +//--------------------------------------------------------------------------- + +#define PCIE_BRIDGE_VID_DID 0x88008086 + +//--------------------------------------------------------------------------- +// Quark South Cluster definitions. +//--------------------------------------------------------------------------- + +#define IOH_BUS 0 +#define IOH_PCI_IOSF2AHB_0_DEV_NUM 0x14 +#define IOH_PCI_IOSF2AHB_0_MAX_FUNCS 7 +#define IOH_PCI_IOSF2AHB_1_DEV_NUM 0x15 +#define IOH_PCI_IOSF2AHB_1_MAX_FUNCS 3 + +//--------------------------------------------------------------------------- +// Quark South Cluster USB definitions. +//--------------------------------------------------------------------------- + +#define IOH_USB_BUS_NUMBER IOH_BUS +#define IOH_USB_CONTROLLER_MMIO_RANGE 0x1000 +#define IOH_MAX_OHCI_USB_CONTROLLERS 1 +#define IOH_MAX_EHCI_USB_CONTROLLERS 1 +#define IOH_MAX_USBDEVICE_USB_CONTROLLERS 1 + +#define R_IOH_USB_VENDOR_ID 0x00 +#define V_IOH_USB_VENDOR_ID INTEL_VENDOR_ID +#define R_IOH_USB_DEVICE_ID 0x02 +#define R_IOH_USB_COMMAND 0x04 +#define B_IOH_USB_COMMAND_BME BIT2 +#define B_IOH_USB_COMMAND_MSE BIT1 +#define B_IOH_USB_COMMAND_ISE BIT0 +#define R_IOH_USB_MEMBAR 0x10 +#define B_IOH_USB_MEMBAR_ADDRESS_MASK 0xFFFFF000 // [31:12]. +#define R_IOH_USB_OHCI_HCCABAR 0x18 + +//--------------------------------------------------------------------------- +// Quark South Cluster OHCI definitions +//--------------------------------------------------------------------------- +#define IOH_USB_OHCI_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM +#define IOH_OHCI_FUNCTION_NUMBER 0x04 + +//--------------------------------------------------------------------------- +// Quark South Cluster EHCI definitions +//--------------------------------------------------------------------------- +#define IOH_USB_EHCI_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM +#define IOH_EHCI_FUNCTION_NUMBER 0x03 + +// +// EHCI memory mapped registers offset from memory BAR0. +// +#define R_IOH_EHCI_CAPLENGTH 0x00 +#define R_IOH_EHCI_INSNREG01 0x94 +#define B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP (16) +#define B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_MASK (0xff << B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP) +#define B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP (0) +#define B_IOH_EHCI_INSNREG01_IN_THRESHOLD_MASK (0xff << B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP) + +// +// EHCI memory mapped registers offset from memory BAR0 + Cap length value. +// +#define R_IOH_EHCI_CONFIGFLAGS 0x40 + +//--------------------------------------------------------------------------- +// Quark South Cluster USB Device definitions +//--------------------------------------------------------------------------- +#define IOH_USBDEVICE_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM +#define IOH_USBDEVICE_FUNCTION_NUMBER 0x02 + +// +// USB Device memory mapped registers offset from memory BAR0. +// +#define R_IOH_USBDEVICE_D_INTR_UDC_REG 0x40c +#define R_IOH_USBDEVICE_D_INTR_MSK_UDC_REG 0x410 +#define B_IOH_USBDEVICE_D_INTR_MSK_UDC_REG_MASK1_MASK 0xff +#define R_IOH_USBDEVICE_EP_INTR_UDC_REG 0x414 +#define R_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG 0x418 +#define B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_OUT_EP_MASK 0x000f0000 +#define B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_IN_EP_MASK 0x0000000f + +//--------------------------------------------------------------------------- +// Quark South Cluster 10/100 Mbps Ethernet Device definitions. +//--------------------------------------------------------------------------- +#define IOH_MAC0_BUS_NUMBER IOH_BUS +#define IOH_MAC0_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM +#define IOH_MAC0_FUNCTION_NUMBER 0x06 +#define IOH_MAC1_BUS_NUMBER IOH_BUS +#define IOH_MAC1_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM +#define IOH_MAC1_FUNCTION_NUMBER 0x07 + +// +// MAC Device PCI config registers. +// +#define R_IOH_MAC_DEVICE_ID 0x02 +#define V_IOH_MAC_VENDOR_ID INTEL_VENDOR_ID +#define R_IOH_MAC_DEVICE_ID 0x02 +#define V_IOH_MAC_DEVICE_ID 0x0937 +#define R_IOH_MAC_COMMAND 0x04 +#define B_IOH_MAC_COMMAND_BME BIT2 +#define B_IOH_MAC_COMMAND_MSE BIT1 +#define B_IOH_MAC_COMMAND_ISE BIT0 +#define R_IOH_MAC_MEMBAR 0x10 +#define B_IOH_MAC_MEMBAR_ADDRESS_MASK 0xFFFFF000 + +// +// LAN Device memory mapped registers offset from memory BAR0. +// +#define R_IOH_MAC_GMAC_REG_8 0x20 +#define B_IOH_MAC_USERVER_MASK 0x0000FF00 +#define B_IOH_MAC_SNPSVER_MASK 0x000000FF +#define R_IOH_MAC_GMAC_REG_16 0x40 +#define B_IOH_MAC_ADDRHI_MASK 0x0000FFFF +#define B_IOH_MAC_AE BIT31 +#define R_IOH_MAC_GMAC_REG_17 0x44 +#define B_IOH_MAC_ADDRLO_MASK 0xFFFFFFFF + +//--------------------------------------------------------------------------- +// Quark I2C / GPIO definitions +//--------------------------------------------------------------------------- + +#define V_IOH_I2C_GPIO_VENDOR_ID INTEL_VENDOR_ID +#define V_IOH_I2C_GPIO_DEVICE_ID 0x0934 + +#define R_IOH_I2C_MEMBAR 0x10 +#define B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK 0xFFFFF000 // [31:12]. + +#define GPIO_SWPORTA_DR 0x00 +#define GPIO_SWPORTA_DDR 0x04 +#define GPIO_INTEN 0x30 +#define GPIO_INTMASK 0x34 +#define GPIO_INTTYPE_LEVEL 0x38 +#define GPIO_INT_POLARITY 0x3C +#define GPIO_INTSTATUS 0x40 +#define GPIO_RAW_INTSTATUS 0x44 +#define GPIO_DEBOUNCE 0x48 +#define GPIO_PORTA_EOI 0x4C +#define GPIO_EXT_PORTA 0x50 +#define GPIO_EXT_PORTB 0x54 +#define GPIO_LS_SYNC 0x60 +#define GPIO_CONFIG_REG2 0x70 +#define GPIO_CONFIG_REG1 0x74 + +//--------------------------------------------------------------------------- +// Quark South Cluster UART definitions. +//--------------------------------------------------------------------------- + +#define R_IOH_UART_MEMBAR 0x10 +#define B_IOH_UART_MEMBAR_ADDRESS_MASK 0xFFFFF000 // [31:12]. + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h new file mode 100644 index 0000000000..a259dd8df7 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohAccess.h @@ -0,0 +1,18 @@ +/** @file +Macros to simplify and abstract the interface to PCI configuration. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +#ifndef _IOH_ACCESS_H_ +#define _IOH_ACCESS_H_ + +#include "Ioh.h" +#include "IohCommonDefinitions.h" + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h new file mode 100644 index 0000000000..09f13e2f2a --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/IohCommonDefinitions.h @@ -0,0 +1,342 @@ +/** @file +This header file provides common definitions just for MCH using to avoid including extra module's file. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _IOH_COMMON_DEFINITIONS_H_ +#define _IOH_COMMON_DEFINITIONS_H_ + +// +// PCI CONFIGURATION MAP REGISTER OFFSETS +// +#ifndef PCI_VID +#define PCI_VID 0x0000 // Vendor ID Register +#define PCI_DID 0x0002 // Device ID Register +#define PCI_CMD 0x0004 // PCI Command Register +#define PCI_STS 0x0006 // PCI Status Register +#define PCI_RID 0x0008 // Revision ID Register +#define PCI_IFT 0x0009 // Interface Type +#define PCI_SCC 0x000A // Sub Class Code Register +#define PCI_BCC 0x000B // Base Class Code Register +#define PCI_CLS 0x000C // Cache Line Size +#define PCI_PMLT 0x000D // Primary Master Latency Timer +#define PCI_HDR 0x000E // Header Type Register +#define PCI_BIST 0x000F // Built in Self Test Register +#define PCI_BAR0 0x0010 // Base Address Register 0 +#define PCI_BAR1 0x0014 // Base Address Register 1 +#define PCI_BAR2 0x0018 // Base Address Register 2 +#define PCI_PBUS 0x0018 // Primary Bus Number Register +#define PCI_SBUS 0x0019 // Secondary Bus Number Register +#define PCI_SUBUS 0x001A // Subordinate Bus Number Register +#define PCI_SMLT 0x001B // Secondary Master Latency Timer +#define PCI_BAR3 0x001C // Base Address Register 3 +#define PCI_IOBASE 0x001C // I/O base Register +#define PCI_IOLIMIT 0x001D // I/O Limit Register +#define PCI_SECSTATUS 0x001E // Secondary Status Register +#define PCI_BAR4 0x0020 // Base Address Register 4 +#define PCI_MEMBASE 0x0020 // Memory Base Register +#define PCI_MEMLIMIT 0x0022 // Memory Limit Register +#define PCI_BAR5 0x0024 // Base Address Register 5 +#define PCI_PRE_MEMBASE 0x0024 // Prefetchable memory Base register +#define PCI_PRE_MEMLIMIT 0x0026 // Prefetchable memory Limit register +#define PCI_PRE_MEMBASE_U 0x0028 // Prefetchable memory base upper 32 bits +#define PCI_PRE_MEMLIMIT_U 0x002C // Prefetchable memory limit upper 32 bits +#define PCI_SVID 0x002C // Subsystem Vendor ID +#define PCI_SID 0x002E // Subsystem ID +#define PCI_IOBASE_U 0x0030 // I/O base Upper Register +#define PCI_IOLIMIT_U 0x0032 // I/O Limit Upper Register +#define PCI_CAPP 0x0034 // Capabilities Pointer +#define PCI_EROM 0x0038 // Expansion ROM Base Address +#define PCI_INTLINE 0x003C // Interrupt Line Register +#define PCI_INTPIN 0x003D // Interrupt Pin Register +#define PCI_MAXGNT 0x003E // Max Grant Register +#define PCI_BRIDGE_CNTL 0x003E // Bridge Control Register +#define PCI_MAXLAT 0x003F // Max Latency Register +#endif +// +// Bit Difinitions +// +#ifndef BIT0 +#define BIT0 0x0001 +#define BIT1 0x0002 +#define BIT2 0x0004 +#define BIT3 0x0008 +#define BIT4 0x0010 +#define BIT5 0x0020 +#define BIT6 0x0040 +#define BIT7 0x0080 +#define BIT8 0x0100 +#define BIT9 0x0200 +#define BIT10 0x0400 +#define BIT11 0x0800 +#define BIT12 0x1000 +#define BIT13 0x2000 +#define BIT14 0x4000 +#define BIT15 0x8000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 +#endif + + +// +// Common Memory mapped Io access macros ------------------------------------------ +// +#define IohMmioAddress( BaseAddr, Register ) \ + ( (UINTN)BaseAddr + \ + (UINTN)(Register) \ + ) + +// +// UINT64 +// +#define IohMmio64Ptr( BaseAddr, Register ) \ + ( (volatile UINT64 *)IohMmioAddress( BaseAddr, Register ) ) + +#define IohMmio64( BaseAddr, Register ) \ + *IohMmio64Ptr( BaseAddr, Register ) + +#define IohMmio64Or( BaseAddr, Register, OrData ) \ + IohMmio64( BaseAddr, Register ) = \ + (UINT64) ( \ + IohMmio64( BaseAddr, Register ) | \ + (UINT64)(OrData) \ + ) + +#define IohMmio64And( BaseAddr, Register, AndData ) \ + IohMmio64( BaseAddr, Register ) = \ + (UINT64) ( \ + IohMmio64( BaseAddr, Register ) & \ + (UINT64)(AndData) \ + ) + +#define IohMmio64AndThenOr( BaseAddr, Register, AndData, OrData ) \ + IohMmio64( BaseAddr, Register ) = \ + (UINT64) ( \ + ( IohMmio64( BaseAddr, Register ) & \ + (UINT64)(AndData) \ + ) | \ + (UINT64)(OrData) \ + ) + +// +// UINT32 +// +#define IohMmio32Ptr( BaseAddr, Register ) \ + ( (volatile UINT32 *)IohMmioAddress( BaseAddr, Register ) ) + +#define IohMmio32( BaseAddr, Register ) \ + *IohMmio32Ptr( BaseAddr, Register ) + +#define IohMmio32Or( BaseAddr, Register, OrData ) \ + IohMmio32( BaseAddr, Register ) = \ + (UINT32) ( \ + IohMmio32( BaseAddr, Register ) | \ + (UINT32)(OrData) \ + ) + +#define IohMmio32And( BaseAddr, Register, AndData ) \ + IohMmio32( BaseAddr, Register ) = \ + (UINT32) ( \ + IohMmio32( BaseAddr, Register ) & \ + (UINT32)(AndData) \ + ) + +#define IohMmio32AndThenOr( BaseAddr, Register, AndData, OrData ) \ + IohMmio32( BaseAddr, Register ) = \ + (UINT32) ( \ + ( IohMmio32( BaseAddr, Register ) & \ + (UINT32)(AndData) \ + ) | \ + (UINT32)(OrData) \ + ) +// +// UINT16 +// + +#define IohMmio16Ptr( BaseAddr, Register ) \ + ( (volatile UINT16 *)IohMmioAddress( BaseAddr, Register ) ) + +#define IohMmio16( BaseAddr, Register ) \ + *IohMmio16Ptr( BaseAddr, Register ) + +#define IohMmio16Or( BaseAddr, Register, OrData ) \ + IohMmio16( BaseAddr, Register ) = \ + (UINT16) ( \ + IohMmio16( BaseAddr, Register ) | \ + (UINT16)(OrData) \ + ) + +#define IohMmio16And( BaseAddr, Register, AndData ) \ + IohMmio16( BaseAddr, Register ) = \ + (UINT16) ( \ + IohMmio16( BaseAddr, Register ) & \ + (UINT16)(AndData) \ + ) + +#define IohMmio16AndThenOr( BaseAddr, Register, AndData, OrData ) \ + IohMmio16( BaseAddr, Register ) = \ + (UINT16) ( \ + ( IohMmio16( BaseAddr, Register ) & \ + (UINT16)(AndData) \ + ) | \ + (UINT16)(OrData) \ + ) +// +// UINT8 +// +#define IohMmio8Ptr( BaseAddr, Register ) \ + ( (volatile UINT8 *)IohMmioAddress( BaseAddr, Register ) ) + +#define IohMmio8( BaseAddr, Register ) \ + *IohMmio8Ptr( BaseAddr, Register ) + +#define IohMmio8Or( BaseAddr, Register, OrData ) \ + IohMmio8( BaseAddr, Register ) = \ + (UINT8) ( \ + IohMmio8( BaseAddr, Register ) | \ + (UINT8)(OrData) \ + ) + +#define IohMmio8And( BaseAddr, Register, AndData ) \ + IohMmio8( BaseAddr, Register ) = \ + (UINT8) ( \ + IohMmio8( BaseAddr, Register ) & \ + (UINT8)(AndData) \ + ) + +#define IohMmio8AndThenOr( BaseAddr, Register, AndData, OrData ) \ + IohMmio8( BaseAddr, Register ) = \ + (UINT8) ( \ + ( IohMmio8( BaseAddr, Register ) & \ + (UINT8)(AndData) \ + ) | \ + (UINT8)(OrData) \ + ) + +// +// Common Memory mapped Pci access macros ------------------------------------------ +// +#define Ioh_PCI_EXPRESS_BASE_ADDRESS 0xE0000000 + + +#define IohMmPciAddress( Segment, Bus, Device, Function, Register ) \ + ( (UINTN)Ioh_PCI_EXPRESS_BASE_ADDRESS + \ + (UINTN)(Bus << 20) + \ + (UINTN)(Device << 15) + \ + (UINTN)(Function << 12) + \ + (UINTN)(Register) \ + ) + +// +// UINT32 +// +#define IohMmPci32Ptr( Segment, Bus, Device, Function, Register ) \ + ( (volatile UINT32 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) ) + +#define IohMmPci32( Segment, Bus, Device, Function, Register ) \ + *IohMmPci32Ptr( Segment, Bus, Device, Function, Register ) + +#define IohMmPci32Or( Segment, Bus, Device, Function, Register, OrData ) \ + IohMmPci32( Segment, Bus, Device, Function, Register ) = \ + (UINT32) ( \ + IohMmPci32( Segment, Bus, Device, Function, Register ) | \ + (UINT32)(OrData) \ + ) + +#define IohMmPci32And( Segment, Bus, Device, Function, Register, AndData ) \ + IohMmPci32( Segment, Bus, Device, Function, Register ) = \ + (UINT32) ( \ + IohMmPci32( Segment, Bus, Device, Function, Register ) & \ + (UINT32)(AndData) \ + ) + +#define IohMmPci32AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \ + IohMmPci32( Segment, Bus, Device, Function, Register ) = \ + (UINT32) ( \ + ( IohMmPci32( Segment, Bus, Device, Function, Register ) & \ + (UINT32)(AndData) \ + ) | \ + (UINT32)(OrData) \ + ) +// +// UINT16 +// +#define IohMmPci16Ptr( Segment, Bus, Device, Function, Register ) \ + ( (volatile UINT16 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) ) + +#define IohMmPci16( Segment, Bus, Device, Function, Register ) \ + *IohMmPci16Ptr( Segment, Bus, Device, Function, Register ) + +#define IohMmPci16Or( Segment, Bus, Device, Function, Register, OrData ) \ + IohMmPci16( Segment, Bus, Device, Function, Register ) = \ + (UINT16) ( \ + IohMmPci16( Segment, Bus, Device, Function, Register ) | \ + (UINT16)(OrData) \ + ) + +#define IohMmPci16And( Segment, Bus, Device, Function, Register, AndData ) \ + IohMmPci16( Segment, Bus, Device, Function, Register ) = \ + (UINT16) ( \ + IohMmPci16( Segment, Bus, Device, Function, Register ) & \ + (UINT16)(AndData) \ + ) + +#define IohMmPci16AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \ + IohMmPci16( Segment, Bus, Device, Function, Register ) = \ + (UINT16) ( \ + ( IohMmPci16( Segment, Bus, Device, Function, Register ) & \ + (UINT16)(AndData) \ + ) | \ + (UINT16)(OrData) \ + ) +// +// UINT8 +// +#define IohMmPci8Ptr( Segment, Bus, Device, Function, Register ) \ + ( (volatile UINT8 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) ) + +#define IohMmPci8( Segment, Bus, Device, Function, Register ) \ + *IohMmPci8Ptr( Segment, Bus, Device, Function, Register ) + +#define IohMmPci8Or( Segment, Bus, Device, Function, Register, OrData ) \ + IohMmPci8( Segment, Bus, Device, Function, Register ) = \ + (UINT8) ( \ + IohMmPci8( Segment, Bus, Device, Function, Register ) | \ + (UINT8)(OrData) \ + ) + +#define IohMmPci8And( Segment, Bus, Device, Function, Register, AndData ) \ + IohMmPci8( Segment, Bus, Device, Function, Register ) = \ + (UINT8) ( \ + IohMmPci8( Segment, Bus, Device, Function, Register ) & \ + (UINT8)(AndData) \ + ) + +#define IohMmPci8AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \ + IohMmPci8( Segment, Bus, Device, Function, Register ) = \ + (UINT8) ( \ + ( IohMmPci8( Segment, Bus, Device, Function, Register ) & \ + (UINT8)(AndData) \ + ) | \ + (UINT8)(OrData) \ + ) + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h new file mode 100644 index 0000000000..d401c6b43e --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/I2cLib.h @@ -0,0 +1,152 @@ +/** @file + +Intel I2C library implementation built upon I/O library + + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _I2C_LIB_H_ +#define _I2C_LIB_H_ + +#include "I2cRegs.h" + +/** + + The I2cWriteByte() function is a wrapper function for the WriteByte() function. + Provides a standard way to execute a standard single byte write to an IC2 device + (without accessing sub-addresses), as defined in the I2C Specification. + + @param SlaveAddress The I2C slave address of the device + with which to communicate. + + @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address. + + @param Buffer Contains the value of byte data to execute to the + I2C slave device. + + + @retval EFI_SUCCESS Transfer success. + @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + +**/ +EFI_STATUS +EFIAPI +I2cWriteByte ( + IN EFI_I2C_DEVICE_ADDRESS SlaveAddress, + IN EFI_I2C_ADDR_MODE AddrMode, + IN OUT VOID *Buffer + ); + +/** + + The I2cReadByte() function is a wrapper function for the ReadByte() function. + Provides a standard way to execute a standard single byte read to an I2C device + (without accessing sub-addresses), as defined in the I2C Specification. + + @param SlaveAddress The I2C slave address of the device + with which to communicate. + + @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address. + + @param Buffer Contains the value of byte data read from the + I2C slave device. + + + @retval EFI_SUCCESS Transfer success. + @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + +**/ +EFI_STATUS +EFIAPI +I2cReadByte ( + IN EFI_I2C_DEVICE_ADDRESS SlaveAddress, + IN EFI_I2C_ADDR_MODE AddrMode, + IN OUT VOID *Buffer + ); + +/** + + The I2cWriteMultipleByte() function is a wrapper function for the WriteMultipleByte() + function. Provides a standard way to execute multiple byte writes to an I2C device (e.g. when + accessing sub-addresses or writing block of data), as defined in the I2C Specification. + + @param SlaveAddress The I2C slave address of the device + with which to communicate. + + @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address. + + @param Length No. of bytes to be written. + + @param Buffer Contains the value of byte to be written to the + I2C slave device. + + @retval EFI_SUCCESS Transfer success. + @retval EFI_INVALID_PARAMETER This, Length or Buffer pointers are invalid. + @retval EFI_UNSUPPORTED Unsupported input param. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + +**/ +EFI_STATUS +EFIAPI +I2cWriteMultipleByte ( + IN EFI_I2C_DEVICE_ADDRESS SlaveAddress, + IN EFI_I2C_ADDR_MODE AddrMode, + IN UINTN *Length, + IN OUT VOID *Buffer + ); + +/** + + The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte + function. Provides a standard way to execute multiple byte writes to an IC2 device + (e.g. when accessing sub-addresses or when reading block of data), as defined + in the I2C Specification (I2C combined write/read protocol). + + @param SlaveAddress The I2C slave address of the device + with which to communicate. + + @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address. + + @param WriteLength No. of bytes to be written. In this case data + written typically contains sub-address or sub-addresses + in Hi-Lo format, that need to be read (I2C combined + write/read protocol). + + @param ReadLength No. of bytes to be read from I2C slave device. + need to be read. + + @param Buffer Contains the value of byte data read from the + I2C slave device. + + @retval EFI_SUCCESS Transfer success. + @retval EFI_INVALID_PARAMETER This, WriteLength, ReadLength or Buffer + pointers are invalid. + @retval EFI_UNSUPPORTED Unsupported input param. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + +**/ +EFI_STATUS +EFIAPI +I2cReadMultipleByte ( + IN EFI_I2C_DEVICE_ADDRESS SlaveAddress, + IN EFI_I2C_ADDR_MODE AddrMode, + IN UINTN *WriteLength, + IN UINTN *ReadLength, + IN OUT VOID *Buffer + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h new file mode 100644 index 0000000000..a3aa071ef5 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/Library/IohLib.h @@ -0,0 +1,36 @@ +/** @file +Library that provides Soc specific library services for SouthCluster devices. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __IOH_LIB_H__ +#define __IOH_LIB_H__ + +#include "Ioh.h" + +EFI_STATUS +EFIAPI +InitializeIohSsvidSsid ( + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Func + ); + +VOID +EFIAPI +EnableUsbMemIoBusMaster ( + IN UINT8 UsbBusNumber + ); + +UINT32 +EFIAPI +ReadIohGpioValues ( + VOID + ); + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h new file mode 100644 index 0000000000..549171e53e --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/MMC.h @@ -0,0 +1,274 @@ +/** @file + +Header file for Industry MMC 4.2 spec. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _MMC_H +#define _MMC_H + +#pragma pack(1) +// +//Command definition +// + +#define CMD0 0 +#define CMD1 1 +#define CMD2 2 +#define CMD3 3 +#define CMD4 4 +#define CMD6 6 +#define CMD7 7 +#define CMD8 8 +#define CMD9 9 +#define CMD10 10 +#define CMD11 11 +#define CMD12 12 +#define CMD13 13 +#define CMD14 14 +#define CMD15 15 +#define CMD16 16 +#define CMD17 17 +#define CMD18 18 +#define CMD19 19 +#define CMD20 20 +#define CMD23 23 +#define CMD24 24 +#define CMD25 25 +#define CMD26 26 +#define CMD27 27 +#define CMD28 28 +#define CMD29 29 +#define CMD30 30 +#define CMD35 35 +#define CMD36 36 +#define CMD38 38 +#define CMD39 39 +#define CMD40 40 +#define CMD42 42 +#define CMD55 55 +#define CMD56 56 + + + +#define GO_IDLE_STATE CMD0 +#define SEND_OP_COND CMD1 +#define ALL_SEND_CID CMD2 +#define SET_RELATIVE_ADDR CMD3 +#define SET_DSR CMD4 +#define SWITCH CMD6 +#define SELECT_DESELECT_CARD CMD7 +#define SEND_EXT_CSD CMD8 +#define SEND_CSD CMD9 +#define SEND_CID CMD10 +#define READ_DAT_UNTIL_STOP CMD11 +#define STOP_TRANSMISSION CMD12 +#define SEND_STATUS CMD13 +#define BUSTEST_R CMD14 +#define GO_INACTIVE_STATE CMD15 +#define SET_BLOCKLEN CMD16 +#define READ_SINGLE_BLOCK CMD17 +#define READ_MULTIPLE_BLOCK CMD18 +#define BUSTEST_W CMD19 +#define WRITE_DAT_UNTIL_STOP CMD20 +#define SET_BLOCK_COUNT CMD23 +#define WRITE_BLOCK CMD24 +#define WRITE_MULTIPLE_BLOCK CMD25 +#define PROGRAM_CID CMD26 +#define PROGRAM_CSD CMD27 +#define SET_WRITE_PROT CMD28 +#define CLR_WRITE_PROT CMD29 +#define SEND_WRITE_PROT CMD30 +#define ERASE_GROUP_START CMD35 +#define ERASE_GROUP_END CMD36 +#define ERASE CMD38 +#define FAST_IO CMD39 +#define GO_IRQ_STATE CMD40 +#define LOCK_UNLOCK CMD42 +#define APP_CMD CMD55 +#define GEN_CMD CMD56 + + +#define CMD_INDEX_MASK 0x3F +#define AUTO_CMD12_ENABLE BIT6 +#define AUTO_CMD23_ENABLE BIT7 + +#define FREQUENCY_OD (400 * 1000) +#define FREQUENCY_MMC_PP (26 * 1000 * 1000) +#define FREQUENCY_MMC_PP_HIGH (52 * 1000 * 1000) + +#define DEFAULT_DSR_VALUE 0x404 + +// +//Registers definition +// + +typedef struct { + UINT32 Reserved0: 7; // 0 + UINT32 V170_V195: 1; // 1.70V - 1.95V + UINT32 V200_V260: 7; // 2.00V - 2.60V + UINT32 V270_V360: 9; // 2.70V - 3.60V + UINT32 Reserved1: 5; // 0 + UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode) + UINT32 Busy: 1; // This bit is set to LOW if the card has not finished the power up routine +}OCR; + + +typedef struct { + UINT8 NotUsed: 1; // 1 + UINT8 CRC: 7; // CRC7 checksum + UINT8 MDT; // Manufacturing date + UINT32 PSN; // Product serial number + UINT8 PRV; // Product revision + UINT8 PNM[6]; // Product name + UINT16 OID; // OEM/Application ID + UINT8 MID; // Manufacturer ID +}CID; + + +typedef struct { + UINT8 NotUsed: 1; // 1 [0:0] + UINT8 CRC: 7; // CRC [7:1] + UINT8 ECC: 2; // ECC code [9:8] + UINT8 FILE_FORMAT: 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13] + UINT8 COPY: 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15] + UINT16 CONTENT_PROT_APP: 1; // Content protection application [16:16] + UINT16 Reserved0: 4; // 0 [20:17] + UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21] + UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR: 3; // Write speed factor [28:26] + UINT16 DEFAULT_ECC: 2; // Manufacturer default ECC [30:29] + UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31] + UINT32 WP_GRP_SIZE: 5; // Write protect group size [36:32] + UINT32 ERASE_GRP_MULT: 5; // Erase group size multiplier [41:37] + UINT32 ERASE_GRP_SIZE: 5; // Erase group size [46:42] + UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47] + UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50] + UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53] + UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56] + UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59] + UINT32 C_SIZELow2: 2;// Device size [73:62] + UINT32 C_SIZEHigh10: 10;// Device size [73:62] + UINT32 Reserved1: 2; // 0 [75:74] + UINT32 DSR_IMP: 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79] + UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80] + UINT32 CCC: 12;// Card command classes [95:84] + UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96] + UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104] + UINT8 TAAC ; // Data read access-time 1 [119:112] + UINT8 Reserved2: 2; // 0 [121:120] + UINT8 SPEC_VERS: 4; // System specification version [125:122] + UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126] +}CSD; + +typedef struct { + UINT8 Reserved0[181]; // 0 [0:180] + UINT8 ERASED_MEM_CONT; // Erased Memory Content [181] + UINT8 Reserved2; // Erased Memory Content [182] + UINT8 BUS_WIDTH; // Bus Width Mode [183] + UINT8 Reserved3; // 0 [184] + UINT8 HS_TIMING; // High Speed Interface Timing [185] + UINT8 Reserved4; // 0 [186] + UINT8 POWER_CLASS; // Power Class [187] + UINT8 Reserved5; // 0 [188] + UINT8 CMD_SET_REV; // Command Set Revision [189] + UINT8 Reserved6; // 0 [190] + UINT8 CMD_SET; // Command Set [191] + UINT8 EXT_CSD_REV; // Extended CSD Revision [192] + UINT8 Reserved7; // 0 [193] + UINT8 CSD_STRUCTURE; // CSD Structure Version [194] + UINT8 Reserved8; // 0 [195] + UINT8 CARD_TYPE; // Card Type [196] + UINT8 Reserved9[3]; // 0 [199:197] + UINT8 PWR_CL_52_195; // Power Class for 52MHz @ 1.95V [200] + UINT8 PWR_CL_26_195; // Power Class for 26MHz @ 1.95V [201] + UINT8 PWR_CL_52_360; // Power Class for 52MHz @ 3.6V [202] + UINT8 PWR_CL_26_360; // Power Class for 26MHz @ 3.6V [203] + UINT8 Reserved10; // 0 [204] + UINT8 MIN_PERF_R_4_26; // Minimum Read Performance for 4bit @26MHz [205] + UINT8 MIN_PERF_W_4_26; // Minimum Write Performance for 4bit @26MHz [206] + UINT8 MIN_PERF_R_8_26_4_52; // Minimum Read Performance for 8bit @26MHz/4bit @52MHz [207] + UINT8 MIN_PERF_W_8_26_4_52; // Minimum Write Performance for 8bit @26MHz/4bit @52MHz [208] + UINT8 MIN_PERF_R_8_52; // Minimum Read Performance for 8bit @52MHz [209] + UINT8 MIN_PERF_W_8_52; // Minimum Write Performance for 8bit @52MHz [210] + UINT8 Reserved11; // 0 [211] + UINT8 SEC_COUNT[4]; // Sector Count [215:212] + UINT8 Reserved12[288]; // 0 [503:216] + UINT8 S_CMD_SET; // Sector Count [504] + UINT8 Reserved13[7]; // Sector Count [511:505] +}EXT_CSD; + + +// +//Card Status definition +// +typedef struct { + UINT32 Reserved0: 2; //Reserved for Manufacturer Test Mode + UINT32 Reserved1: 2; //Reserved for Application Specific commands + UINT32 Reserved2: 1; // + UINT32 SAPP_CMD: 1; // + UINT32 Reserved3: 1; //Reserved + UINT32 SWITCH_ERROR: 1; // + UINT32 READY_FOR_DATA: 1; // + UINT32 CURRENT_STATE: 4; // + UINT32 ERASE_RESET: 1; // + UINT32 Reserved4: 1; //Reserved + UINT32 WP_ERASE_SKIP: 1; // + UINT32 CID_CSD_OVERWRITE: 1; // + UINT32 OVERRUN: 1; // + UINT32 UNDERRUN: 1; // + UINT32 ERROR: 1; // + UINT32 CC_ERROR: 1; // + UINT32 CARD_ECC_FAILED: 1; // + UINT32 ILLEGAL_COMMAND: 1; // + UINT32 COM_CRC_ERROR: 1; // + UINT32 LOCK_UNLOCK_FAILED: 1; // + UINT32 CARD_IS_LOCKED: 1; // + UINT32 WP_VIOLATION: 1; // + UINT32 ERASE_PARAM: 1; // + UINT32 ERASE_SEQ_ERROR: 1; // + UINT32 BLOCK_LEN_ERROR: 1; // + UINT32 ADDRESS_MISALIGN: 1; // + UINT32 ADDRESS_OUT_OF_RANGE:1; // +}CARD_STATUS; + +typedef struct { + UINT32 CmdSet: 3; + UINT32 Reserved0: 5; + UINT32 Value: 8; + UINT32 Index: 8; + UINT32 Access: 2; + UINT32 Reserved1: 6; +}SWITCH_ARGUMENT; + +#define CommandSet_Mode 0 +#define SetBits_Mode 1 +#define ClearBits_Mode 2 +#define WriteByte_Mode 3 + + +#define Idle_STATE 0 +#define Ready_STATE 1 +#define Ident_STATE 2 +#define Stby_STATE 3 +#define Tran_STATE 4 +#define Data_STATE 5 +#define Rcv_STATE 6 +#define Prg_STATE 7 +#define Dis_STATE 8 +#define Btst_STATE 9 + + + +#pragma pack() +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h new file mode 100644 index 0000000000..93db8d248a --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDCard.h @@ -0,0 +1,146 @@ +/** @file + +Header file for Industry SD Card 2.0 spec. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SD_CARD_H +#define _SD_CARD_H + +#include "MMC.h" + +#pragma pack(1) + +#define CHECK_PATTERN 0xAA ///< Physical Layer Simplified Specification Version 3.01 recommended 0xAA + +#define ACMD6 6 +#define ACMD13 13 +#define ACMD23 23 +#define ACMD41 41 +#define ACMD42 42 +#define ACMD51 51 + + +#define SWITCH_FUNC CMD6 +#define SEND_IF_COND CMD8 + + +#define SET_BUS_WIDTH ACMD6 +#define SD_STATUS ACMD13 +#define SET_WR_BLK_ERASE_COUNT ACMD23 +#define SD_SEND_OP_COND ACMD41 +#define SET_CLR_CARD_DETECT ACMD42 +#define SEND_SCR ACMD51 + + + +#define SD_BUS_WIDTH_1 0 +#define SD_BUS_WIDTH_4 2 + + + +#define FREQUENCY_SD_PP (25 * 1000 * 1000) +#define FREQUENCY_SD_PP_HIGH (50 * 1000 * 1000) + + +#define SD_SPEC_10 0 +#define SD_SPEC_11 1 +#define SD_SPEC_20 2 + + +#define VOLTAGE_27_36 0x1 + +typedef struct { + UINT8 NotUsed: 1; // 1 [0:0] + UINT8 CRC: 7; // CRC [7:1] + UINT8 ECC: 2; // ECC code [9:8] + UINT8 FILE_FORMAT: 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13] + UINT8 COPY: 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15] + UINT16 Reserved0: 5; // 0 [20:16] + UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21] + UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR: 3; // Write speed factor [28:26] + UINT16 DEFAULT_ECC: 2; // Manufacturer default ECC [30:29] + UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31] + UINT16 WP_GRP_SIZE: 7; // Write protect group size [38:32] + UINT16 SECTOR_SIZE: 7; // Erase sector size [45:39] + UINT16 ERASE_BLK_EN: 1; // Erase single block enable [46:46] + UINT16 Reserved1: 1; // 0 [47:47] + + UINT32 C_SIZE: 22; // Device size [69:48] + UINT32 Reserved2: 6; // 0 [75:70] + UINT32 DSR_IMP: 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79] + + UINT16 READ_BL_LEN: 4; // Max. read data block length [83:80] + UINT16 CCC: 12; // Card command classes [95:84] + UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96] + UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104] + UINT8 TAAC ; // Data read access-time 1 [119:112] + UINT8 Reserved3: 6; // 0 [125:120] + UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126] +}CSD_SDV2; + +typedef struct { + UINT32 Reserved0; + UINT32 Reserved1: 16; + UINT32 SD_BUS_WIDTH: 4; + UINT32 SD_SECURITY: 3; + UINT32 DATA_STAT_AFTER_ERASE: 1; + UINT32 SD_SPEC: 4; + UINT32 SCR_STRUCT: 4; +}SCR; + + +typedef struct { + UINT8 Reserved0[50]; + UINT8 ERASE_OFFSET: 2; + UINT8 ERASE_TIMEOUT: 6; + UINT16 ERASE_SIZE; + UINT8 Reserved1: 4; + UINT8 AU_SIZE: 4; + UINT8 PERFORMANCE_MOVE; + UINT8 SPEED_CLASS; + UINT32 SIZE_OF_PROTECTED_AREA; + UINT32 SD_CARD_TYPE: 16; + UINT32 Reserved2: 13; + UINT32 SECURED_MODE: 1; + UINT32 DAT_BUS_WIDTH: 2; +}SD_STATUS_REG; + + + +typedef struct { + UINT8 Reserved0[34]; + UINT16 Group1BusyStatus; + UINT16 Group2BusyStatus; + UINT16 Group3BusyStatus; + UINT16 Group4BusyStatus; + UINT16 Group5BusyStatus; + UINT16 Group6BusyStatus; + UINT8 DataStructureVersion; + UINT8 Group21Status; + UINT8 Group43Status; + UINT8 Group65Status; + UINT16 Group1Function; + UINT16 Group2Function; + UINT16 Group3Function; + UINT16 Group4Function; + UINT16 Group5Function; + UINT16 Group6Function; + UINT16 MaxCurrent; +}SWITCH_STATUS; + + +#pragma pack() +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h new file mode 100644 index 0000000000..7ce0793390 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Include/SDHostIo.h @@ -0,0 +1,333 @@ +/** @file + +Interface definition for EFI_SD_HOST_IO_PROTOCOL. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SD_HOST_IO_H +#define _SD_HOST_IO_H + +#include "SDCard.h" +#include "CEATA.h" + + +#define EFI_SD_HOST_IO_PROTOCOL_GUID \ + { \ + 0xb63f8ec7, 0xa9c9, 0x4472, {0xa4, 0xc0, 0x4d, 0x8b, 0xf3, 0x65, 0xcc, 0x51} \ + } + +/// +/// Forward reference for pure ANSI compatability +/// +typedef struct _EFI_SD_HOST_IO_PROTOCOL EFI_SD_HOST_IO_PROTOCOL; + + + +typedef enum { + ResponseNo = 0, + ResponseR1, + ResponseR1b, + ResponseR2, + ResponseR3, + ResponseR4, + ResponseR5, + ResponseR5b, + ResponseR6, + ResponseR7 +}RESPONSE_TYPE; + +typedef enum { + NoData = 0, + InData, + OutData +}TRANSFER_TYPE; + +typedef enum { + Reset_Auto = 0, + Reset_DAT, + Reset_CMD, + Reset_DAT_CMD, + Reset_All +}RESET_TYPE; + +#define PCI_SUBCLASS_SD_HOST_CONTROLLER 0x05 +#define PCI_IF_STANDARD_HOST_NO_DMA 0x00 +#define PCI_IF_STANDARD_HOST_SUPPORT_DMA 0x01 + +#define SDHCI_SPEC_100 0 +#define SDHCI_SPEC_200 1 +#define SDHCI_SPEC_300 2 + +// +//MMIO Registers definition for MMC/SDIO controller +// +#define MMIO_DMAADR 0x00 +#define MMIO_BLKSZ 0x04 +#define MMIO_BLKCNT 0x06 +#define MMIO_CMDARG 0x08 +#define MMIO_XFRMODE 0x0C +#define MMIO_SDCMD 0x0E +#define MMIO_RESP 0x10 +#define MMIO_BUFDATA 0x20 +#define MMIO_PSTATE 0x24 +#define MMIO_HOSTCTL 0x28 +#define MMIO_PWRCTL 0x29 +#define MMIO_BLKGAPCTL 0x2A +#define MMIO_WAKECTL 0x2B +#define MMIO_CLKCTL 0x2C +#define V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL 0x80 +#define V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL 0x3FF +#define B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK 0xC0 + +#define MMIO_TOCTL 0x2E +#define MMIO_SWRST 0x2F +#define MMIO_NINTSTS 0x30 +#define MMIO_ERINTSTS 0x32 +#define MMIO_NINTEN 0x34 +#define MMIO_ERINTEN 0x36 +#define MMIO_NINTSIGEN 0x38 +#define MMIO_ERINTSIGEN 0x3A +#define MMIO_AC12ERRSTS 0x3C +#define MMIO_HOSTCTL2 0x3E +#define MMIO_CAP 0x40 +#define MMIO_MCCAP 0x48 +#define MMIO_SLTINTSTS 0xFC +#define MMIO_CTRLRVER 0xFE +#define MMIO_SRST 0x1FC + +// +// Protocol definitions +// + +/** + The main function used to send the command to the card inserted into the SD host slot. + It will assemble the arguments to set the command register and wait for the command + and transfer completed until timeout. Then it will read the response register to fill + the ResponseData. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param CommandIndex The command index to set the command index field of command register. + @param Argument Command argument to set the argument field of command register. + @param DataType TRANSFER_TYPE, indicates no data, data in or data out. + @param Buffer Contains the data read from / write to the device. + @param BufferSize The size of the buffer. + @param ResponseType RESPONSE_TYPE. + @param TimeOut Time out value in 1 ms unit. + @param ResponseData Depending on the ResponseType, such as CSD or card status. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_OUT_OF_RESOURCES + @retval EFI_TIMEOUT + @retval EFI_DEVICE_ERROR + +**/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SEND_COMMAND) ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT16 CommandIndex, + IN UINT32 Argument, + IN TRANSFER_TYPE DataType, + IN UINT8 *Buffer, OPTIONAL + IN UINT32 BufferSize, + IN RESPONSE_TYPE ResponseType, + IN UINT32 TimeOut, + OUT UINT32 *ResponseData OPTIONAL + ); + +/** + Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency. + It depends on the max frequency the host can support, divider, and host speed mode. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param MaxFrequency Max frequency in HZ. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_CLOCK_FREQUENCY) ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 MaxFrequency + ); + + +/** + Set bus width of the host controller + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param BusWidth Bus width in 1, 4, 8 bits. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + +**/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_BUS_WIDTH) ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 BusWidth + ); + +/** + Set voltage which could supported by the host controller. + Support 0(Power off the host), 1.8V, 3.0V, 3.3V + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Voltage Units in 0.1 V. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + +**/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_HOST_VOLTAGE) ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 Voltage + ); + +/** + Reset the host controller. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param ResetAll TRUE to reset all. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_RESET_SD_HOST) ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN RESET_TYPE ResetType + ); + +/** + Enable auto stop on the host controller. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Enable TRUE to enable, FALSE to disable. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_ENABLE_AUTO_STOP_CMD) ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ); + +/** + Find whether these is a card inserted into the slot. If so init the host. + If not, return EFI_NOT_FOUND. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + +**/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_DETECT_CARD_AND_INIT_HOST) ( + IN EFI_SD_HOST_IO_PROTOCOL *This + ); + +/** + Set the Block length on the host controller. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param BlockLength card supportes block length. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ + +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_BLOCK_LENGTH) ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 BlockLength + ); + +/** + Enable/Disable High Speed transfer mode + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Enable TRUE to Enable, FALSE to Disable + + @return EFI_SUCCESS +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_HIGH_SPEED_MODE) ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_DUAL_DATARATE_MODE) ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ); + + + +#define EFI_SD_HOST_IO_PROTOCOL_REVISION_01 0x02 + + +typedef struct { + UINT32 HighSpeedSupport: 1; //High speed supported + UINT32 V18Support: 1; //1.8V supported + UINT32 V30Support: 1; //3.0V supported + UINT32 V33Support: 1; //3.3V supported + UINT32 Reserved0: 4; + UINT32 HostVersion: 8; + UINT32 BusWidth4: 1; // 4 bit width + UINT32 BusWidth8: 1; // 8 bit width + UINT32 Reserved1: 14; + UINT32 BoundarySize; +}HOST_CAPABILITY; + + +// +// Interface structure for the SD HOST I/O Protocol +// +struct _EFI_SD_HOST_IO_PROTOCOL { + UINT32 Revision; + HOST_CAPABILITY HostCapability; + EFI_SD_HOST_IO_PROTOCOL_SEND_COMMAND SendCommand; + EFI_SD_HOST_IO_PROTOCOL_SET_CLOCK_FREQUENCY SetClockFrequency; + EFI_SD_HOST_IO_PROTOCOL_SET_BUS_WIDTH SetBusWidth; + EFI_SD_HOST_IO_PROTOCOL_SET_HOST_VOLTAGE SetHostVoltage; + EFI_SD_HOST_IO_PROTOCOL_RESET_SD_HOST ResetSDHost; + EFI_SD_HOST_IO_PROTOCOL_ENABLE_AUTO_STOP_CMD EnableAutoStopCmd; + EFI_SD_HOST_IO_PROTOCOL_DETECT_CARD_AND_INIT_HOST DetectCardAndInitHost; + EFI_SD_HOST_IO_PROTOCOL_SET_BLOCK_LENGTH SetBlockLength; + EFI_SD_HOST_IO_PROTOCOL_HIGH_SPEED_MODE SetHighSpeedMode; + EFI_SD_HOST_IO_PROTOCOL_DUAL_DATARATE_MODE SetDDRMode; +}; + +extern EFI_GUID gEfiSDHostIoProtocolGuid; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h new file mode 100644 index 0000000000..dfc8a244c5 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/CommonHeader.h @@ -0,0 +1,55 @@ +/** @file +Common header file shared by all source files. + +This file includes package header files, library classes and protocol, PPI & GUID definitions. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef __COMMON_HEADER_H_ +#define __COMMON_HEADER_H_ + +// +// The package level header files this module uses +// +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h new file mode 100644 index 0000000000..1212ab86fd --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohBds.h @@ -0,0 +1,83 @@ +/** @file +Head file for BDS Platform specific code + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _IOH_BDS_H +#define _IOH_BDS_H + +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c new file mode 100644 index 0000000000..cf6006626b --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohData.c @@ -0,0 +1,42 @@ +/** @file +Defined the Ioh device path which will be used by +platform Bbd to perform the platform policy connect. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "IohBds.h" + +// +// Predefined platform root bridge +// +PLATFORM_ROOT_BRIDGE_DEVICE_PATH gPlatformRootBridge0 = { + gPciRootBridge, + gEndEntire +}; + +EFI_DEVICE_PATH_PROTOCOL* gPlatformRootBridges [] = { + (EFI_DEVICE_PATH_PROTOCOL*)&gPlatformRootBridge0, + NULL +}; + +// +// Ioh USB EHCI controller device path +// +IOH_PCI_USB_DEVICE_PATH gIohUsbDevicePath0 = { + gPciRootBridge, + PCI_DEVICE_PATH_NODE(IOH_EHCI_FUNCTION_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER), + gEndEntire +}; + +// +// Ioh predefined device connecting option +// +EFI_DEVICE_PATH_PROTOCOL* gDeviceConnectOption [] = { + // (EFI_DEVICE_PATH_PROTOCOL*)&gIohUsbDevicePath0, + NULL +}; + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c new file mode 100644 index 0000000000..8ea791a88c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInit.c @@ -0,0 +1,37 @@ +/** @file +QuarkSCSocId module initialization module + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "CommonHeader.h" +#include "IohBds.h" + +/** + The entry function for IohInit driver. + + This function just call initialization function. + + @param ImageHandle The driver image handle for GmchInit driver + @param SystemTable The pointer to System Table + + @retval EFI_SUCCESS Success to initialize every module. + @return EFI_STATUS The status of initialization work. + +**/ +EFI_STATUS +EFIAPI +IohInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + InitializeIohSsvidSsid(IOH_BUS, IOH_PCI_IOSF2AHB_0_DEV_NUM, 0); + + InitializeIohSsvidSsid(IOH_BUS, IOH_PCI_IOSF2AHB_1_DEV_NUM, 0); + + return EFI_SUCCESS; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf new file mode 100644 index 0000000000..264a9eea7d --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf @@ -0,0 +1,76 @@ +## @file +# Component description file for Quark South Cluster Init driver. +# +# IohInit driver implement QuarkSCSocId related drivers, includes: +# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver. +# +# This driver mainly do full initialization for the Soc chipet includes: +# 1. Initialize the PCI Express device. +# 2. Initialize the PciHostBridge, and allocate the I/O and memory space from GCD service. +# 3. Initialize the SmmAccess module and install EFI_SMM_ACCESS_PROTOCOL +# 4. Initialize the LegacyRegion module, install EFI_LEGACY_REGION_PROTOCOL and set below 1M +# memory attribute from MTRR. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = IohInitDxe + FILE_GUID = 3FE2A8A3-C400-48F8-832F-7881A394C250 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = IohInit + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + IohInit.c + IohBds.h + IohData.c + CommonHeader.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + S3BootScriptLib + PcdLib + HobLib + PciLib + BaseMemoryLib + MemoryAllocationLib + S3PciLib + UefiLib + DebugLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + DxeServicesTableLib + UefiDriverEntryPoint + BaseLib + S3IoLib + IoLib + DevicePathLib + IohLib + +[Protocols] + gEfiPciRootBridgeIoProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiPciIoProtocolGuid + +[Pcd] + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartBusNumber + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartDevNumber + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartFunctionNumber + +[Depex] + TRUE diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h new file mode 100644 index 0000000000..67c66ff4ac --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/CommonHeader.h @@ -0,0 +1,214 @@ +/** @file +Provides definition of entry point to the common I2C module that produces +common I2C Controller functions used by I2C library services. + + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _I2CCOMMON_H_ +#define _I2CCOMMON_H_ + +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c new file mode 100644 index 0000000000..de99361f46 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c @@ -0,0 +1,998 @@ +/** @file +I2C Library for Quark I2C Controller. +Follows I2C Controller setup instructions as detailed in +Quark DataSheet (doc id: 329676) Section 19.1/19.1.3. + + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CommonHeader.h" + +/** + The Called to Common Service Entry. + + @return None. + +**/ + +VOID +I2cCommonServiceEntry ( + OUT UINT16 *SaveCmdPtr, + OUT UINT32 *SaveBar0Ptr + ) +{ + *SaveBar0Ptr = IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0); + if (((*SaveBar0Ptr) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) { + + IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) = + FixedPcdGet32 (PcdIohI2cMmioBase) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK; + + // + // also Save Cmd Register, Setup by InitializeInternal later during xfers. + // + *SaveCmdPtr = IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD); + } +} + +/** + The Called on Common Service Exit. + + @return None. + +**/ +VOID +I2cCommonServiceExit ( + IN CONST UINT16 SaveCmd, + IN CONST UINT32 SaveBar0 + + ) +{ + if ((SaveBar0 & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) { + IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD) = SaveCmd; + IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) = SaveBar0; + } +} + + +/** + The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller. + + Always reads PCI configuration space to get MMIO base address of I2C Controller. + + @return The IO port base address of I2C controller. + +**/ +UINTN +GetI2CIoPortBaseAddress ( + VOID + ) +{ + UINTN I2CIoPortBaseAddress; + + // + // Get I2C Memory Mapped registers base address. + // + I2CIoPortBaseAddress = IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0); + + // + // Make sure that the IO port base address has been properly set. + // + ASSERT (I2CIoPortBaseAddress != 0); + ASSERT (I2CIoPortBaseAddress != 0xFF); + + return I2CIoPortBaseAddress; +} + + +/** + The EnableI2CMmioSpace() function enables access to I2C MMIO space. + +**/ +VOID +EnableI2CMmioSpace ( + VOID + ) +{ + UINT8 PciCmd; + + // + // Read PCICMD. Bus=0, Dev=0, Func=0, Reg=0x4 + // + PciCmd = IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD); + + // + // Enable Bus Master(Bit2), MMIO Space(Bit1) & I/O Space(Bit0) + // + PciCmd |= 0x7; + IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD) = PciCmd; + +} + +/** + The DisableI2CController() functions disables I2C Controller. + +**/ +VOID +DisableI2CController ( + VOID + ) +{ + UINTN I2CIoPortBaseAddress; + UINT32 Addr; + UINT32 Data; + UINT8 PollCount; + + PollCount = 0; + + // + // Get I2C Memory Mapped registers base address. + // + I2CIoPortBaseAddress = GetI2CIoPortBaseAddress (); + + // + // Disable the I2C Controller by setting IC_ENABLE.ENABLE to zero + // + Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= ~B_I2C_REG_ENABLE; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Read the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled + // + Data = 0xFF; + Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE_STATUS; + Data = *((volatile UINT32 *) (UINTN)(Addr)) & I2C_REG_ENABLE_STATUS; + while (Data != 0) { + // + // Poll the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled, until timeout (TI2C_POLL*MAX_T_POLL_COUNT). + // + PollCount++; + if (PollCount >= MAX_T_POLL_COUNT) { + break; + } + MicroSecondDelay(TI2C_POLL); + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= I2C_REG_ENABLE_STATUS; + } + + // + // Asset if controller does not enter Disabled state. + // + ASSERT (PollCount < MAX_T_POLL_COUNT); + + // + // Read IC_CLR_INTR register to automatically clear the combined interrupt, + // all individual interrupts and the IC_TX_ABRT_SOURCE register. + // + Addr = I2CIoPortBaseAddress + I2C_REG_CLR_INT; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + +} + +/** + The EnableI2CController() function enables the I2C Controller. + +**/ +VOID +EnableI2CController ( + VOID + ) +{ + UINTN I2CIoPortBaseAddress; + UINT32 Addr; + UINT32 Data; + + // + // Get I2C Memory Mapped registers base address. + // + I2CIoPortBaseAddress = GetI2CIoPortBaseAddress (); + + // + // Enable the I2C Controller by setting IC_ENABLE.ENABLE to 1 + // + Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data |= B_I2C_REG_ENABLE; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Clear overflow and abort error status bits before transactions. + // + Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_OVER; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_OVER; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_ABRT; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + +} + +/** + The WaitForStopDet() function waits until I2C STOP Condition occurs, + indicating transfer completion. + + @retval EFI_SUCCESS Stop detected. + @retval EFI_TIMEOUT Timeout while waiting for stop condition. + @retval EFI_ABORTED Tx abort signaled in HW status register. + @retval EFI_DEVICE_ERROR Tx or Rx overflow detected. + +**/ +EFI_STATUS +WaitForStopDet ( + VOID + ) +{ + UINTN I2CIoPortBaseAddress; + UINT32 Addr; + UINT32 Data; + UINT32 PollCount; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + PollCount = 0; + + // + // Get I2C Memory Mapped registers base address. + // + I2CIoPortBaseAddress = GetI2CIoPortBaseAddress (); + + // + // Wait for STOP Detect. + // + Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT; + + do { + Data = *((volatile UINT32 *) (UINTN)(Addr)); + if ((Data & I2C_REG_RAW_INTR_STAT_TX_ABRT) != 0) { + Status = EFI_ABORTED; + break; + } + if ((Data & I2C_REG_RAW_INTR_STAT_TX_OVER) != 0) { + Status = EFI_DEVICE_ERROR; + break; + } + if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) { + Status = EFI_DEVICE_ERROR; + break; + } + if ((Data & I2C_REG_RAW_INTR_STAT_STOP_DET) != 0) { + Status = EFI_SUCCESS; + break; + } + MicroSecondDelay(TI2C_POLL); + PollCount++; + if (PollCount >= MAX_STOP_DET_POLL_COUNT) { + Status = EFI_TIMEOUT; + break; + } + + } while (TRUE); + + return Status; +} + +/** + + The InitializeInternal() function initialises internal I2C Controller + register values that are commonly required for I2C Write and Read transfers. + + @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address. + + @retval EFI_SUCCESS I2C Operation completed successfully. + +**/ +EFI_STATUS +InitializeInternal ( + IN EFI_I2C_ADDR_MODE AddrMode + ) +{ + UINTN I2CIoPortBaseAddress; + UINTN Addr; + UINT32 Data; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + // + // Enable access to I2C Controller MMIO space. + // + EnableI2CMmioSpace (); + + // + // Disable I2C Controller initially + // + DisableI2CController (); + + // + // Get I2C Memory Mapped registers base address. + // + I2CIoPortBaseAddress = GetI2CIoPortBaseAddress (); + + // + // Clear START_DET + // + Addr = I2CIoPortBaseAddress + I2C_REG_CLR_START_DET; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= ~B_I2C_REG_CLR_START_DET; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Clear STOP_DET + // + Addr = I2CIoPortBaseAddress + I2C_REG_CLR_STOP_DET; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= ~B_I2C_REG_CLR_STOP_DET; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Set addressing mode to user defined (7 or 10 bit) and + // speed mode to that defined by PCD (standard mode default). + // + Addr = I2CIoPortBaseAddress + I2C_REG_CON; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + // Set Addressing Mode + if (AddrMode == EfiI2CSevenBitAddrMode) { + Data &= ~B_I2C_REG_CON_10BITADD_MASTER; + } else { + Data |= B_I2C_REG_CON_10BITADD_MASTER; + } + // Set Speed Mode + Data &= ~B_I2C_REG_CON_SPEED; + if (FeaturePcdGet (PcdI2CFastModeEnabled)) { + Data |= BIT2; + } else { + Data |= BIT1; + } + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + Data = *((volatile UINT32 *) (UINTN)(Addr)); + + return Status; + +} + +/** + + The WriteByte() function provides a standard way to execute a + standard single byte write to an IC2 device (without accessing + sub-addresses), as defined in the I2C Specification. + + @param I2CAddress I2C Slave device address + @param Value The 8-bit value to write. + + @retval EFI_SUCCESS Transfer success. + @retval EFI_UNSUPPORTED Unsupported input param. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + +**/ +EFI_STATUS +EFIAPI +WriteByte ( + IN UINTN I2CAddress, + IN UINT8 Value + ) +{ + UINTN I2CIoPortBaseAddress; + UINTN Addr; + UINT32 Data; + EFI_STATUS Status; + + // + // Get I2C Memory Mapped registers base address + // + I2CIoPortBaseAddress = GetI2CIoPortBaseAddress (); + + // + // Write to the IC_TAR register the address of the slave device to be addressed + // + Addr = I2CIoPortBaseAddress + I2C_REG_TAR; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= ~B_I2C_REG_TAR; + Data |= I2CAddress; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Enable the I2C Controller + // + EnableI2CController (); + + // + // Write the data and transfer direction to the IC_DATA_CMD register. + // Also specify that transfer should be terminated by STOP condition. + // + Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= 0xFFFFFF00; + Data |= (UINT8)Value; + Data &= ~B_I2C_REG_DATA_CMD_RW; + Data |= B_I2C_REG_DATA_CMD_STOP; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Wait for transfer completion. + // + Status = WaitForStopDet (); + + // + // Ensure I2C Controller disabled. + // + DisableI2CController(); + + return Status; +} + +/** + + The ReadByte() function provides a standard way to execute a + standard single byte read to an IC2 device (without accessing + sub-addresses), as defined in the I2C Specification. + + @param I2CAddress I2C Slave device address + @param ReturnDataPtr Pointer to location to receive read byte. + + @retval EFI_SUCCESS Transfer success. + @retval EFI_UNSUPPORTED Unsupported input param. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + +**/ +EFI_STATUS +EFIAPI +ReadByte ( + IN UINTN I2CAddress, + OUT UINT8 *ReturnDataPtr + ) +{ + UINTN I2CIoPortBaseAddress; + UINTN Addr; + UINT32 Data; + EFI_STATUS Status; + + // + // Get I2C Memory Mapped registers base address. + // + I2CIoPortBaseAddress = GetI2CIoPortBaseAddress (); + + // + // Write to the IC_TAR register the address of the slave device to be addressed + // + Addr = I2CIoPortBaseAddress + I2C_REG_TAR; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= ~B_I2C_REG_TAR; + Data |= I2CAddress; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Enable the I2C Controller + // + EnableI2CController (); + + // + // Write transfer direction to the IC_DATA_CMD register and + // specify that transfer should be terminated by STOP condition. + // + Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= 0xFFFFFF00; + Data |= B_I2C_REG_DATA_CMD_RW; + Data |= B_I2C_REG_DATA_CMD_STOP; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Wait for transfer completion + // + Status = WaitForStopDet (); + if (!EFI_ERROR(Status)) { + + // + // Clear RX underflow before reading IC_DATA_CMD. + // + Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + + // + // Obtain and return read data byte from RX buffer (IC_DATA_CMD[7:0]). + // + Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= 0x000000FF; + *ReturnDataPtr = (UINT8) Data; + + Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER; + if (Data != 0) { + Status = EFI_DEVICE_ERROR; + } + } + + // + // Ensure I2C Controller disabled. + // + DisableI2CController (); + + return Status; +} + +/** + + The WriteMultipleByte() function provides a standard way to execute + multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or + when writing block of data), as defined in the I2C Specification. + + @param I2CAddress The I2C slave address of the device + with which to communicate. + + @param WriteBuffer Contains the value of byte to be written to the + I2C slave device. + + @param Length No. of bytes to be written. + + @retval EFI_SUCCESS Transfer success. + @retval EFI_UNSUPPORTED Unsupported input param. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Tx abort signaled in HW status register. + @retval EFI_DEVICE_ERROR Tx overflow detected. + +**/ +EFI_STATUS +EFIAPI +WriteMultipleByte ( + IN UINTN I2CAddress, + IN UINT8 *WriteBuffer, + IN UINTN Length + ) +{ + UINTN I2CIoPortBaseAddress; + UINTN Index; + UINTN Addr; + UINT32 Data; + EFI_STATUS Status; + + if (Length > I2C_FIFO_SIZE) { + return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size. + } + + I2CIoPortBaseAddress = GetI2CIoPortBaseAddress (); + + // + // Write to the IC_TAR register the address of the slave device to be addressed + // + Addr = I2CIoPortBaseAddress + I2C_REG_TAR; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= ~B_I2C_REG_TAR; + Data |= I2CAddress; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Enable the I2C Controller + // + EnableI2CController (); + + // + // Write the data and transfer direction to the IC_DATA_CMD register. + // Also specify that transfer should be terminated by STOP condition. + // + Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD; + for (Index = 0; Index < Length; Index++) { + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= 0xFFFFFF00; + Data |= (UINT8)WriteBuffer[Index]; + Data &= ~B_I2C_REG_DATA_CMD_RW; + if (Index == (Length-1)) { + Data |= B_I2C_REG_DATA_CMD_STOP; + } + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + } + + // + // Wait for transfer completion + // + Status = WaitForStopDet (); + + // + // Ensure I2C Controller disabled. + // + DisableI2CController (); + return Status; +} + +/** + + The ReadMultipleByte() function provides a standard way to execute + multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or + when reading block of data), as defined in the I2C Specification (I2C combined + write/read protocol). + + @param I2CAddress The I2C slave address of the device + with which to communicate. + + @param Buffer Contains the value of byte data written or read from the + I2C slave device. + + @param WriteLength No. of bytes to be written. In this case data + written typically contains sub-address or sub-addresses + in Hi-Lo format, that need to be read (I2C combined + write/read protocol). + + @param ReadLength No. of bytes to be read from I2C slave device. + + @retval EFI_SUCCESS Transfer success. + @retval EFI_UNSUPPORTED Unsupported input param. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Tx abort signaled in HW status register. + @retval EFI_DEVICE_ERROR Rx underflow or Rx/Tx overflow detected. + +**/ +EFI_STATUS +EFIAPI +ReadMultipleByte ( + IN UINTN I2CAddress, + IN OUT UINT8 *Buffer, + IN UINTN WriteLength, + IN UINTN ReadLength + ) +{ + UINTN I2CIoPortBaseAddress; + UINTN Index; + UINTN Addr; + UINT32 Data; + UINT8 PollCount; + EFI_STATUS Status; + + if (WriteLength > I2C_FIFO_SIZE || ReadLength > I2C_FIFO_SIZE) { + return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size. + } + + I2CIoPortBaseAddress = GetI2CIoPortBaseAddress (); + + // + // Write to the IC_TAR register the address of the slave device to be addressed + // + Addr = I2CIoPortBaseAddress + I2C_REG_TAR; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= ~B_I2C_REG_TAR; + Data |= I2CAddress; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + + // + // Enable the I2C Controller + // + EnableI2CController (); + + // + // Write the data (sub-addresses) to the IC_DATA_CMD register. + // + Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD; + for (Index = 0; Index < WriteLength; Index++) { + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= 0xFFFFFF00; + Data |= (UINT8)Buffer[Index]; + Data &= ~B_I2C_REG_DATA_CMD_RW; + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + } + + // + // Issue Read Transfers for each byte (Restart issued when write/read bit changed). + // + for (Index = 0; Index < ReadLength; Index++) { + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data |= B_I2C_REG_DATA_CMD_RW; + // Issue a STOP for last read transfer. + if (Index == (ReadLength-1)) { + Data |= B_I2C_REG_DATA_CMD_STOP; + } + *((volatile UINT32 *) (UINTN)(Addr)) = Data; + } + + // + // Wait for STOP condition. + // + Status = WaitForStopDet (); + if (!EFI_ERROR(Status)) { + + // + // Poll Receive FIFO Buffer Level register until valid (upto MAX_T_POLL_COUNT times). + // + Data = 0; + PollCount = 0; + Addr = I2CIoPortBaseAddress + I2C_REG_RXFLR; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + while ((Data != ReadLength) && (PollCount < MAX_T_POLL_COUNT)) { + MicroSecondDelay(TI2C_POLL); + PollCount++; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + } + + Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + + // + // If no timeout or device error then read rx data. + // + if (PollCount == MAX_T_POLL_COUNT) { + Status = EFI_TIMEOUT; + } else if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) { + Status = EFI_DEVICE_ERROR; + } else { + + // + // Clear RX underflow before reading IC_DATA_CMD. + // + Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + + // + // Read data. + // + Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD; + for (Index = 0; Index < ReadLength; Index++) { + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= 0x000000FF; + *(Buffer+Index) = (UINT8)Data; + } + Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT; + Data = *((volatile UINT32 *) (UINTN)(Addr)); + Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER; + if (Data != 0) { + Status = EFI_DEVICE_ERROR; + } else { + Status = EFI_SUCCESS; + } + } + } + + // + // Ensure I2C Controller disabled. + // + DisableI2CController (); + + return Status; +} + +/** + + The I2cWriteByte() function is a wrapper function for the WriteByte function. + Provides a standard way to execute a standard single byte write to an IC2 device + (without accessing sub-addresses), as defined in the I2C Specification. + + @param SlaveAddress The I2C slave address of the device + with which to communicate. + + @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address. + + @param Buffer Contains the value of byte data to execute to the + I2C slave device. + + + @retval EFI_SUCCESS Transfer success. + @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid. + @retval EFI_UNSUPPORTED Unsupported input param. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + +**/ +EFI_STATUS +EFIAPI +I2cWriteByte ( + IN EFI_I2C_DEVICE_ADDRESS SlaveAddress, + IN EFI_I2C_ADDR_MODE AddrMode, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN I2CAddress; + UINT16 SaveCmd; + UINT32 SaveBar0; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + SaveCmd = 0; + SaveBar0 = 0; + + I2cCommonServiceEntry (&SaveCmd, &SaveBar0); + + Status = EFI_SUCCESS; + + I2CAddress = SlaveAddress.I2CDeviceAddress; + Status = InitializeInternal (AddrMode); + if (!EFI_ERROR(Status)) { + Status = WriteByte (I2CAddress, *(UINT8 *) Buffer); + } + + I2cCommonServiceExit (SaveCmd, SaveBar0); + return Status; +} + +/** + + The I2cReadByte() function is a wrapper function for the ReadByte function. + Provides a standard way to execute a standard single byte read to an I2C device + (without accessing sub-addresses), as defined in the I2C Specification. + + @param SlaveAddress The I2C slave address of the device + with which to communicate. + + @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address. + + @param Buffer Contains the value of byte data read from the + I2C slave device. + + + @retval EFI_SUCCESS Transfer success. + @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + + +**/ +EFI_STATUS +EFIAPI +I2cReadByte ( + IN EFI_I2C_DEVICE_ADDRESS SlaveAddress, + IN EFI_I2C_ADDR_MODE AddrMode, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN I2CAddress; + UINT16 SaveCmd; + UINT32 SaveBar0; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + SaveCmd = 0; + SaveBar0 =0; + + I2cCommonServiceEntry (&SaveCmd, &SaveBar0); + + Status = EFI_SUCCESS; + + I2CAddress = SlaveAddress.I2CDeviceAddress; + + Status = InitializeInternal (AddrMode); + if (!EFI_ERROR(Status)) { + Status = ReadByte (I2CAddress, (UINT8 *) Buffer); + } + I2cCommonServiceExit (SaveCmd, SaveBar0); + return Status; +} + +/** + + The I2cWriteMultipleByte() function is a wrapper function for the + WriteMultipleByte() function. Provides a standard way to execute multiple + byte writes to an I2C device (e.g. when accessing sub-addresses or writing + block of data), as defined in the I2C Specification. + + @param SlaveAddress The I2C slave address of the device + with which to communicate. + + @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address. + + @param Length No. of bytes to be written. + + @param Buffer Contains the value of byte to be written to the + I2C slave device. + + @retval EFI_SUCCESS Transfer success. + @retval EFI_INVALID_PARAMETER This, Length or Buffer pointers are invalid. + @retval EFI_UNSUPPORTED Unsupported input param. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + +**/ +EFI_STATUS +EFIAPI +I2cWriteMultipleByte ( + IN EFI_I2C_DEVICE_ADDRESS SlaveAddress, + IN EFI_I2C_ADDR_MODE AddrMode, + IN UINTN *Length, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN I2CAddress; + UINT16 SaveCmd; + UINT32 SaveBar0; + + if (Buffer == NULL || Length == NULL) { + return EFI_INVALID_PARAMETER; + } + SaveCmd = 0; + SaveBar0 =0; + + I2cCommonServiceEntry (&SaveCmd, &SaveBar0); + Status = EFI_SUCCESS; + + I2CAddress = SlaveAddress.I2CDeviceAddress; + + Status = InitializeInternal (AddrMode); + if (!EFI_ERROR(Status)) { + Status = WriteMultipleByte (I2CAddress, Buffer, (*Length)); + } + + I2cCommonServiceExit (SaveCmd, SaveBar0); + return Status; +} + +/** + + The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte() function. + Provides a standard way to execute multiple byte writes to an I2C device + (e.g. when accessing sub-addresses or when reading block of data), as defined + in the I2C Specification (I2C combined write/read protocol). + + @param SlaveAddress The I2C slave address of the device + with which to communicate. + + @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address. + + @param WriteLength No. of bytes to be written. In this case data + written typically contains sub-address or sub-addresses + in Hi-Lo format, that need to be read (I2C combined + write/read protocol). + + @param ReadLength No. of bytes to be read from I2C slave device. + + @param Buffer Contains the value of byte data read from the + I2C slave device. + + @retval EFI_SUCCESS Transfer success. + @retval EFI_INVALID_PARAMETER This, WriteLength, ReadLength or Buffer + pointers are invalid. + @retval EFI_UNSUPPORTED Unsupported input param. + @retval EFI_TIMEOUT Timeout while waiting xfer. + @retval EFI_ABORTED Controller aborted xfer. + @retval EFI_DEVICE_ERROR Device error detected by controller. + +**/ +EFI_STATUS +EFIAPI +I2cReadMultipleByte ( + IN EFI_I2C_DEVICE_ADDRESS SlaveAddress, + IN EFI_I2C_ADDR_MODE AddrMode, + IN UINTN *WriteLength, + IN UINTN *ReadLength, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN I2CAddress; + UINT16 SaveCmd; + UINT32 SaveBar0; + + if (Buffer == NULL || WriteLength == NULL || ReadLength == NULL) { + return EFI_INVALID_PARAMETER; + } + SaveCmd = 0; + SaveBar0 =0; + + I2cCommonServiceEntry (&SaveCmd, &SaveBar0); + + Status = EFI_SUCCESS; + + I2CAddress = SlaveAddress.I2CDeviceAddress; + Status = InitializeInternal (AddrMode); + if (!EFI_ERROR(Status)) { + Status = ReadMultipleByte (I2CAddress, Buffer, (*WriteLength), (*ReadLength)); + } + I2cCommonServiceExit (SaveCmd, SaveBar0); + return Status; +} + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf new file mode 100644 index 0000000000..243582fcae --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.inf @@ -0,0 +1,62 @@ +## @file +# Component description file for Quark South Cluster I2C library. +# +# I2C library implement QuarkSCSocId related drivers, includes: +# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver. +# +# This driver contains I2C bus access routines: +# 1. I2C Read (byte, multi-byte) +# 2. I2C Write (byte, multi-byte) +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = I2cLib + FILE_GUID = 462d127a-c143-469e-8449-b6e36beb04a8 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = I2cLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + CommonHeader.h + I2cLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + PcdLib + PciLib + BaseMemoryLib + MemoryAllocationLib + DebugLib + BaseLib + TimerLib + IoLib + IohLib + +[FeaturePcd] + gEfiQuarkSCSocIdTokenSpaceGuid.PcdI2CFastModeEnabled + +[FixedPcd] + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohI2cMmioBase + +[Pcd] + +[Depex] + TRUE diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h new file mode 100644 index 0000000000..bcb7f593a6 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/CommonHeader.h @@ -0,0 +1,29 @@ +/** @file +Common header file shared by all source files. + +This file includes package header files, library classes and protocol, PPI & GUID definitions. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef __COMMON_HEADER_H_ +#define __COMMON_HEADER_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c new file mode 100644 index 0000000000..9e7e6b7c35 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.c @@ -0,0 +1,99 @@ +/** @file +Lib function for Pei Quark South Cluster. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "CommonHeader.h" + +/** + Program SVID/SID the same as VID/DID* +**/ +EFI_STATUS +EFIAPI +InitializeIohSsvidSsid ( + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Func + ) +{ + UINTN Index; + + for (Index = 0; Index <= IOH_PCI_IOSF2AHB_0_MAX_FUNCS; Index++) { + if (((Device == IOH_PCI_IOSF2AHB_1_DEV_NUM) && (Index >= IOH_PCI_IOSF2AHB_1_MAX_FUNCS))) { + continue; + } + + IohMmPci32(0, Bus, Device, Index, PCI_REG_SVID0) = IohMmPci32(0, Bus, Device, Index, PCI_REG_VID); + } + + return EFI_SUCCESS; +} + +/* Enable memory, io, and bus master for USB controller */ +VOID +EFIAPI +EnableUsbMemIoBusMaster ( + IN UINT8 UsbBusNumber + ) +{ + UINT16 CmdReg; + + CmdReg = PciRead16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, PCI_REG_PCICMD)); + CmdReg = (UINT16) (CmdReg | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_BUS_MASTER); + PciWrite16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, PCI_REG_PCICMD), CmdReg); + + CmdReg = PciRead16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, PCI_REG_PCICMD)); + CmdReg = (UINT16) (CmdReg | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_BUS_MASTER); + PciWrite16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, PCI_REG_PCICMD), CmdReg); +} + +/** + Read south cluster GPIO input from Port A. + +**/ +UINT32 +EFIAPI +ReadIohGpioValues ( + VOID + ) +{ + UINT32 GipData; + UINT32 GipAddr; + UINT32 TempBarAddr; + UINT16 SaveCmdReg; + UINT32 SaveBarReg; + + TempBarAddr = (UINT32) PcdGet64(PcdIohGpioMmioBase); + + GipAddr = PCI_LIB_ADDRESS( + PcdGet8 (PcdIohGpioBusNumber), + PcdGet8 (PcdIohGpioDevNumber), + PcdGet8 (PcdIohGpioFunctionNumber), 0); + + // + // Save current settings for PCI CMD/BAR registers. + // + SaveCmdReg = PciRead16 (GipAddr + PCI_COMMAND_OFFSET); + SaveBarReg = PciRead32 (GipAddr + PcdGet8 (PcdIohGpioBarRegister)); + + DEBUG ((EFI_D_INFO, "SC GPIO temporary enable at %08X\n", TempBarAddr)); + + // Use predefined temporary memory resource. + PciWrite32 ( GipAddr + PcdGet8 (PcdIohGpioBarRegister), TempBarAddr); + PciWrite8 ( GipAddr + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); + + // Read GPIO configuration + GipData = MmioRead32(TempBarAddr + GPIO_EXT_PORTA); + + // + // Restore settings for PCI CMD/BAR registers. + // + PciWrite32 ((GipAddr + PcdGet8 (PcdIohGpioBarRegister)), SaveBarReg); + PciWrite16 (GipAddr + PCI_COMMAND_OFFSET, SaveCmdReg); + + // Only 8 bits valid. + return GipData & 0x000000FF; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf new file mode 100644 index 0000000000..0fc506ba1e --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf @@ -0,0 +1,49 @@ +## @file +# Intel Soc Library Instance +# +# Intel Soc Library Instance +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = IohLib + FILE_GUID = B4C12297-7B19-4523-B165-81374D96716B + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = IohLib + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + IohLib.c + CommonHeader.h + +[Packages] + MdePkg/MdePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + DebugLib + PciLib + IoLib + PciCf8Lib + BaseLib + CpuLib + +[Pcd] + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioDevNumber + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioFunctionNumber + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBarRegister + gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioMmioBase diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c new file mode 100644 index 0000000000..85db4cd104 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.c @@ -0,0 +1,227 @@ +/** @file + +UEFI Component Name(2) protocol implementation for SD controller driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SDController.h" + + +// +// EFI Component Name Protocol +// + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSDControllerName = { + SDControllerGetDriverName, + SDControllerGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSDControllerName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SDControllerGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SDControllerGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSDControllerDriverNameTable[] = { + { "eng;en", L"EFI SD Host Controller Driver" }, + { NULL, NULL } +}; + + +// +// EFI Component Name Functions +// + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 3066 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SDControllerGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSDControllerDriverNameTable, + DriverName, + (BOOLEAN)(This == &gSDControllerName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 3066 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SDControllerGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + SDHOST_DATA *SDHostData; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver is currently managing ControllerHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gSDControllerDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSDHostIoProtocolGuid, + (VOID **) &SDHostIo, + gSDControllerDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + SDHostData = SDHOST_DATA_FROM_THIS(SDHostIo); + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + SDHostData->ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gSDControllerName) + ); + +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h new file mode 100644 index 0000000000..91cc4725ec --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/ComponentName.h @@ -0,0 +1,141 @@ +/** @file + +This file contains the delarations for componet name routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _COMPONENT_NAME_H_ +#define _COMPONENT_NAME_H_ + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 3066 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SDControllerGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 3066 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SDControllerGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c new file mode 100644 index 0000000000..7d97b90b92 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c @@ -0,0 +1,1784 @@ +/** @file + +The SD host controller driver model and HC protocol routines. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#include "SDController.h" + + +EFI_DRIVER_BINDING_PROTOCOL gSDControllerDriverBinding = { + SDControllerSupported, + SDControllerStart, + SDControllerStop, + 0x20, + NULL, + NULL +}; + + +EFI_SD_HOST_IO_PROTOCOL mSDHostIo = { + EFI_SD_HOST_IO_PROTOCOL_REVISION_01, + { + 0, // HighSpeedSupport + 0, // V18Support + 0, // V30Support + 0, // V33Support + 0, // Reserved0 + 0, // BusWidth4 + 0, // BusWidth8 + 0, // Reserved1 + 0, // Reserved1 + (512 * 1024) //BoundarySize + }, + SendCommand, + SetClockFrequency, + SetBusWidth, + SetHostVoltage, + ResetSDHost, + EnableAutoStopCmd, + DetectCardAndInitHost, + SetBlockLength, + SetHighSpeedMode, + SetDDRMode +}; + +/** + Find sdclk_freq_sel and upr_sdclk_freq_sel bits + for Clock Control Register (CLK_CTL)Offset 2Ch when using 8bit or 10bit + divided clock mode. + + @param BaseClockFreg Base Clock Frequency in Hz For SD Clock in the + Capabilities register. + @param TargetFreq Target Frequency in Hz to reach. + @param Is8BitMode True if 8-bit Divided Clock Mode else 10bit mode. + @param Bits sdclk_freq_sel and upr_sdclk_freq_sel bits for + TargetFreq. + + @return EFI_SUCCESS // Bits setup. + @return EFI_UNSUPPORTED // Cannot divide base clock to reach target clock. +**/ +EFI_STATUS +DividedClockModeBits ( + IN CONST UINTN BaseClockFreg, + IN CONST UINTN TargetFreq, + IN CONST BOOLEAN Is8BitMode, + OUT UINT16 *Bits + ) +{ + UINTN N; + UINTN CurrFreq; + + *Bits = 0; + CurrFreq = BaseClockFreg; + N = 0; + // + // N == 0 same for 8bit & 10bit mode i.e. BaseClockFreg of controller. + // + if (TargetFreq < CurrFreq) { + if (Is8BitMode) { + N = 1; + do { + // + // N values for 8bit mode when N > 0. + // Bit[15:8] SDCLK Frequency Select at offset 2Ch + // 80h - base clock divided by 256 + // 40h - base clock divided by 128 + // 20h - base clock divided by 64 + // 10h - base clock divided by 32 + // 08h - base clock divided by 16 + // 04h - base clock divided by 8 + // 02h - base clock divided by 4 + // 01h - base clock divided by 2 + // + CurrFreq = BaseClockFreg / (2 * N); + if (TargetFreq >= CurrFreq) { + break; + } + N *= 2; + if (N > V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL) { + return EFI_UNSUPPORTED; + } + } while (TRUE); + } else { + N = 1; + CurrFreq = BaseClockFreg / (2 * N); + // + // (try N = 0 or 1 first since don't want divide by 0). + // + if (TargetFreq < CurrFreq) { + // + // If still no match then calculate it for 10bit. + // N values for 10bit mode. + // N 1/2N Divided Clock (Duty 50%). + // from Spec "The length of divider is extended to 10 bits and all + // divider values shall be supported. + // + N = (BaseClockFreg / TargetFreq) / 2; + + // + // Can only be N or N+1; + // + CurrFreq = BaseClockFreg / (2 * N); + if (TargetFreq < CurrFreq) { + N++; + CurrFreq = BaseClockFreg / (2 * N); + } + + if (N > V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL) { + return EFI_UNSUPPORTED; + } + + // + // Set upper bits of SDCLK Frequency Select (bits 7:6 of reg 0x2c). + // + *Bits |= ((UINT16) ((N >> 2) & B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK)); + } + } + } + + // + // Set lower bits of SDCLK Frequency Select (bits 15:8 of reg 0x2c). + // + *Bits |= ((UINT16) ((UINT8) N) << 8); + DEBUG ( + (EFI_D_INFO, + "SDIO:DividedClockModeBits: %dbit mode Want %dHz Got %dHz bits = %04x\r\n", + (Is8BitMode) ? 8 : 10, + TargetFreq, + CurrFreq, + (UINTN) *Bits + )); + + return EFI_SUCCESS; +} + +/** + Print type of error and command index + + @param CommandIndex Command index to set the command index field of command register. + @param ErrorCode Error interrupt status read from host controller + + @return EFI_DEVICE_ERROR + @return EFI_TIMEOUT + @return EFI_CRC_ERROR + +**/ +EFI_STATUS +GetErrorReason ( + IN UINT16 CommandIndex, + IN UINT16 ErrorCode + ) +{ + EFI_STATUS Status; + + Status = EFI_DEVICE_ERROR; + + DEBUG((EFI_D_ERROR, "[%2d] -- ", CommandIndex)); + + if (ErrorCode & BIT0) { + Status = EFI_TIMEOUT; + DEBUG((EFI_D_ERROR, "Command Timeout Erro")); + } + + if (ErrorCode & BIT1) { + Status = EFI_CRC_ERROR; + DEBUG((EFI_D_ERROR, "Command CRC Error")); + } + + if (ErrorCode & BIT2) { + DEBUG((EFI_D_ERROR, "Command End Bit Error")); + } + + if (ErrorCode & BIT3) { + DEBUG((EFI_D_ERROR, "Command Index Error")); + } + if (ErrorCode & BIT4) { + Status = EFI_TIMEOUT; + DEBUG((EFI_D_ERROR, "Data Timeout Error")); + } + + if (ErrorCode & BIT5) { + Status = EFI_CRC_ERROR; + DEBUG((EFI_D_ERROR, "Data CRC Error")); + } + + if (ErrorCode & BIT6) { + DEBUG((EFI_D_ERROR, "Data End Bit Error")); + } + + if (ErrorCode & BIT7) { + DEBUG((EFI_D_ERROR, "Current Limit Error")); + } + + if (ErrorCode & BIT8) { + DEBUG((EFI_D_ERROR, "Auto CMD12 Error")); + } + + if (ErrorCode & BIT9) { + DEBUG((EFI_D_ERROR, "ADMA Error")); + } + + DEBUG((EFI_D_ERROR, "\n")); + + return Status; +} +/** + Enable/Disable High Speed transfer mode + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Enable TRUE to Enable, FALSE to Disable + + @return EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +SetHighSpeedMode ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ) +{ + UINT32 Data; + SDHOST_DATA *SDHostData; + EFI_PCI_IO_PROTOCOL *PciIo; + + SDHostData = SDHOST_DATA_FROM_THIS (This); + PciIo = SDHostData->PciIo; + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_HOSTCTL, + 1, + &Data + ); + + if (Enable) { + if (PcdGetBool(PcdSdHciQuirkNoHiSpd)) { + DEBUG ((EFI_D_INFO, "SDIO: Quirk never set High Speed Enable bit\r\n")); + return EFI_SUCCESS; + } + DEBUG ((EFI_D_INFO, "Enable High Speed transfer mode ... \r\n")); + Data |= BIT2; + } else { + Data &= ~BIT2; + } + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_HOSTCTL, + 1, + &Data + ); + return EFI_SUCCESS; +} +EFI_STATUS +EFIAPI +SetDDRMode ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ) +{ + UINT16 Data; + SDHOST_DATA *SDHostData; + EFI_PCI_IO_PROTOCOL *PciIo; + SDHostData = SDHOST_DATA_FROM_THIS (This); + PciIo = SDHostData->PciIo; + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_HOSTCTL2, + 1, + &Data + ); + Data &= 0xFFF0; + if (Enable) { + Data |= 0x0004; // Enable DDR50 by default, later should enable other mode like HS200/400 + Data |= BIT3; // Enable 1.8V Signaling + } + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_HOSTCTL2, + 1, + &Data + ); + return EFI_SUCCESS; +} +/** + Power on/off the LED associated with the slot + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Enable TRUE to set LED on, FALSE to set LED off + + @return EFI_SUCCESS +**/ +EFI_STATUS +HostLEDEnable ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ) +{ + SDHOST_DATA *SDHostData; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 Data; + + SDHostData = SDHOST_DATA_FROM_THIS (This); + PciIo = SDHostData->PciIo; + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_HOSTCTL, + 1, + &Data + ); + + if (Enable) { + // + //LED On + // + Data |= BIT0; + } else { + // + //LED Off + // + Data &= ~BIT0; + } + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_HOSTCTL, + 1, + &Data + ); + + return EFI_SUCCESS; +} + + +/** + The main function used to send the command to the card inserted into the SD host slot. + It will assemble the arguments to set the command register and wait for the command + and transfer completed until timeout. Then it will read the response register to fill + the ResponseData. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param CommandIndex The command index to set the command index field of command register. + @param Argument Command argument to set the argument field of command register. + @param DataType TRANSFER_TYPE, indicates no data, data in or data out. + @param Buffer Contains the data read from / write to the device. + @param BufferSize The size of the buffer. + @param ResponseType RESPONSE_TYPE. + @param TimeOut Time out value in 1 ms unit. + @param ResponseData Depending on the ResponseType, such as CSD or card status. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_OUT_OF_RESOURCES + @retval EFI_TIMEOUT + @retval EFI_DEVICE_ERROR + +**/ + +EFI_STATUS +EFIAPI +SendCommand ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT16 CommandIndex, + IN UINT32 Argument, + IN TRANSFER_TYPE DataType, + IN UINT8 *Buffer, OPTIONAL + IN UINT32 BufferSize, + IN RESPONSE_TYPE ResponseType, + IN UINT32 TimeOut, + OUT UINT32 *ResponseData OPTIONAL + ) +/*++ + + Routine Description: + The main function used to send the command to the card inserted into the SD host + slot. + It will assemble the arguments to set the command register and wait for the command + and transfer completed until timeout. Then it will read the response register to fill + the ResponseData + + Arguments: + This - Pointer to EFI_SD_HOST_IO_PROTOCOL + CommandIndex - The command index to set the command index field of command register + Argument - Command argument to set the argument field of command register + DataType - TRANSFER_TYPE, indicates no data, data in or data out + Buffer - Contains the data read from / write to the device + BufferSize - The size of the buffer + ResponseType - RESPONSE_TYPE + TimeOut - Time out value in 1 ms unit + ResponseData - Depending on the ResponseType, such as CSD or card status + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + EFI_TIMEOUT + EFI_DEVICE_ERROR + +--*/ +{ + EFI_STATUS Status; + SDHOST_DATA *SDHostData; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 ResponseDataCount; + UINT32 Data; + UINT64 Data64; + UINT8 Index; + INTN TimeOut2; + BOOLEAN AutoCMD12Enable = FALSE; + + + Status = EFI_SUCCESS; + ResponseDataCount = 1; + SDHostData = SDHOST_DATA_FROM_THIS (This); + PciIo = SDHostData->PciIo; + AutoCMD12Enable = (CommandIndex & AUTO_CMD12_ENABLE) ? TRUE : FALSE; + CommandIndex = CommandIndex & CMD_INDEX_MASK; + + if (Buffer != NULL && DataType == NoData) { + Status = EFI_INVALID_PARAMETER; + DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n")); + goto Exit; + } + + if (((UINTN)Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN)NULL) { + Status = EFI_INVALID_PARAMETER; + DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n")); + goto Exit; + } + + DEBUG ((EFI_D_INFO, "SendCommand: Command Index = %d \r\n", CommandIndex)); + // + TimeOut2 = 1000; // 10 ms + do { + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + (UINT64)MMIO_PSTATE, + 1, + &Data + ); + gBS->Stall (10); + }while ((TimeOut2-- > 0) && (Data & BIT0)); + TimeOut2 = 1000; // 10 ms + do { + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + (UINT64)MMIO_PSTATE, + 1, + &Data + ); + gBS->Stall (10); + }while ((TimeOut2-- > 0) && (Data & BIT1)); + //Clear status bits + // + Data = 0xFFFF; + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_NINTSTS, + 1, + &Data + ); + + Data = 0xFFFF; + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_ERINTSTS, + 1, + &Data + ); + + + if (Buffer != NULL) { + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint32, + 0, + (UINT64)MMIO_DMAADR, + 1, + &Buffer + ); + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_BLKSZ, + 1, + &Data + ); + Data &= ~(0xFFF); + if (BufferSize <= SDHostData->BlockLength) { + Data |= (BufferSize | 0x7000); + } else { + Data |= (SDHostData->BlockLength | 0x7000); + } + + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_BLKSZ, + 1, + &Data + ); + if (BufferSize <= SDHostData->BlockLength) { + Data = 1; + } else { + Data = BufferSize / SDHostData->BlockLength; + } + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_BLKCNT, + 1, + &Data + ); + + } else { + Data = 0; + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_BLKSZ, + 1, + &Data + ); + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_BLKCNT, + 1, + &Data + ); + } + + // + //Argument + // + Data = Argument; + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint32, + 0, + (UINT64)MMIO_CMDARG, + 1, + &Data + ); + + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_XFRMODE, + 1, + &Data + ); + + + DEBUG ((EFI_D_INFO, "Transfer mode read = 0x%x \r\n", (Data & 0xFFFF))); + // + //BIT0 - DMA Enable + //BIT2 - Auto Cmd12 + // + if (DataType == InData) { + Data |= BIT4 | BIT0; + } else if (DataType == OutData){ + Data &= ~BIT4; + Data |= BIT0; + } else { + Data &= ~(BIT4 | BIT0); + } + + if (BufferSize <= SDHostData->BlockLength) { + Data &= ~ (BIT5 | BIT1 | BIT2); + Data |= BIT1; // Enable block count always + } else { + if (SDHostData->IsAutoStopCmd && AutoCMD12Enable) { + Data |= (BIT5 | BIT1 | BIT2); + } else { + Data |= (BIT5 | BIT1); + } + } + + DEBUG ((EFI_D_INFO, "Transfer mode write = 0x%x \r\n", (Data & 0xffff))); + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_XFRMODE, + 1, + &Data + ); + // + //Command + // + //ResponseTypeSelect IndexCheck CRCCheck ResponseType + // 00 0 0 NoResponse + // 01 0 1 R2 + // 10 0 0 R3, R4 + // 10 1 1 R1, R5, R6, R7 + // 11 1 1 R1b, R5b + // + switch (ResponseType) { + case ResponseNo: + Data = (CommandIndex << 8); + ResponseDataCount = 0; + break; + + case ResponseR1: + case ResponseR5: + case ResponseR6: + case ResponseR7: + Data = (CommandIndex << 8) | BIT1 | BIT4| BIT3; + ResponseDataCount = 1; + break; + + case ResponseR1b: + case ResponseR5b: + Data = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3; + ResponseDataCount = 1; + break; + + case ResponseR2: + Data = (CommandIndex << 8) | BIT0 | BIT3; + ResponseDataCount = 4; + break; + + case ResponseR3: + case ResponseR4: + Data = (CommandIndex << 8) | BIT1; + ResponseDataCount = 1; + break; + + default: + ASSERT (0); + Status = EFI_INVALID_PARAMETER; + DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n")); + goto Exit; + } + + if (DataType != NoData) { + Data |= BIT5; + } + + HostLEDEnable (This, TRUE); + + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_SDCMD, + 1, + &Data + ); + + + Data = 0; + do { + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_ERINTSTS, + 1, + &Data + ); + + if ((Data & 0x07FF) != 0) { + Status = GetErrorReason (CommandIndex, (UINT16)Data); + DEBUG ((EFI_D_ERROR, "SendCommand: Error happens \r\n")); + goto Exit; + } + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_NINTSTS, + 1, + &Data + ); + + if ((Data & BIT0) == BIT0) { + // + //Command completed, can read response + // + if (DataType == NoData) { + break; + } else { + // + //Transfer completed + // + if ((Data & BIT1) == BIT1) { + break; + } + } + } + + gBS->Stall (1 * 1000); + + TimeOut --; + + } while (TimeOut > 0); + + if (TimeOut == 0) { + Status = EFI_TIMEOUT; + DEBUG ((EFI_D_ERROR, "SendCommand: Time out \r\n")); + goto Exit; + } + + if (ResponseData != NULL) { + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + (UINT64)MMIO_RESP, + ResponseDataCount, + ResponseData + ); + if (ResponseType == ResponseR2) { + // + // Adjustment for R2 response + // + Data = 1; + for (Index = 0; Index < ResponseDataCount; Index++) { + Data64 = LShiftU64(*ResponseData, 8); + *ResponseData = (UINT32)((Data64 & 0xFFFFFFFF) | Data); + Data = (UINT32)RShiftU64 (Data64, 32); + ResponseData++; + } + } + } + +Exit: + HostLEDEnable (This, FALSE); + return Status; +} + +/** + Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency. + It depends on the max frequency the host can support, divider, and host speed mode. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param MaxFrequency Max frequency in HZ. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ +EFI_STATUS +EFIAPI +SetClockFrequency ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 MaxFrequency + ) +{ + UINT32 Data; + UINT16 FreqSelBits; + EFI_STATUS Status; + SDHOST_DATA *SDHostData; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 TimeOutCount; + UINT32 Revision; + + SDHostData = SDHOST_DATA_FROM_THIS (This); + PciIo = SDHostData->PciIo; + Data = 0; + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CLKCTL, + 1, + &Data + ); + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_CTRLRVER, + 1, + &Revision + ); + Revision &= 0x000000FF; + + Status = DividedClockModeBits ( + SDHostData->BaseClockInMHz * 1000 * 1000, + MaxFrequency, + (Revision < SDHCI_SPEC_300), + &FreqSelBits + ); + + if (EFI_ERROR (Status)) { + // + // Cannot reach MaxFrequency with SDHostData->BaseClockInMHz. + // + ASSERT_EFI_ERROR (Status); + return Status; + } + + Data = 0; + + // + //Enable internal clock and Stop Clock Enable + // + Data = BIT0; + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CLKCTL, + 1, + &Data + ); + + TimeOutCount = TIME_OUT_1S; + do { + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CLKCTL, + 1, + &Data + ); + gBS->Stall (1 * 1000); + TimeOutCount --; + if (TimeOutCount == 0) { + DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n")); + return EFI_TIMEOUT; + } + } while ((Data & BIT1) != BIT1); + + DEBUG ((EFI_D_INFO, "Base Clock In MHz: %d\r\n", SDHostData->BaseClockInMHz)); + + Data = (BIT0 | ((UINT32) FreqSelBits)); + DEBUG ((EFI_D_INFO, "Data write to MMIO_CLKCTL: 0x%04x \r\n", Data)); + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CLKCTL, + 1, + &Data + ); + + TimeOutCount = TIME_OUT_1S; + do { + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CLKCTL, + 1, + &Data + ); + gBS->Stall (1 * 1000); + TimeOutCount --; + if (TimeOutCount == 0) { + DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n")); + return EFI_TIMEOUT; + } + } while ((Data & BIT1) != BIT1); + gBS->Stall (20 * 1000); + Data |= BIT2; + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CLKCTL, + 1, + &Data + ); + + return EFI_SUCCESS; +} + +/** + Set bus width of the host controller + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param BusWidth Bus width in 1, 4, 8 bits. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + +**/ +EFI_STATUS +EFIAPI +SetBusWidth ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 BusWidth + ) +{ + SDHOST_DATA *SDHostData; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 Data; + + SDHostData = SDHOST_DATA_FROM_THIS (This); + + + if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) { + DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n")); + return EFI_INVALID_PARAMETER; + } + + if ((SDHostData->SDHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) { + DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n")); + return EFI_INVALID_PARAMETER; + } + + PciIo = SDHostData->PciIo; + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_HOSTCTL, + 1, + &Data + ); + // + // BIT5 8-bit MMC Support (MMC8): + // If set, IOH supports 8-bit MMC. When cleared, IOH does not support this feature + // + if (BusWidth == 8) { + DEBUG ((EFI_D_INFO, "Bus Width is 8-bit ... \r\n")); + Data |= BIT5; + } else if (BusWidth == 4) { + DEBUG ((EFI_D_INFO, "Bus Width is 4-bit ... \r\n")); + Data &= ~BIT5; + Data |= BIT1; + } else { + DEBUG ((EFI_D_INFO, "Bus Width is 1-bit ... \r\n")); + Data &= ~BIT5; + Data &= ~BIT1; + } + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_HOSTCTL, + 1, + &Data + ); + + return EFI_SUCCESS; +} + + +/** + Set voltage which could supported by the host controller. + Support 0(Power off the host), 1.8V, 3.0V, 3.3V + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Voltage Units in 0.1 V. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + +**/ +EFI_STATUS +EFIAPI +SetHostVoltage ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 Voltage + ) +{ + SDHOST_DATA *SDHostData; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 Data; + EFI_STATUS Status; + + SDHostData = SDHOST_DATA_FROM_THIS (This); + PciIo = SDHostData->PciIo; + Status = EFI_SUCCESS; + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_PWRCTL, + 1, + &Data + ); + + if (Voltage == 0) { + // + //Power Off the host + // + Data &= ~BIT0; + } else if (Voltage <= 18 && This->HostCapability.V18Support) { + // + //1.8V + // + Data |= (BIT1 | BIT3 | BIT0); + } else if (Voltage > 18 && Voltage <= 30 && This->HostCapability.V30Support) { + // + //3.0V + // + Data |= (BIT2 | BIT3 | BIT0); + } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) { + // + //3.3V + // + Data |= (BIT1 | BIT2 | BIT3 | BIT0); + } else { + Status = EFI_UNSUPPORTED; + goto Exit; + } + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_PWRCTL, + 1, + &Data + ); + gBS->Stall (10 * 1000); + +Exit: + return Status; +} + + + +/** + Reset the host controller. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param ResetAll TRUE to reset all. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ +EFI_STATUS +EFIAPI +ResetSDHost ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN RESET_TYPE ResetType + ) +{ + SDHOST_DATA *SDHostData; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 Data; + UINT16 ErrStatus; + UINT32 Mask; + UINT32 TimeOutCount; + UINT16 SaveClkCtl; + UINT16 ZeroClkCtl; + + SDHostData = SDHOST_DATA_FROM_THIS (This); + PciIo = SDHostData->PciIo; + Mask = 0; + ErrStatus = 0; + + if (ResetType == Reset_Auto) { + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_ERINTSTS, + 1, + &ErrStatus + ); + if ((ErrStatus & 0xF) != 0) { + // + //Command Line + // + Mask |= BIT1; + } + if ((ErrStatus & 0x70) != 0) { + // + //Data Line + // + Mask |= BIT2; + } + } + + + if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) { + Mask |= BIT2; + } + if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) { + Mask |= BIT1; + } + if (ResetType == Reset_All) { + Mask = BIT0; + } + + if (Mask == 0) { + return EFI_SUCCESS; + } + + // + // To improve SD stability, we zero the MMIO_CLKCTL register and + // stall for 50 microseconds before resetting the controller. We + // restore the register setting following the reset operation. + // + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CLKCTL, + 1, + &SaveClkCtl + ); + + ZeroClkCtl = (UINT16) 0; + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CLKCTL, + 1, + &ZeroClkCtl + ); + + gBS->Stall (50); + + // + // Reset the SD host controller + // + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_SWRST, + 1, + &Mask + ); + + Data = 0; + TimeOutCount = TIME_OUT_1S; + do { + + gBS->Stall (1 * 1000); + + TimeOutCount --; + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_SWRST, + 1, + &Data + ); + if ((Data & Mask) == 0) { + break; + } + } while (TimeOutCount > 0); + + // + // We now restore the MMIO_CLKCTL register which we set to 0 above. + // + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CLKCTL, + 1, + &SaveClkCtl + ); + + if (TimeOutCount == 0) { + DEBUG ((EFI_D_ERROR, "ResetSDHost: Time out \r\n")); + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + + +/** + Enable auto stop on the host controller. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Enable TRUE to enable, FALSE to disable. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ +EFI_STATUS +EFIAPI +EnableAutoStopCmd ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ) +{ + SDHOST_DATA *SDHostData; + + SDHostData = SDHOST_DATA_FROM_THIS (This); + + SDHostData->IsAutoStopCmd = Enable; + + return EFI_SUCCESS; +} + +/** + Set the Block length on the host controller. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param BlockLength card supportes block length. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ +EFI_STATUS +EFIAPI +SetBlockLength ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 BlockLength + ) +{ + SDHOST_DATA *SDHostData; + + SDHostData = SDHOST_DATA_FROM_THIS (This); + + DEBUG ((EFI_D_INFO, "Block length on the host controller: %d \r\n", BlockLength)); + SDHostData->BlockLength = BlockLength; + + return EFI_SUCCESS; +} + + +/** + Find whether these is a card inserted into the slot. If so init the host. + If not, return EFI_NOT_FOUND. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + +**/ +EFI_STATUS +EFIAPI +DetectCardAndInitHost ( + IN EFI_SD_HOST_IO_PROTOCOL *This + ) +{ + SDHOST_DATA *SDHostData; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 Data; + EFI_STATUS Status; + UINT8 Voltages[] = { 33, 30, 18 }; + UINTN Loop; + + SDHostData = SDHOST_DATA_FROM_THIS (This); + PciIo = SDHostData->PciIo; + Status = EFI_NOT_FOUND; + + Data = 0; + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + (UINT64)MMIO_PSTATE, + 1, + &Data + ); + + if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) { + // + // Has no card inserted + // + DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: No Cards \r\n")); + Status = EFI_NOT_FOUND; + goto Exit; + } + DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: Find Cards \r\n")); + + Status = EFI_NOT_FOUND; + for (Loop = 0; Loop < sizeof (Voltages); Loop++) { + DEBUG (( + EFI_D_INFO, + "DetectCardAndInitHost: SetHostVoltage %d.%dV \r\n", + Voltages[Loop] / 10, + Voltages[Loop] % 10 + )); + Status = SetHostVoltage (This, Voltages[Loop]); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [failed]\n")); + } else { + DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [success]\n")); + break; + } + } + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set voltage \r\n")); + goto Exit; + } + + Status = SetClockFrequency (This, FREQUENCY_OD); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set frequency \r\n")); + goto Exit; + } + SetBusWidth (This, 1); + + // + //Enable normal status change + // + + Data = (BIT0 | BIT1); + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_NINTEN, + 1, + &Data + ); + + // + //Enable error status change + // + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_ERINTEN, + 1, + &Data + ); + + Data |= (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8); + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_ERINTEN, + 1, + &Data + ); + + // + //Data transfer Timeout control + // + Data = 0x0E; + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + 0, + (UINT64)MMIO_TOCTL, + 1, + &Data + ); + // + //Set Default Bus width as 1 bit + // + +Exit: + return Status; + +} + +/** + Entry point for EFI drivers. + + @param ImageHandle EFI_HANDLE. + @param SystemTable EFI_SYSTEM_TABLE. + + @retval EFI_SUCCESS Driver is successfully loaded. + @return Others Failed. + +**/ +EFI_STATUS +EFIAPI +InitializeSDController ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSDControllerDriverBinding, + ImageHandle, + &gSDControllerName, + &gSDControllerName2 + ); +} + + +/** + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that has SDHostIoProtocol installed will be supported. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS This driver supports this device. + @return EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +SDControllerSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS OpenStatus; + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_CLASSC PciClass; + EFI_SD_HOST_IO_PROTOCOL *SdHostIo; + Status = gBS->OpenProtocol ( + Controller, + &gEfiSDHostIoProtocolGuid, + (VOID **)&SdHostIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + DEBUG (( DEBUG_INFO, "SdHost controller is already started\n")); + return EFI_ALREADY_STARTED; + } + + // + // Test whether there is PCI IO Protocol attached on the controller handle. + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (OpenStatus)) { + return OpenStatus; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (PCI_CLASSC) / sizeof (UINT8), + &PciClass + ); + + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + + // + // Test whether the controller belongs to SD type + // + if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) || + (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) || + ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA)) + ) { + + Status = EFI_UNSUPPORTED; + } + +ON_EXIT: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} +/** + Starting the SD Host Controller Driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. + EFI_OUT_OF_RESOURCES- Failed due to resource shortage. + +**/ +EFI_STATUS +EFIAPI +SDControllerStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + SDHOST_DATA *SDHostData; + UINT32 Data; + + + SDHostData = NULL; + Data = 0; + + // + // Open PCI I/O Protocol and save pointer to open protocol + // in private data area. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Enable the SD Host Controller MMIO space + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE, + NULL + ); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + + SDHostData = (SDHOST_DATA*)AllocateZeroPool(sizeof (SDHOST_DATA)); + if (SDHostData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + SDHostData->Signature = SDHOST_DATA_SIGNATURE; + SDHostData->PciIo = PciIo; + + CopyMem (&SDHostData->SDHostIo, &mSDHostIo, sizeof (EFI_SD_HOST_IO_PROTOCOL)); + + ResetSDHost (&SDHostData->SDHostIo, Reset_All); + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint16, + 0, + (UINT64)MMIO_CTRLRVER, + 1, + &Data + ); + SDHostData->SDHostIo.HostCapability.HostVersion = Data & 0xFF; + DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: HostVersion 0x%x \r\n", SDHostData->SDHostIo.HostCapability.HostVersion)); + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + (UINT64)MMIO_CAP, + 1, + &Data + ); + DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: MMIO_CAP 0x%x \r\n", Data)); + if ((Data & BIT18) != 0) { + SDHostData->SDHostIo.HostCapability.BusWidth8 = TRUE; + } + + if ((Data & BIT21) != 0) { + SDHostData->SDHostIo.HostCapability.HighSpeedSupport = TRUE; + } + + if ((Data & BIT24) != 0) { + SDHostData->SDHostIo.HostCapability.V33Support = TRUE; + } + + if ((Data & BIT25) != 0) { + SDHostData->SDHostIo.HostCapability.V30Support = TRUE; + } + + if ((Data & BIT26) != 0) { + SDHostData->SDHostIo.HostCapability.V18Support = TRUE; + } + + SDHostData->SDHostIo.HostCapability.BusWidth4 = TRUE; + + if(SDHostData->SDHostIo.HostCapability.HostVersion < SDHCI_SPEC_300) { + + + + SDHostData->BaseClockInMHz = (Data >> 8) & 0x3F; + } + else { + SDHostData->BaseClockInMHz = (Data >> 8) & 0xFF; + + } + + SDHostData->BlockLength = 512 << ((Data >> 16) & 0x03); + DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: BlockLength 0x%x \r\n", SDHostData->BlockLength)); + SDHostData->IsAutoStopCmd = TRUE; + + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiSDHostIoProtocolGuid, + EFI_NATIVE_INTERFACE, + &SDHostData->SDHostIo + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Install the component name protocol + // + SDHostData->ControllerNameTable = NULL; + + AddUnicodeString2 ( + "eng", + gSDControllerName.SupportedLanguages, + &SDHostData->ControllerNameTable, + L"SD Host Controller", + TRUE + ); + AddUnicodeString2 ( + "en", + gSDControllerName2.SupportedLanguages, + &SDHostData->ControllerNameTable, + L"SD Host Controller", + FALSE + ); + +Exit: + if (EFI_ERROR (Status)) { + if (SDHostData != NULL) { + FreePool (SDHostData); + } + } + + return Status; +} + + +/** + Stop this driver on ControllerHandle. Support stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +SDControllerStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + SDHOST_DATA *SDHostData; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiSDHostIoProtocolGuid, + (VOID **) &SDHostIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + // + // Test whether the Controller handler passed in is a valid + // Usb controller handle that should be supported, if not, + // return the error status directly + // + if (EFI_ERROR (Status)) { + return Status; + } + + SetHostVoltage (SDHostIo, 0); + + SDHostData = SDHOST_DATA_FROM_THIS(SDHostIo); + + // + // Uninstall Block I/O protocol from the device handle + // + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiSDHostIoProtocolGuid, + SDHostIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FreeUnicodeStringTable (SDHostData->ControllerNameTable); + + FreePool (SDHostData); + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; +} + + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h new file mode 100644 index 0000000000..025c80c263 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.h @@ -0,0 +1,316 @@ +/** @file + +The definition for SD host controller driver model and HC protocol routines. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SD_CONTROLLER_H_ +#define _SD_CONTROLLER_H_ + + +#include + + +#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 stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +SDControllerStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +/** + The main function used to send the command to the card inserted into the SD host slot. + It will assemble the arguments to set the command register and wait for the command + and transfer completed until timeout. Then it will read the response register to fill + the ResponseData. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param CommandIndex The command index to set the command index field of command register. + @param Argument Command argument to set the argument field of command register. + @param DataType TRANSFER_TYPE, indicates no data, data in or data out. + @param Buffer Contains the data read from / write to the device. + @param BufferSize The size of the buffer. + @param ResponseType RESPONSE_TYPE. + @param TimeOut Time out value in 1 ms unit. + @param ResponseData Depending on the ResponseType, such as CSD or card status. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_OUT_OF_RESOURCES + @retval EFI_TIMEOUT + @retval EFI_DEVICE_ERROR + +**/ +EFI_STATUS +EFIAPI +SendCommand ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT16 CommandIndex, + IN UINT32 Argument, + IN TRANSFER_TYPE DataType, + IN UINT8 *Buffer, OPTIONAL + IN UINT32 BufferSize, + IN RESPONSE_TYPE ResponseType, + IN UINT32 TimeOut, + OUT UINT32 *ResponseData OPTIONAL + ); + +/** + Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency. + It depends on the max frequency the host can support, divider, and host speed mode. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param MaxFrequency Max frequency in HZ. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ +EFI_STATUS +EFIAPI +SetClockFrequency ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 MaxFrequencyInKHz + ); + +/** + Set bus width of the host controller + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param BusWidth Bus width in 1, 4, 8 bits. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + +**/ +EFI_STATUS +EFIAPI +SetBusWidth ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 BusWidth + ); + + +/** + Set voltage which could supported by the host controller. + Support 0(Power off the host), 1.8V, 3.0V, 3.3V + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Voltage Units in 0.1 V. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + +**/ +EFI_STATUS +EFIAPI +SetHostVoltage ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 Voltage + ); + + +/** + Reset the host controller. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param ResetAll TRUE to reset all. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ +EFI_STATUS +EFIAPI +ResetSDHost ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN RESET_TYPE ResetType + ); + + +/** + Enable auto stop on the host controller. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Enable TRUE to enable, FALSE to disable. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ +EFI_STATUS +EFIAPI +EnableAutoStopCmd ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ); + +/** + Find whether these is a card inserted into the slot. If so init the host. + If not, return EFI_NOT_FOUND. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + +**/ +EFI_STATUS +EFIAPI +DetectCardAndInitHost ( + IN EFI_SD_HOST_IO_PROTOCOL *This + ); + +/** + Set the Block length on the host controller. + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param BlockLength card supportes block length. + + @retval EFI_SUCCESS + @retval EFI_TIMEOUT + +**/ +EFI_STATUS +EFIAPI +SetBlockLength ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN UINT32 BlockLength + ); + +/** + Enable/Disable High Speed transfer mode + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param Enable TRUE to Enable, FALSE to Disable + + @return EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +SetHighSpeedMode ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ); + +EFI_STATUS +EFIAPI +SetDDRMode ( + IN EFI_SD_HOST_IO_PROTOCOL *This, + IN BOOLEAN Enable + ); +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf new file mode 100644 index 0000000000..c5fb51d006 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf @@ -0,0 +1,56 @@ +## @file +# +# Component Description File For SDControllerDxe Module. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SDController + FILE_GUID = 90A330BD-6F89-4900-933A-C25EB4356348 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeSDController + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# DRIVER_BINDING = gSDControllerDriverBinding +# COMPONENT_NAME = gSDControllerName +# COMPONENT_NAME2 = gSDControllerName2 +# + +[Sources] + SDController.c + SDController.h + ComponentName.c + ComponentName.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + DebugLib + PcdLib + +[Protocols] + gEfiPciIoProtocolGuid ## TO_START + gEfiSDHostIoProtocolGuid ## BY_START + +[FeaturePcd] + gEfiQuarkSCSocIdTokenSpaceGuid.PcdSdHciQuirkNoHiSpd + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c new file mode 100644 index 0000000000..41a3065b5c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATA.c @@ -0,0 +1,647 @@ +/** @file + +CEATA specific functions implementation + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SDMediaDevice.h" + +/** + Send RW_MULTIPLE_REGISTER command + + @param CardData Pointer to CARD_DATA. + @param Address Register address. + @param ByteCount Buffer size. + @param Write TRUE means write, FALSE means read. + @param Buffer Buffer pointer. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +ReadWriteMultipleRegister ( + IN CARD_DATA *CardData, + IN UINT16 Address, + IN UINT8 ByteCount, + IN BOOLEAN Write, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINT32 Argument; + + Status = EFI_SUCCESS; + + if ((Address % 4 != 0) || (ByteCount % 4 != 0)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Argument = (Address << 16) | ByteCount; + if (Write) { + Argument |= BIT31; + } + + + if (Write) { + CopyMem (CardData->AlignedBuffer, Buffer, ByteCount); + + Status = SendCommand ( + CardData, + RW_MULTIPLE_REGISTER, + Argument, + OutData, + CardData->AlignedBuffer, + ByteCount, + ResponseR1b, + TIMEOUT_DATA, + (UINT32*)&(CardData->CardStatus) + ); + } else { + Status = SendCommand ( + CardData, + RW_MULTIPLE_REGISTER, + Argument, + InData, + CardData->AlignedBuffer, + ByteCount, + ResponseR1, + TIMEOUT_DATA, + (UINT32*)&(CardData->CardStatus) + ); + if (!EFI_ERROR (Status)) { + CopyMem (Buffer, CardData->AlignedBuffer, ByteCount); + } + + } +Exit: + return Status; +} + +/** + Send ReadWriteMultipleBlock command with RW_MULTIPLE_REGISTER command + + @param CardData Pointer to CARD_DATA. + @param DataUnitCount Buffer size in 512 bytes unit. + @param Write TRUE means write, FALSE means read. + @param Buffer Buffer pointer. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +ReadWriteMultipleBlock ( + IN CARD_DATA *CardData, + IN UINT16 DataUnitCount, + IN BOOLEAN Write, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + UINT32 TransferLength; + + Status = EFI_SUCCESS; + SDHostIo = CardData->SDHostIo; + + TransferLength = DataUnitCount * DATA_UNIT_SIZE; + if (TransferLength > SDHostIo->HostCapability.BoundarySize) { + return EFI_INVALID_PARAMETER; + } + + if (Write) { + CopyMem (CardData->AlignedBuffer, Buffer, TransferLength); + + Status = SendCommand ( + CardData, + RW_MULTIPLE_BLOCK, + (DataUnitCount | BIT31), + OutData, + CardData->AlignedBuffer, + TransferLength, + ResponseR1b, + TIMEOUT_DATA, + (UINT32*)&(CardData->CardStatus) + ); + } else { + Status = SendCommand ( + CardData, + RW_MULTIPLE_BLOCK, + DataUnitCount, + InData, + CardData->AlignedBuffer, + TransferLength, + ResponseR1, + TIMEOUT_DATA, + (UINT32*)&(CardData->CardStatus) + ); + if (!EFI_ERROR (Status)) { + CopyMem (Buffer, CardData->AlignedBuffer, TransferLength); + } + } + + return Status; +} + +/** + Send software reset + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +SoftwareReset ( + IN CARD_DATA *CardData + ) +{ + EFI_STATUS Status; + UINT8 Data; + UINT32 TimeOut; + + Data = BIT2; + + Status = FastIO (CardData, Reg_Control, &Data, TRUE); + if (EFI_ERROR (Status)) { + goto Exit; + } + + TimeOut = 5 * 1000; + + do { + gBS->Stall (1 * 1000); + Status = FastIO (CardData, Reg_Control, &Data, FALSE); + if (EFI_ERROR (Status)) { + goto Exit; + } + if ((Data & BIT2) == BIT2) { + break; + } + + TimeOut--; + } while (TimeOut > 0); + + if (TimeOut == 0) { + Status = EFI_TIMEOUT; + goto Exit; + } + + Data &= ~BIT2; + Status = FastIO (CardData, Reg_Control, &Data, TRUE); + + TimeOut = 5 * 1000; + + do { + gBS->Stall (1 * 1000); + Status = FastIO (CardData, Reg_Control, &Data, FALSE); + if (EFI_ERROR (Status)) { + goto Exit; + } + if ((Data & BIT2) != BIT2) { + break; + } + + TimeOut--; + } while (TimeOut > 0); + + + if (TimeOut == 0) { + Status = EFI_TIMEOUT; + goto Exit; + } + + +Exit: + return Status; +} + + +/** + SendATACommand specificed in Taskfile + + @param CardData Pointer to CARD_DATA. + @param TaskFile Pointer to TASK_FILE. + @param Write TRUE means write, FALSE means read. + @param Buffer If NULL, means no data transfer, neither read nor write. + @param SectorCount Buffer size in 512 bytes unit. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +SendATACommand ( + IN CARD_DATA *CardData, + IN TASK_FILE *TaskFile, + IN BOOLEAN Write, + IN UINT8 *Buffer, + IN UINT16 SectorCount + ) +{ + EFI_STATUS Status; + UINT8 Data; + UINT32 TimeOut; + + // + //Write register + // + Status = ReadWriteMultipleRegister ( + CardData, + 0, + sizeof (TASK_FILE), + TRUE, + (UINT8*)TaskFile + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister 0x%x\n", Status)); + goto Exit; + } + + TimeOut = 5000; + do { + gBS->Stall (1 * 1000); + Data = 0; + Status = FastIO ( + CardData, + Reg_Command_Status, + &Data, + FALSE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (((Data & BIT7) == 0) && ((Data & BIT6) == BIT6)) { + break; + } + + TimeOut --; + } while (TimeOut > 0); + + if (TimeOut == 0) { + DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister FastIO EFI_TIMEOUT 0x%x\n", Data)); + Status = EFI_TIMEOUT; + goto Exit; + } + + + if (Buffer != NULL) { + Status = ReadWriteMultipleBlock ( + CardData, + SectorCount, + Write, + (UINT8*)Buffer + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock EFI_TIMEOUT 0x%x\n", Status)); + goto Exit; + } + + TimeOut = 5 * 1000; + do { + gBS->Stall (1 * 1000); + + Data = 0; + Status = FastIO ( + CardData, + Reg_Command_Status, + &Data, + FALSE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (((Data & BIT7) == 0) && ((Data & BIT3) == 0)) { + break; + } + + TimeOut --; + } while (TimeOut > 0); + if (TimeOut == 0) { + DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock FastIO EFI_TIMEOUT 0x%x\n", Data)); + Status = EFI_TIMEOUT; + goto Exit; + } + + + if (((Data & BIT6) == BIT6) && (Data & BIT0) == 0) { + Status = EFI_SUCCESS; + } else { + Status = EFI_DEVICE_ERROR; + } + } + +Exit: + if (EFI_ERROR (Status)) { + SoftwareReset (CardData); + } + + return Status; +} + +/** + IDENTIFY_DEVICE command + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +IndentifyDevice ( + IN CARD_DATA *CardData + ) +{ + EFI_STATUS Status; + + ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE)); + + // + //The host only supports nIEN = 0 + // + CardData->TaskFile.Command_Status = IDENTIFY_DEVICE; + + + Status = SendATACommand ( + CardData, + &CardData->TaskFile, + FALSE, + (UINT8*)&(CardData->IndentifyDeviceData), + 1 + ); + + + return Status; +} + +/** + FLUSH_CACHE_EXT command + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +FlushCache ( + IN CARD_DATA *CardData + ) +{ + + // + //Hitachi CE-ATA will always make the busy high after + //receving this command + // +/* + EFI_STATUS Status; + ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE)); + // + //The host only supports nIEN = 0 + // + CardData->TaskFile.Command_Status = FLUSH_CACHE_EXT; + + Status = SendATACommand ( + CardData, + &CardData->TaskFile, + FALSE, + NULL, + 0 + ); +*/ + return EFI_SUCCESS; +} + +/** + STANDBY_IMMEDIATE command + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +StandByImmediate ( + IN CARD_DATA *CardData + ) +{ + EFI_STATUS Status; + + ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE)); + // + //The host only supports nIEN = 0 + // + CardData->TaskFile.Command_Status = STANDBY_IMMEDIATE; + + + Status = SendATACommand ( + CardData, + &CardData->TaskFile, + FALSE, + NULL, + 0 + ); + return Status; +} + +/** + READ_DMA_EXT command + + @param CardData Pointer to CARD_DATA. + @param LBA The starting logical block address to read from on the device. + @param Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + @param SectorCount Size in 512 bytes unit. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +ReadDMAExt ( + IN CARD_DATA *CardData, + IN EFI_LBA LBA, + IN UINT8 *Buffer, + IN UINT16 SectorCount + ) +{ + + EFI_STATUS Status; + + ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE)); + // + //The host only supports nIEN = 0 + // + CardData->TaskFile.Command_Status = READ_DMA_EXT; + + CardData->TaskFile.SectorCount = (UINT8)SectorCount; + CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8); + + CardData->TaskFile.LBALow = (UINT8)LBA; + CardData->TaskFile.LBAMid = (UINT8)RShiftU64(LBA, 8); + CardData->TaskFile.LBAHigh = (UINT8)RShiftU64(LBA, 16); + + CardData->TaskFile.LBALow_Exp = (UINT8)RShiftU64(LBA, 24); + CardData->TaskFile.LBAMid_Exp = (UINT8)RShiftU64(LBA, 32); + CardData->TaskFile.LBAHigh_Exp = (UINT8)RShiftU64(LBA, 40); + + Status = SendATACommand ( + CardData, + &CardData->TaskFile, + FALSE, + Buffer, + SectorCount + ); + return Status; + +} + +/** + WRITE_DMA_EXT command + + @param CardData Pointer to CARD_DATA. + @param LBA The starting logical block address to read from on the device. + @param Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + @param SectorCount Size in 512 bytes unit. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +WriteDMAExt ( + IN CARD_DATA *CardData, + IN EFI_LBA LBA, + IN UINT8 *Buffer, + IN UINT16 SectorCount + ) +{ + + EFI_STATUS Status; + + ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE)); + // + //The host only supports nIEN = 0 + // + CardData->TaskFile.Command_Status = WRITE_DMA_EXT; + + CardData->TaskFile.SectorCount = (UINT8)SectorCount; + CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8); + + CardData->TaskFile.LBALow = (UINT8)LBA; + CardData->TaskFile.LBAMid = (UINT8)RShiftU64(LBA, 8); + CardData->TaskFile.LBAHigh = (UINT8)RShiftU64(LBA, 16); + + CardData->TaskFile.LBALow_Exp = (UINT8)RShiftU64(LBA, 24); + CardData->TaskFile.LBAMid_Exp = (UINT8)RShiftU64(LBA, 32); + CardData->TaskFile.LBAHigh_Exp = (UINT8)RShiftU64(LBA, 40); + + Status = SendATACommand ( + CardData, + &CardData->TaskFile, + TRUE, + Buffer, + SectorCount + ); + return Status; + +} + + +/** + Judge whether it is CE-ATA device or not. + + @param CardData Pointer to CARD_DATA. + + @retval TRUE + @retval FALSE + +**/ +BOOLEAN +IsCEATADevice ( + IN CARD_DATA *CardData + ) +{ + EFI_STATUS Status; + + Status = ReadWriteMultipleRegister ( + CardData, + 0, + sizeof (TASK_FILE), + FALSE, + (UINT8*)&CardData->TaskFile + ); + if (EFI_ERROR (Status)) { + // + //To bring back the normal MMC card to work + // + CardData->SDHostIo->ResetSDHost (CardData->SDHostIo, Reset_DAT_CMD); + return FALSE; + } + + if (CardData->TaskFile.LBAMid == CE_ATA_SIG_CE && + CardData->TaskFile.LBAHigh == CE_ATA_SIG_AA + ) { + // + //Disable Auto CMD for CE-ATA + // + CardData->SDHostIo->EnableAutoStopCmd (CardData->SDHostIo, FALSE); + + return TRUE; + } + + return FALSE; +} + + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c new file mode 100644 index 0000000000..eb48baa75c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/CEATABlockIo.c @@ -0,0 +1,389 @@ +/** @file + +Block I/O protocol for CE-ATA device + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SDMediaDevice.h" + +/** + Implements EFI_BLOCK_IO_PROTOCOL.Reset() function. + + @param This The EFI_BLOCK_IO_PROTOCOL instance. + @param ExtendedVerification Indicates that the driver may perform a more exhaustive. + verification operation of the device during reset. + (This parameter is ingored in this driver.) + + @retval EFI_SUCCESS Success +**/ +EFI_STATUS +EFIAPI +CEATABlockReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + CARD_DATA *CardData; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + + CardData = CARD_DATA_FROM_THIS(This); + SDHostIo = CardData->SDHostIo; + + if (!ExtendedVerification) { + Status = SoftwareReset (CardData); + } else { + Status = SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" )); + return Status; + } + Status = MMCSDCardInit (CardData); + } + + + return Status; + + } + +/** + Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function. + + @param This The EFI_BLOCK_IO_PROTOCOL instance. + @param MediaId The media id that the write request is for. + @param LBA The starting logical block address to read from on the device. + The caller is responsible for writing to only legitimate locations. + @param BufferSize The size of the Buffer in bytes. This must be a multiple of the + intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad +**/ +EFI_STATUS +EFIAPI +CEATABlockReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + CARD_DATA *CardData; + UINT32 TransferSize; + UINT8 *pBuf; + UINT32 Index; + UINT64 Address; + UINT32 Remainder; + UINT64 CEATALBA; + UINT32 BoundarySize; + + Status = EFI_SUCCESS; + CardData = CARD_DATA_FROM_THIS(This); + pBuf = Buffer; + Index = 0; + Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize); + BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize; + + if (!Buffer) { + Status = EFI_INVALID_PARAMETER; + DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" )); + goto Exit; + } + + if (MediaId != CardData->BlockIoMedia.MediaId) { + Status = EFI_MEDIA_CHANGED; + DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" )); + goto Exit; + } + + if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) { + Status = EFI_BAD_BUFFER_SIZE; + DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" )); + goto Exit; + } + + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto Exit; + } + + if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) { + Status = EFI_INVALID_PARAMETER; + DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" )); + goto Exit; + } + + + do { + if (BufferSize < BoundarySize) { + TransferSize = (UINT32)BufferSize; + } else { + TransferSize = BoundarySize; + } + + Address += Index * TransferSize; + CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder); + ASSERT(Remainder == 0); + + Status = ReadDMAExt ( + CardData, + CEATALBA, + pBuf, + (UINT16)(TransferSize / DATA_UNIT_SIZE) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize)); + This->Reset (This, TRUE); + goto Exit; + } + BufferSize -= TransferSize; + pBuf += TransferSize; + Index ++; + } while (BufferSize != 0); + + +Exit: + return Status; +} + +/** + Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function. + + @param This The EFI_BLOCK_IO_PROTOCOL instance. + @param MediaId The media id that the write request is for. + @param LBA The starting logical block address to read from on the device. + The caller is responsible for writing to only legitimate locations. + @param BufferSize The size of the Buffer in bytes. This must be a multiple of the + intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad +**/ +EFI_STATUS +EFIAPI +CEATABlockWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + CARD_DATA *CardData; + UINT32 TransferSize; + UINT8 *pBuf; + UINT32 Index; + UINT64 Address; + UINT32 Remainder; + UINT64 CEATALBA; + UINT32 BoundarySize; + + + Status = EFI_SUCCESS; + CardData = CARD_DATA_FROM_THIS(This); + pBuf = Buffer; + Index = 0; + Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize); + BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize; + + + if (!Buffer) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + if (MediaId != CardData->BlockIoMedia.MediaId) { + Status = EFI_MEDIA_CHANGED; + goto Exit; + } + + if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) { + Status = EFI_BAD_BUFFER_SIZE; + goto Exit; + } + + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto Exit; + } + + if (CardData->BlockIoMedia.ReadOnly) { + Status = EFI_WRITE_PROTECTED; + goto Exit; + } + + if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + CardData->NeedFlush = TRUE; + + do { + if (BufferSize < BoundarySize) { + TransferSize = (UINT32)BufferSize; + } else { + TransferSize = BoundarySize; + } + + Address += Index * TransferSize; + CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder); + ASSERT(Remainder == 0); + + Status = WriteDMAExt ( + CardData, + CEATALBA, + pBuf, + (UINT16)(TransferSize / DATA_UNIT_SIZE) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize)); + This->Reset (This, TRUE); + goto Exit; + } + BufferSize -= TransferSize; + pBuf += TransferSize; + Index ++; + } while (BufferSize != 0); + + +Exit: + return Status; +} + +/** + Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function. + (In this driver, this function just returns EFI_SUCCESS.) + + @param This The EFI_BLOCK_IO_PROTOCOL instance. + + @retval EFI_SUCCESS + @retval Others +**/ +EFI_STATUS +EFIAPI +CEATABlockFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + + CARD_DATA *CardData; + + CardData = CARD_DATA_FROM_THIS(This); + + if (CardData->NeedFlush) { + CardData->NeedFlush = FALSE; + FlushCache (CardData); + } + + return EFI_SUCCESS; +} + + +/** + CEATA card BlockIo init function. + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS + @retval Others +**/ +EFI_STATUS +CEATABlockIoInit ( + IN CARD_DATA *CardData + ) +/*++ + + Routine Description: + CEATA card BlockIo init function + + Arguments: + CardData - Pointer to CARD_DATA + + Returns: + EFI_SUCCESS - Success +--*/ +{ + EFI_STATUS Status; + UINT64 MaxSize; + UINT32 Remainder; + // + //BlockIO protocol + // + CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; + CardData->BlockIo.Media = &(CardData->BlockIoMedia); + CardData->BlockIo.Reset = CEATABlockReset; + CardData->BlockIo.ReadBlocks = CEATABlockReadBlocks ; + CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks; + CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks; + + CardData->BlockIoMedia.MediaId = 0; + CardData->BlockIoMedia.RemovableMedia = FALSE; + CardData->BlockIoMedia.MediaPresent = TRUE; + CardData->BlockIoMedia.LogicalPartition = FALSE; + + if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) { + CardData->BlockIoMedia.ReadOnly = TRUE; + } else { + CardData->BlockIoMedia.ReadOnly = FALSE; + } + + + CardData->BlockIoMedia.WriteCaching = FALSE; + CardData->BlockIoMedia.IoAlign = 1; + + Status = IndentifyDevice (CardData); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + //Some device does not support this feature + // + + if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) { + CardData->BlockIoMedia.ReadOnly = TRUE; + } + + CardData->BlockIoMedia.BlockSize = (1 << CardData->IndentifyDeviceData.Sectorsize); + ASSERT(CardData->BlockIoMedia.BlockSize >= 12); + + + MaxSize = *(UINT64*)(CardData->IndentifyDeviceData.MaximumLBA); + MaxSize = MultU64x32 (MaxSize, 512); + + Remainder = 0; + CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder); + ASSERT(Remainder == 0); + + CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1); + + +Exit: + return Status; + +} + + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c new file mode 100644 index 0000000000..0f95968406 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.c @@ -0,0 +1,215 @@ +/** @file + +UEFI Component Name(2) protocol implementation for SD media device driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SDMediaDevice.h" + + +// +// EFI Component Name Protocol +// + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSDMediaDeviceName = { + SDMediaDeviceGetDriverName, + SDMediaDeviceGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSDMediaDeviceName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SDMediaDeviceGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SDMediaDeviceGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSDMediaDeviceDriverNameTable[] = { + { "eng;en", L"UEFI MMC/SD Media Device Driver" }, + { NULL, NULL } +}; + + +// +// EFI Component Name Functions +// + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 3066 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SDMediaDeviceGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSDMediaDeviceDriverNameTable, + DriverName, + (BOOLEAN)(This == &gSDMediaDeviceName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 3066 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SDMediaDeviceGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + CARD_DATA *CardData; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + gSDMediaDeviceDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + CardData = CARD_DATA_FROM_THIS (BlockIo); + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + CardData->ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gSDMediaDeviceName) + ); + +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h new file mode 100644 index 0000000000..69eb4d7a73 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/ComponentName.h @@ -0,0 +1,139 @@ +/** @file + +This file contains the delarations for componet name routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _COMPONENT_NAME_H_ +#define _COMPONENT_NAME_H_ + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 3066 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SDMediaDeviceGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 3066 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SDMediaDeviceGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c new file mode 100644 index 0000000000..da6202983b --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDBlockIo.c @@ -0,0 +1,538 @@ +/** @file + +Block I/O protocol for MMC/SD device + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SDMediaDevice.h" + +/** + Implements EFI_BLOCK_IO_PROTOCOL.Reset() function. + + @param This The EFI_BLOCK_IO_PROTOCOL instance. + @param ExtendedVerification Indicates that the driver may perform a more exhaustive. + verification operation of the device during reset. + (This parameter is ingored in this driver.) + + @retval EFI_SUCCESS Success +**/ +EFI_STATUS +EFIAPI +MMCSDBlockReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + CARD_DATA *CardData; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + + CardData = CARD_DATA_FROM_THIS(This); + SDHostIo = CardData->SDHostIo; + + return SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD); + } + +/** + Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function. + + @param This The EFI_BLOCK_IO_PROTOCOL instance. + @param MediaId The media id that the write request is for. + @param LBA The starting logical block address to read from on the device. + The caller is responsible for writing to only legitimate locations. + @param BufferSize The size of the Buffer in bytes. This must be a multiple of the + intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad +**/ +EFI_STATUS +EFIAPI +MMCSDBlockReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT32 Address; + CARD_DATA *CardData; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + UINT32 RemainingLength; + UINT32 TransferLength; + UINT8 *BufferPointer; + BOOLEAN SectorAddressing; + UINTN TotalBlock; + + DEBUG((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize)); + Status = EFI_SUCCESS; + CardData = CARD_DATA_FROM_THIS(This); + SDHostIo = CardData->SDHostIo; + if (MediaId != CardData->BlockIoMedia.MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (ModU64x32 (BufferSize,CardData->BlockIoMedia.BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) { + SectorAddressing = TRUE; + } else { + SectorAddressing = FALSE; + } + if (SectorAddressing) { + // + //Block Address + // + Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512); + } else { + // + //Byte Address + // + Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize); + } + TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize); + if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) { + return EFI_INVALID_PARAMETER; + } + + + if (!Buffer) { + Status = EFI_INVALID_PARAMETER; + DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n")); + goto Done; + } + + if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) { + Status = EFI_BAD_BUFFER_SIZE; + DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n")); + goto Done; + } + + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + + + + BufferPointer = Buffer; + RemainingLength = (UINT32)BufferSize; + + while (RemainingLength > 0) { + if ((BufferSize > CardData->BlockIoMedia.BlockSize)) { + if (RemainingLength > SDHostIo->HostCapability.BoundarySize) { + TransferLength = SDHostIo->HostCapability.BoundarySize; + } else { + TransferLength = RemainingLength; + } + + if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) { + if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) { + Status = SendCommand ( + CardData, + SET_BLOCKLEN, + CardData->BlockIoMedia.BlockSize, + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + break; + } + } + Status = SendCommand ( + CardData, + SET_BLOCK_COUNT, + TransferLength / CardData->BlockIoMedia.BlockSize, + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + break; + } + } + Status = SendCommand ( + CardData, + READ_MULTIPLE_BLOCK, + Address, + InData, + CardData->AlignedBuffer, + TransferLength, + ResponseR1, + TIMEOUT_DATA, + (UINT32*)&(CardData->CardStatus) + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n")); + break; + } + } else { + if (RemainingLength > CardData->BlockIoMedia.BlockSize) { + TransferLength = CardData->BlockIoMedia.BlockSize; + } else { + TransferLength = RemainingLength; + } + + Status = SendCommand ( + CardData, + READ_SINGLE_BLOCK, + Address, + InData, + CardData->AlignedBuffer, + (UINT32)TransferLength, + ResponseR1, + TIMEOUT_DATA, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n")); + break; + } + } + CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength); + + if (SectorAddressing) { + // + //Block Address + // + Address += TransferLength / 512; + } else { + // + //Byte Address + // + Address += TransferLength; + } + BufferPointer += TransferLength; + RemainingLength -= TransferLength; + } + + + if (EFI_ERROR (Status)) { + if ((CardData->CardType == SDMemoryCard) || + (CardData->CardType == SDMemoryCard2)|| + (CardData->CardType == SDMemoryCard2High)) { + SendCommand ( + CardData, + STOP_TRANSMISSION, + 0, + NoData, + NULL, + 0, + ResponseR1b, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + } else { + SendCommand ( + CardData, + STOP_TRANSMISSION, + 0, + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + } + + } + + +Done: + DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status)); + return Status; +} + +/** + Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function. + + @param This The EFI_BLOCK_IO_PROTOCOL instance. + @param MediaId The media id that the write request is for. + @param LBA The starting logical block address to read from on the device. + The caller is responsible for writing to only legitimate locations. + @param BufferSize The size of the Buffer in bytes. This must be a multiple of the + intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad +**/ +EFI_STATUS +EFIAPI +MMCSDBlockWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT32 Address; + CARD_DATA *CardData; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + UINT32 RemainingLength; + UINT32 TransferLength; + UINT8 *BufferPointer; + BOOLEAN SectorAddressing; + + DEBUG((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize)); + Status = EFI_SUCCESS; + CardData = CARD_DATA_FROM_THIS(This); + SDHostIo = CardData->SDHostIo; + if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) { + SectorAddressing = TRUE; + } else { + SectorAddressing = FALSE; + } + if (SectorAddressing) { + // + //Block Address + // + Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512); + } else { + // + //Byte Address + // + Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize); + } + + if (!Buffer) { + Status = EFI_INVALID_PARAMETER; + DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n")); + goto Done; + } + + if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) { + Status = EFI_BAD_BUFFER_SIZE; + DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n")); + goto Done; + } + + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + if (This->Media->ReadOnly == TRUE) { + Status = EFI_WRITE_PROTECTED; + DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n")); + goto Done; + } + + + + BufferPointer = Buffer; + RemainingLength = (UINT32)BufferSize; + + while (RemainingLength > 0) { + if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) { + if (RemainingLength > SDHostIo->HostCapability.BoundarySize) { + TransferLength = SDHostIo->HostCapability.BoundarySize; + } else { + TransferLength = RemainingLength; + } + + if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) { + + if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) { + Status = SendCommand ( + CardData, + SET_BLOCKLEN, + CardData->BlockIoMedia.BlockSize, + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + break; + } + } + Status = SendCommand ( + CardData, + SET_BLOCK_COUNT, + TransferLength / CardData->BlockIoMedia.BlockSize, + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + break; + } + } + + CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength); + + Status = SendCommand ( + CardData, + WRITE_MULTIPLE_BLOCK, + Address, + OutData, + CardData->AlignedBuffer, + (UINT32)TransferLength, + ResponseR1, + TIMEOUT_DATA, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n")); + break; + } + } else { + if (RemainingLength > CardData->BlockIoMedia.BlockSize) { + TransferLength = CardData->BlockIoMedia.BlockSize; + } else { + TransferLength = RemainingLength; + } + + CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength); + + Status = SendCommand ( + CardData, + WRITE_BLOCK, + Address, + OutData, + CardData->AlignedBuffer, + (UINT32)TransferLength, + ResponseR1, + TIMEOUT_DATA, + (UINT32*)&(CardData->CardStatus) + ); + } + if (SectorAddressing) { + // + //Block Address + // + Address += TransferLength / 512; + } else { + // + //Byte Address + // + Address += TransferLength; + } + BufferPointer += TransferLength; + RemainingLength -= TransferLength; + + } + + if (EFI_ERROR (Status)) { + SendCommand ( + CardData, + STOP_TRANSMISSION, + 0, + NoData, + NULL, + 0, + ResponseR1b, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + + } + + +Done: + return EFI_SUCCESS; +} + +/** + Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function. + (In this driver, this function just returns EFI_SUCCESS.) + + @param This The EFI_BLOCK_IO_PROTOCOL instance. + + @retval EFI_SUCCESS + @retval Others +**/ +EFI_STATUS +EFIAPI +MMCSDBlockFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + + +/** + MMC/SD card BlockIo init function. + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS + @retval Others +**/ +EFI_STATUS +MMCSDBlockIoInit ( + IN CARD_DATA *CardData + ) +{ + // + //BlockIO protocol + // + CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; + CardData->BlockIo.Media = &(CardData->BlockIoMedia); + CardData->BlockIo.Reset = MMCSDBlockReset; + CardData->BlockIo.ReadBlocks = MMCSDBlockReadBlocks ; + CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks; + CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks; + + CardData->BlockIoMedia.MediaId = 0; + CardData->BlockIoMedia.RemovableMedia = FALSE; + CardData->BlockIoMedia.MediaPresent = TRUE; + CardData->BlockIoMedia.LogicalPartition = FALSE; + + if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) { + CardData->BlockIoMedia.ReadOnly = TRUE; + } else { + CardData->BlockIoMedia.ReadOnly = FALSE; + } + + + CardData->BlockIoMedia.WriteCaching = FALSE; + CardData->BlockIoMedia.BlockSize = CardData->BlockLen; + CardData->BlockIoMedia.IoAlign = 1; + CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1); + + + return EFI_SUCCESS; + +} + + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c new file mode 100644 index 0000000000..65b71a008c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/MMCSDTransfer.c @@ -0,0 +1,1708 @@ +/** @file + +MMC/SD transfer specific functions + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SDMediaDevice.h" + +/** + Check card status, print the debug info and check the error + + @param Status Status got from card status register. + + @retval EFI_SUCCESS + @retval EFI_DEVICE_ERROR + +**/ +EFI_STATUS +CheckCardStatus ( + IN UINT32 Status + ) +{ + CARD_STATUS *CardStatus; + CardStatus = (CARD_STATUS*)(&Status); + + if (CardStatus->ADDRESS_OUT_OF_RANGE) { + DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n")); + } + + if (CardStatus->ADDRESS_MISALIGN) { + DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n")); + } + + if (CardStatus->BLOCK_LEN_ERROR) { + DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n")); + } + + if (CardStatus->ERASE_SEQ_ERROR) { + DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n")); + } + + if (CardStatus->ERASE_PARAM) { + DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n")); + } + + if (CardStatus->WP_VIOLATION) { + DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n")); + } + + if (CardStatus->CARD_IS_LOCKED) { + DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n")); + } + + if (CardStatus->LOCK_UNLOCK_FAILED) { + DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n")); + } + + if (CardStatus->COM_CRC_ERROR) { + DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n")); + } + + if (CardStatus->ILLEGAL_COMMAND) { + DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n")); + } + + if (CardStatus->CARD_ECC_FAILED) { + DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n")); + } + + if (CardStatus->CC_ERROR) { + DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n")); + } + + if (CardStatus->ERROR) { + DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n")); + } + + if (CardStatus->UNDERRUN) { + DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n")); + } + + if (CardStatus->OVERRUN) { + DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n")); + } + + if (CardStatus->CID_CSD_OVERWRITE) { + DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n")); + } + + if (CardStatus->WP_ERASE_SKIP) { + DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n")); + } + + if (CardStatus->ERASE_RESET) { + DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n")); + } + + if (CardStatus->SWITCH_ERROR) { + DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n")); + } + + if ((Status & 0xFCFFA080) != 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Send command by using Host IO protocol + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param CommandIndex The command index to set the command index field of command register. + @param Argument Command argument to set the argument field of command register. + @param DataType TRANSFER_TYPE, indicates no data, data in or data out. + @param Buffer Contains the data read from / write to the device. + @param BufferSize The size of the buffer. + @param ResponseType RESPONSE_TYPE. + @param TimeOut Time out value in 1 ms unit. + @param ResponseData Depending on the ResponseType, such as CSD or card status. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_UNSUPPORTED + @retval EFI_DEVICE_ERROR + +**/ +EFI_STATUS +SendCommand ( + IN CARD_DATA *CardData, + IN UINT16 CommandIndex, + IN UINT32 Argument, + IN TRANSFER_TYPE DataType, + IN UINT8 *Buffer, OPTIONAL + IN UINT32 BufferSize, + IN RESPONSE_TYPE ResponseType, + IN UINT32 TimeOut, + OUT UINT32 *ResponseData + ) +{ + + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + SDHostIo = CardData->SDHostIo; + if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) { + CommandIndex |= AUTO_CMD12_ENABLE; + } + + Status = SDHostIo->SendCommand ( + SDHostIo, + CommandIndex, + Argument, + DataType, + Buffer, + BufferSize, + ResponseType, + TimeOut, + ResponseData + ); + if (!EFI_ERROR (Status)) { + if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) { + ASSERT(ResponseData != NULL); + Status = CheckCardStatus (*ResponseData); + } + } else { + SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD); + } + + return Status; +} + +/** + Send the card APP_CMD command with the following command indicated by CommandIndex + + @param CardData Pointer to CARD_DATA. + @param CommandIndex The command index to set the command index field of command register. + @param Argument Command argument to set the argument field of command register. + @param DataType TRANSFER_TYPE, indicates no data, data in or data out. + @param Buffer Contains the data read from / write to the device. + @param BufferSize The size of the buffer. + @param ResponseType RESPONSE_TYPE. + @param TimeOut Time out value in 1 ms unit. + @param ResponseData Depending on the ResponseType, such as CSD or card status. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_UNSUPPORTED + @retval EFI_DEVICE_ERROR + +**/ +EFI_STATUS +SendAppCommand ( + IN CARD_DATA *CardData, + IN UINT16 CommandIndex, + IN UINT32 Argument, + IN TRANSFER_TYPE DataType, + IN UINT8 *Buffer, OPTIONAL + IN UINT32 BufferSize, + IN RESPONSE_TYPE ResponseType, + IN UINT32 TimeOut, + OUT UINT32 *ResponseData + ) +{ + + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + UINT8 Index; + + SDHostIo = CardData->SDHostIo; + Status = EFI_SUCCESS; + + for (Index = 0; Index < 2; Index++) { + Status = SDHostIo->SendCommand ( + SDHostIo, + APP_CMD, + (CardData->Address << 16), + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (!EFI_ERROR (Status)) { + Status = CheckCardStatus (*(UINT32*)&(CardData->CardStatus)); + if (CardData->CardStatus.SAPP_CMD != 1) { + Status = EFI_DEVICE_ERROR; + } + if (!EFI_ERROR (Status)) { + break; + } + } else { + SDHostIo->ResetSDHost (SDHostIo, Reset_Auto); + } + } + + if (EFI_ERROR (Status)) { + return Status; + } + if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) { + CommandIndex |= AUTO_CMD12_ENABLE; + } + + Status = SDHostIo->SendCommand ( + SDHostIo, + CommandIndex, + Argument, + DataType, + Buffer, + BufferSize, + ResponseType, + TimeOut, + ResponseData + ); + if (!EFI_ERROR (Status)) { + if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) { + ASSERT(ResponseData != NULL); + Status = CheckCardStatus (*ResponseData); + } + } else { + SDHostIo->ResetSDHost (SDHostIo, Reset_Auto); + } + + return Status; +} + + +/** + Send the card FAST_IO command + + @param CardData Pointer to CARD_DATA. + @param RegisterAddress Register Address. + @param RegisterData Pointer to register Data. + @param Write TRUE for write, FALSE for read. + + @retval EFI_SUCCESS + @retval EFI_UNSUPPORTED + @retval EFI_INVALID_PARAMETER + @retval EFI_DEVICE_ERROR + +**/ +EFI_STATUS +FastIO ( + IN CARD_DATA *CardData, + IN UINT8 RegisterAddress, + IN OUT UINT8 *RegisterData, + IN BOOLEAN Write + ) +{ + EFI_STATUS Status; + UINT32 Argument; + UINT32 Data; + + Status = EFI_SUCCESS; + + if (RegisterData == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Argument = (CardData->Address << 16) | (RegisterAddress << 8); + if (Write) { + Argument |= BIT15 | (*RegisterData); + } + + Status = SendCommand ( + CardData, + FAST_IO, + Argument, + NoData, + NULL, + 0, + ResponseR4, + TIMEOUT_COMMAND, + &Data + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + if ((Data & BIT15) == 0) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + if (!Write) { + *RegisterData = (UINT8)Data; + } + +Exit: + return Status; +} + +/** + Send the card GO_INACTIVE_STATE command. + + @param CardData Pointer to CARD_DATA. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +PutCardInactive ( + IN CARD_DATA *CardData + ) +{ + EFI_STATUS Status; + + + Status = SendCommand ( + CardData, + GO_INACTIVE_STATE, + (CardData->Address << 16), + NoData, + NULL, + 0, + ResponseNo, + TIMEOUT_COMMAND, + NULL + ); + + return Status; + +} + +/** + Get card interested information for CSD rergister + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS + @retval EFI_UNSUPPORTED + @retval EFI_INVALID_PARAMETER + +**/ +EFI_STATUS +CaculateCardParameter ( + IN CARD_DATA *CardData + ) +{ + EFI_STATUS Status; + UINT32 Frequency; + UINT32 Multiple; + UINT32 CSize; + CSD_SDV2 *CsdSDV2; + + Status = EFI_SUCCESS; + + switch (CardData->CSDRegister.TRAN_SPEED & 0x7) { + case 0: + Frequency = 100 * 1000; + break; + + case 1: + Frequency = 1 * 1000 * 1000; + break; + + case 2: + Frequency = 10 * 1000 * 1000; + break; + + case 3: + Frequency = 100 * 1000 * 1000; + break; + + default: + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) { + case 1: + Multiple = 10; + break; + + case 2: + Multiple = 12; + break; + + case 3: + Multiple = 13; + break; + + case 4: + Multiple = 15; + break; + + case 5: + Multiple = 20; + break; + + case 6: + if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) { + Multiple = 26; + } else { + Multiple = 25; + } + break; + + case 7: + Multiple = 30; + break; + + case 8: + Multiple = 35; + break; + + case 9: + Multiple = 40; + break; + + case 10: + Multiple = 45; + break; + + case 11: + if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) { + Multiple = 52; + } else { + Multiple = 50; + } + break; + + case 12: + Multiple = 55; + break; + + case 13: + Multiple = 60; + break; + + case 14: + Multiple = 70; + break; + + case 15: + Multiple = 80; + break; + + default: + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Frequency = Frequency * Multiple / 10; + CardData->MaxFrequency = Frequency; + + CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN; + + if (CardData->CardType == SDMemoryCard2High) { + ASSERT(CardData->CSDRegister.CSD_STRUCTURE == 1); + CsdSDV2 = (CSD_SDV2*)&CardData->CSDRegister; + // + // The SD Spec 2.0 says (CSize + 1) * 512K is the total size, so block numbber is (CSize + 1) * 1K + // the K here means 1024 not 1000 + // + CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen); + } else { + // + // For MMC card > 2G, the block number will be recaculate later + // + CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2); + CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1); + } + + // + //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes + // + if (CardData->BlockLen > 512) { + CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512); + CardData->BlockLen = 512; + } + + DEBUG(( + EFI_D_INFO, + "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen) + )); + +Exit: + return Status; +} + +/** + Test the bus width setting for MMC card.It is used only for verification purpose. + + @param CardData Pointer to CARD_DATA. + @param Width 1, 4, 8 bits. + + @retval EFI_SUCCESS + @retval EFI_UNSUPPORTED + @retval EFI_INVALID_PARAMETER + +**/ +EFI_STATUS +MMCCardBusWidthTest ( + IN CARD_DATA *CardData, + IN UINT32 Width + ) +{ + EFI_STATUS Status; + UINT64 Data; + UINT64 Value; + + ASSERT(CardData != NULL); + + + Value = 0; + + switch (Width) { + case 1: + Data = 0x80; + break; + + case 4: + Data = 0x5A; + break; + + case 8: + Data = 0xAA55; + break; + + default: + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + CopyMem (CardData->AlignedBuffer, &Data, Width); + Status = SendCommand ( + CardData, + BUSTEST_W, + 0, + OutData, + CardData->AlignedBuffer, + Width, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_W 0x%x\n", *(UINT32*)&(CardData->CardStatus))); + goto Exit; + } + + gBS->Stall (10 * 1000); + + Data = 0; + + Status = SendCommand ( + CardData, + BUSTEST_R, + 0, + InData, + CardData->AlignedBuffer, + Width, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_R 0x%x\n", *(UINT32*)&(CardData->CardStatus))); + goto Exit; + } + CopyMem (&Data, CardData->AlignedBuffer, Width); + + switch (Width) { + case 1: + Value = (~(Data ^ 0x80)) & 0xC0; + break; + case 4: + Value = (~(Data ^ 0x5A)) & 0xFF; + break; + case 8: + Value = (~(Data ^ 0xAA55)) & 0xFFFF; + break; + } + + if (Value == 0) { + Status = EFI_SUCCESS; + } else { + Status = EFI_UNSUPPORTED; + } + + +Exit: + return Status; +} + +/** + This function can detect these card types: + 1. MMC card + 2. SD 1.1 card + 3. SD 2.0 standard card + 3. SD 2.0 high capacity card + + @param CardData Pointer to CARD_DATA. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +GetCardType ( + IN CARD_DATA *CardData + ) +{ + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + UINT32 Argument; + UINT32 ResponseData; + UINT32 Count; + BOOLEAN SDCommand8Support; + + + SDHostIo = CardData->SDHostIo; + + // + // Reset the card + // + Status = SendCommand ( + CardData, + GO_IDLE_STATE, + 0, + NoData, + NULL, + 0, + ResponseNo, + TIMEOUT_COMMAND, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status)); + goto Exit; + } + + // + //No spec requirment, can be adjusted + // + gBS->Stall (10 * 1000); + + + // + // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass + // MMC and SD1.1 card will fail this command + // + Argument = (VOLTAGE_27_36 << 8) | CHECK_PATTERN; + ResponseData = 0; + SDCommand8Support = FALSE; + + Status = SendCommand ( + CardData, + SEND_IF_COND, + Argument, + NoData, + NULL, + 0, + ResponseR7, + TIMEOUT_COMMAND, + &ResponseData + ); + + if (EFI_ERROR (Status)) { + if (Status != EFI_TIMEOUT) { + DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, none time out error\n")); + goto Exit; + } + } else { + if (ResponseData != Argument) { + DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n")); + Status = EFI_DEVICE_ERROR; + goto Exit; + } + SDCommand8Support = TRUE; + } + + + Argument = 0; + if (SDHostIo->HostCapability.V30Support == TRUE) { + Argument |= BIT17 | BIT18; + } else if (SDHostIo->HostCapability.V33Support == TRUE) { + Argument |= BIT20 | BIT21; + } + + if (SDCommand8Support) { + // + //If command SD_SEND_OP_COND sucessed, it should be set. + // SD 1.1 card will ignore it + // SD 2.0 standard card will repsond with CCS 0, SD high capacity card will respond with CCS 1 + // CCS is BIT30 of OCR + Argument |= BIT30; + } + + + Count = 20; + // + //Only SD card will respond to this command, and spec says the card only checks condition at first ACMD41 command + // + do { + Status = SendAppCommand ( + CardData, + SD_SEND_OP_COND, + Argument, + NoData, + NULL, + 0, + ResponseR3, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->OCRRegister) + ); + if (EFI_ERROR (Status)) { + if ((Status == EFI_TIMEOUT) && (!SDCommand8Support)) { + CardData->CardType = MMCCard; + Status = EFI_SUCCESS; + DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, MMC card was identified\n")); + } else { + // + // Not as expected, MMC card should has no response, which means timeout. + // SD card should pass this command + // + DEBUG((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n")); + } + goto Exit; + } + // + //Avoid waiting if sucess. Busy bit 0 means not ready + // + if (CardData->OCRRegister.Busy == 1) { + break; + } + + gBS->Stall (50 * 1000); + Count--; + if (Count == 0) { + DEBUG((EFI_D_ERROR, "Card is always in busy state\n")); + Status = EFI_TIMEOUT; + goto Exit; + } + } while (1); + + // + //Check supported voltage + // + Argument = 0; + if (SDHostIo->HostCapability.V30Support == TRUE) { + if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) { + Argument |= BIT17; + } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) { + Argument |= BIT18; + } + } else if (SDHostIo->HostCapability.V33Support == TRUE) { + if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) { + Argument |= BIT20; + } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) { + Argument |= BIT21; + } + } + + if (Argument == 0) { + // + //No matched support voltage + // + PutCardInactive (CardData); + DEBUG((EFI_D_ERROR, "No matched voltage for this card\n")); + Status = EFI_UNSUPPORTED; + goto Exit; + } + + CardData->CardType = SDMemoryCard; + if (SDCommand8Support == TRUE) { + CardData->CardType = SDMemoryCard2; + DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above standard card was identified\n")); + } + + if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) { + CardData->CardType = SDMemoryCard2High; + DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above high capacity card was identified\n")); + } + + + +Exit: + return Status; +} + +/** + MMC card high/low voltage selection function + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_UNSUPPORTED + @retval EFI_BAD_BUFFER_SIZE + +**/ +EFI_STATUS +MMCCardVoltageSelection ( + IN CARD_DATA *CardData + ) +{ + EFI_STATUS Status; + UINT8 Retry; + UINT32 TimeOut; + + Status = EFI_SUCCESS; + // + //First try the high voltage, then if supported choose the low voltage + // + + for (Retry = 0; Retry < 3; Retry++) { + // + // To bring back the normal MMC card to work + // after sending the SD command. Otherwise some + // card could not work + + Status = SendCommand ( + CardData, + GO_IDLE_STATE, + 0, + NoData, + NULL, + 0, + ResponseNo, + TIMEOUT_COMMAND, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status)); + continue; + } + // + //CE-ATA device needs long delay + // + gBS->Stall ((Retry + 1) * 50 * 1000); + + // + //Get OCR register to check voltage support, first time the OCR is 0 + // + Status = SendCommand ( + CardData, + SEND_OP_COND, + 0, + NoData, + NULL, + 0, + ResponseR3, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->OCRRegister) + ); + if (!EFI_ERROR (Status)) { + break; + } + } + + if (Retry == 3) { + DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status)); + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + // + //TimeOut Value, 5000 * 100 * 1000 = 5 s + // + TimeOut = 5000; + + do { + Status = SendCommand ( + CardData, + SEND_OP_COND, + 0x40300000, + NoData, + NULL, + 0, + ResponseR3, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->OCRRegister) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status)); + goto Exit; + } + + gBS->Stall (1 * 1000); + TimeOut--; + if (TimeOut == 0) { + Status = EFI_TIMEOUT; + DEBUG((EFI_D_ERROR, "Card is always in busy state\n")); + goto Exit; + } + } while (CardData->OCRRegister.Busy != 1); + + if (CardData->OCRRegister.AccessMode == 2) // eMMC Card uses Sector Addressing - High Capacity + { + DEBUG((EFI_D_INFO, "eMMC Card is High Capacity\n")); + CardData->CardType = MMCCardHighCap; + } + +Exit: + return Status; + +} + +/** + This function set the bus and device width for MMC card + + @param CardData Pointer to CARD_DATA. + @param Width 1, 4, 8 bits. + + @retval EFI_SUCCESS + @retval EFI_UNSUPPORTED + @retval EFI_INVALID_PARAMETER + +**/ +EFI_STATUS +MMCCardSetBusWidth ( + IN CARD_DATA *CardData, + IN UINT8 BusWidth, + IN BOOLEAN EnableDDRMode + ) +{ + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + SWITCH_ARGUMENT SwitchArgument; + UINT8 Value; + + SDHostIo = CardData->SDHostIo; + Value = 0; + switch (BusWidth) { + case 8: + if (EnableDDRMode) + Value = 6; + else + Value = 2; + break; + + case 4: + if (EnableDDRMode) + Value = 5; + else + Value = 1; + break; + + case 1: + if (EnableDDRMode) // Bus width 1 is not supported in ddr mode + return EFI_UNSUPPORTED; + Value = 0; + break; + + default: + ASSERT(0); + } + + + ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT)); + SwitchArgument.CmdSet = 0; + SwitchArgument.Value = Value; + SwitchArgument.Index = (UINT32)((UINTN) + (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN)(&(CardData->ExtCSDRegister))); + SwitchArgument.Access = WriteByte_Mode; + Status = SendCommand ( + CardData, + SWITCH, + *(UINT32*)&SwitchArgument, + NoData, + NULL, + 0, + ResponseR1b, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (!EFI_ERROR (Status)) { + Status = SendCommand ( + CardData, + SEND_STATUS, + (CardData->Address << 16), + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth)); + goto Exit; + } else { + DEBUG((EFI_D_ERROR, "MMCCardSetBusWidth:SWITCH Card Status:0x%x\n", *(UINT32*)&(CardData->CardStatus))); + Status = SDHostIo->SetBusWidth (SDHostIo, BusWidth); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SWITCH set %d bits Fail\n", BusWidth)); + goto Exit; + } + gBS->Stall (5 * 1000); + } + } + + if (!EnableDDRMode) { // CMD19 and CMD14 are illegal commands in ddr mode + //if (EFI_ERROR (Status)) { + // DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest: Fail to enable high speed mode\n")); + // goto Exit; + //} + + Status = MMCCardBusWidthTest (CardData, BusWidth); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth)); + goto Exit; + } + } + + CardData->CurrentBusWidth = BusWidth; + +Exit: + return Status; +} + + +/** + MMC/SD card init function + + @param CardData Pointer to CARD_DATA. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +MMCSDCardInit ( + IN CARD_DATA *CardData + ) +{ + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + SWITCH_ARGUMENT SwitchArgument; + UINT32 Data; + UINT32 Argument; + UINT32 nIndex; + UINT8 PowerValue; + BOOLEAN EnableDDRMode; + + ASSERT(CardData != NULL); + SDHostIo = CardData->SDHostIo; + EnableDDRMode = FALSE; + + CardData->CardType = UnknownCard; + Status = GetCardType (CardData); + if (EFI_ERROR (Status)) { + goto Exit; + } + DEBUG((DEBUG_INFO, "CardData->CardType 0x%x\n", CardData->CardType)); + + ASSERT (CardData->CardType != UnknownCard); + // + //MMC, SD card need host auto stop command support + // + SDHostIo->EnableAutoStopCmd (SDHostIo, TRUE); + + if (CardData->CardType == MMCCard) { + Status = MMCCardVoltageSelection (CardData); + if (EFI_ERROR(Status)) { + goto Exit; + } + } + + // + // Get CID Register + // + Status = SendCommand ( + CardData, + ALL_SEND_CID, + 0, + NoData, + NULL, + 0, + ResponseR2, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CIDRegister) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "ALL_SEND_CID Fail Status = 0x%x\n", Status)); + goto Exit; + } else { + // Dump out the Card ID data + DEBUG((EFI_D_INFO, "Product Name: ")); + for ( nIndex=0; nIndex<6; nIndex++ ) { + DEBUG((EFI_D_INFO, "%c", CardData->CIDRegister.PNM[nIndex])); + } + DEBUG((EFI_D_INFO, "\nApplication ID : %d\n", CardData->CIDRegister.OID)); + DEBUG((EFI_D_INFO, "Manufacturer ID: %d\n", CardData->CIDRegister.MID)); + DEBUG((EFI_D_INFO, "Revision ID : %d\n", CardData->CIDRegister.PRV)); + DEBUG((EFI_D_INFO, "Serial Number : %d\n", CardData->CIDRegister.PSN)); + } + + // + //SET_RELATIVE_ADDR + // + if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) { + // + //Hard code the RCA address + // + CardData->Address = 1; + + // + // Set RCA Register + // + Status = SendCommand ( + CardData, + SET_RELATIVE_ADDR, + (CardData->Address << 16), + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status)); + goto Exit; + } + } else { + Data = 0; + Status = SendCommand ( + CardData, + SET_RELATIVE_ADDR, + 0, + NoData, + NULL, + 0, + ResponseR6, + TIMEOUT_COMMAND, + &Data + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status)); + goto Exit; + } + + CardData->Address = (UINT16)(Data >> 16); + *(UINT32*)&CardData->CardStatus = Data & 0x1FFF; + CardData->CardStatus.ERROR = (Data >> 13) & 0x1; + CardData->CardStatus.ILLEGAL_COMMAND = (Data >> 14) & 0x1; + CardData->CardStatus.COM_CRC_ERROR = (Data >> 15) & 0x1; + Status = CheckCardStatus (*(UINT32*)&CardData->CardStatus); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status)); + goto Exit; + } + } + + // + // Get CSD Register + // + Status = SendCommand ( + CardData, + SEND_CSD, + (CardData->Address << 16), + NoData, + NULL, + 0, + ResponseR2, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CSDRegister) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SEND_CSD Fail Status = 0x%x\n", Status)); + goto Exit; + } + + DEBUG((EFI_D_INFO, "CardData->CSDRegister.SPEC_VERS = 0x%x\n", CardData->CSDRegister.SPEC_VERS)); + DEBUG((EFI_D_INFO, "CardData->CSDRegister.CSD_STRUCTURE = 0x%x\n", CardData->CSDRegister.CSD_STRUCTURE)); + + Status = CaculateCardParameter (CardData); + if (EFI_ERROR (Status)) { + goto Exit; + } + + + // + // It is platform and hardware specific, need hadrware engineer input + // + if (CardData->CSDRegister.DSR_IMP == 1) { + // + // Default is 0x404 + // + Status = SendCommand ( + CardData, + SET_DSR, + (DEFAULT_DSR_VALUE << 16), + NoData, + NULL, + 0, + ResponseNo, + TIMEOUT_COMMAND, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SET_DSR Fail Status = 0x%x\n", Status)); + // + // Assume can operate even fail + // + } + } + // + //Change clock frequency from 400KHz to max supported when not in high speed mode + // + Status = SDHostIo->SetClockFrequency (SDHostIo, CardData->MaxFrequency); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n")); + goto Exit; + } + + // + //Put the card into tran state + // + Status = SendCommand ( + CardData, + SELECT_DESELECT_CARD, + (CardData->Address << 16), + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD Fail Status = 0x%x\n", Status)); + goto Exit; + } + + // + // No spec requirment, can be adjusted + // + gBS->Stall (5 * 1000); + // + // No need to do so + // + // + Status = SendCommand ( + CardData, + SEND_STATUS, + (CardData->Address << 16), + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status)); + goto Exit; + } + // + //if the SPEC_VERS indicates a version 4.0 or higher + //The card is a high speed card and support Switch + //and Send_ext_csd command + //otherwise it is an old card + // + + if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) { + // + //Only V4.0 and above supports more than 1 bits and high speed + // + if (CardData->CSDRegister.SPEC_VERS >= 4) { + // + //Get ExtCSDRegister + // + Status = SendCommand ( + CardData, + SEND_EXT_CSD, + 0x0, + InData, + CardData->AlignedBuffer, + sizeof (EXT_CSD), + ResponseR1, + TIMEOUT_DATA, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SEND_EXT_CSD Fail Status = 0x%x\n", Status)); + goto Exit; + } + + CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD)); + + // + // Recaculate the block number for >2G MMC card + // + Data = (CardData->ExtCSDRegister.SEC_COUNT[0]) | + (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) | + (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) | + (CardData->ExtCSDRegister.SEC_COUNT[3] << 24); + + if (Data != 0) { + CardData->BlockNumber = Data; + } + DEBUG((DEBUG_INFO, "CardData->BlockNumber %d\n", Data)); + DEBUG((EFI_D_ERROR, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN)CardData->ExtCSDRegister.CARD_TYPE)); + if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2)|| + (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) { + //DEBUG((DEBUG_INFO, "To enable DDR mode\n")); + //EnableDDRMode = TRUE; + } + // + // Check current chipset capability and the plugged-in card + // whether supports HighSpeed + // + if (SDHostIo->HostCapability.HighSpeedSupport) { + + // + //Change card timing to high speed interface timing + // + ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT)); + SwitchArgument.CmdSet = 0; + SwitchArgument.Value = 1; + SwitchArgument.Index = (UINT32)((UINTN) + (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN)(&(CardData->ExtCSDRegister))); + SwitchArgument.Access = WriteByte_Mode; + Status = SendCommand ( + CardData, + SWITCH, + *(UINT32*)&SwitchArgument, + NoData, + NULL, + 0, + ResponseR1b, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "MMCSDCardInit:SWITCH frequency Fail Status = 0x%x\n", Status)); + } + + gBS->Stall (5 * 1000); + + + if (!EFI_ERROR (Status)) { + Status = SendCommand ( + CardData, + SEND_STATUS, + (CardData->Address << 16), + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (!EFI_ERROR (Status)) { + if (EnableDDRMode) { + DEBUG((EFI_D_ERROR, "Enable ddr mode on host controller\n")); + SDHostIo->SetDDRMode (SDHostIo, TRUE); + } else { + DEBUG((EFI_D_ERROR, "Enable high speed mode on host controller\n")); + SDHostIo->SetHighSpeedMode (SDHostIo, TRUE); + } + // + // Change host clock to support high speed and enable chispet to + // support speed + // + if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) { + Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP_HIGH); + } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) { + Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP); + } else { + Status = EFI_UNSUPPORTED; + } + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n")); + goto Exit; + } + // + // It seems no need to stall after changing bus freqeuncy. + // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command. + // But SetClock alreay has delay. + // + } + } + + } + + + + // + // Prefer wide bus width for performance + // + // + // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits + // + if (SDHostIo->HostCapability.BusWidth8 == TRUE) { + Status = MMCCardSetBusWidth (CardData, 8, EnableDDRMode); + if (EFI_ERROR (Status)) { + // + // CE-ATA may support 8 bits and 4 bits, but has no software method for detection + // + Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode); + if (EFI_ERROR (Status)) { + goto Exit; + } + } + } else if (SDHostIo->HostCapability.BusWidth4 == TRUE) { + Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode); + if (EFI_ERROR (Status)) { + goto Exit; + } + } + + PowerValue = 0; + + if (CardData->CurrentBusWidth == 8) { + if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) { + PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360; + PowerValue = PowerValue >> 4; + } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) { + PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360; + PowerValue = PowerValue >> 4; + } + } else if (CardData->CurrentBusWidth == 4) { + if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) { + PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360; + PowerValue = PowerValue & 0xF; + } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) { + PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360; + PowerValue = PowerValue & 0xF; + } + } + + if (PowerValue != 0) { + // + //Update Power Class + // + ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT)); + SwitchArgument.CmdSet = 0; + SwitchArgument.Value = PowerValue; + SwitchArgument.Index = (UINT32)((UINTN) + (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN)(&(CardData->ExtCSDRegister))); + SwitchArgument.Access = WriteByte_Mode; + Status = SendCommand ( + CardData, + SWITCH, + *(UINT32*)&SwitchArgument, + NoData, + NULL, + 0, + ResponseR1b, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (!EFI_ERROR (Status)) { + Status = SendCommand ( + CardData, + SEND_STATUS, + (CardData->Address << 16), + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SWITCH Power Class Fail Status = 0x%x\n", Status)); + } + //gBS->Stall (10 * 1000); + } + } + + + + } else { + + + DEBUG((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n",CardData->CSDRegister.SPEC_VERS)); + } + } else { + // + // Pin 1, at power up this line has a 50KOhm pull up enabled in the card. + // This pull-up should be disconnected by the user, during regular data transfer, + // with SET_CLR_CARD_DETECT (ACMD42) command + // + Status = SendAppCommand ( + CardData, + SET_CLR_CARD_DETECT, + 0, + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail Status = 0x%x\n", Status)); + goto Exit; + } + + /* + // + // Don't rely on SCR and SD status, some cards have unexpected SCR. + // It only sets private section, the other bits are 0 + // such as Sandisk Ultra II 4.0G, KinSton mini SD 128M, Toshiba 2.0GB + // Some card even fail this command, KinSton SD 4GB + // + Status = SendAppCommand ( + CardData, + SEND_SCR, + 0, + InData, + (UINT8*)&(CardData->SCRRegister), + sizeof(SCR), + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // SD memory card at least supports 1 and 4 bits. + // + // ASSERT ((CardData->SCRRegister.SD_BUS_WIDTH & (BIT0 | BIT2)) == (BIT0 | BIT2)); + */ + + // + // Set Bus Width to 4 + // + Status = SendAppCommand ( + CardData, + SET_BUS_WIDTH, + SD_BUS_WIDTH_4, + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits Fail Status = 0x%x\n", Status)); + goto Exit; + } + + Status = SDHostIo->SetBusWidth (SDHostIo, 4); + if (EFI_ERROR (Status)) { + goto Exit; + } + CardData->CurrentBusWidth = 4; + + + if ((SDHostIo->HostCapability.HighSpeedSupport == FALSE) || + ((CardData->CSDRegister.CCC & BIT10) != BIT10)) { + // + // Host must support high speed + // Card must support Switch function + // + goto Exit; + } + + // + //Mode = 0, group 1, function 1, check operation + // + Argument = 0xFFFF01; + ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS)); + + Status = SendCommand ( + CardData, + SWITCH_FUNC, + Argument, + InData, + CardData->AlignedBuffer, + sizeof (SWITCH_STATUS), + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS)); + + if ((CardData->SwitchStatus.DataStructureVersion == 0x0) || + ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) { + // + // 1. SD 1.1 card does not suppport busy bit + // 2. Ready state + // + // + + // + //Mode = 1, group 1, function 1, BIT31 set means set mode + // + Argument = 0xFFFF01 | BIT31; + ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS)); + + Status = SendCommand ( + CardData, + SWITCH_FUNC, + Argument, + InData, + CardData->AlignedBuffer, + sizeof (SWITCH_STATUS), + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS)); + + if ((CardData->SwitchStatus.DataStructureVersion == 0x0) || + ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) { + // + // 1. SD 1.1 card does not suppport busy bit + // 2. Ready state + // + + // + // 8 clocks, (1/ 25M) * 8 ==> 320 us, so 1ms > 0.32 ms + // + gBS->Stall (1000); + + // + //Change host clock + // + Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_SD_PP_HIGH); + if (EFI_ERROR (Status)) { + goto Exit; + } + + } + } + } + if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) || + (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) { + + // + // Set Block Length, to improve compatibility in case of some cards + // + Status = SendCommand ( + CardData, + SET_BLOCKLEN, + 512, + NoData, + NULL, + 0, + ResponseR1, + TIMEOUT_COMMAND, + (UINT32*)&(CardData->CardStatus) + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "SET_BLOCKLEN Fail Status = 0x%x\n", Status)); + goto Exit; + } + } + SDHostIo->SetBlockLength (SDHostIo, 512); + + +Exit: + return Status; +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c new file mode 100644 index 0000000000..400f041526 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.c @@ -0,0 +1,317 @@ +/** @file + +The definition for SD media device driver model and blkio protocol routines. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "SDMediaDevice.h" + + +EFI_DRIVER_BINDING_PROTOCOL gSDMediaDeviceDriverBinding = { + SDMediaDeviceSupported, + SDMediaDeviceStart, + SDMediaDeviceStop, + 0x20, + NULL, + NULL +}; + +/** + Entry point for EFI drivers. + + @param ImageHandle EFI_HANDLE. + @param SystemTable EFI_SYSTEM_TABLE. + + @retval EFI_SUCCESS Driver is successfully loaded. + @return Others Failed. + +**/ +EFI_STATUS +EFIAPI +InitializeSDMediaDevice ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSDMediaDeviceDriverBinding, + ImageHandle, + &gSDMediaDeviceName, + &gSDMediaDeviceName2 + ); +} + + +/** + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that has BlockIoProtocol installed will be supported. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS This driver supports this device. + @return EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +SDMediaDeviceSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + + // + // Test whether there is PCI IO Protocol attached on the controller handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSDHostIoProtocolGuid, + (VOID **)&SDHostIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + gBS->CloseProtocol ( + Controller, + &gEfiSDHostIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + +Exit: + return Status; +} + +/** + Starting the SD Media Device Driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. + EFI_OUT_OF_RESOURCES- Failed due to resource shortage. + +**/ +EFI_STATUS +EFIAPI +SDMediaDeviceStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_SD_HOST_IO_PROTOCOL *SDHostIo; + CARD_DATA *CardData; + + CardData = NULL; + + // + // Open PCI I/O Protocol and save pointer to open protocol + // in private data area. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSDHostIoProtocolGuid, + (VOID **) &SDHostIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to open gEfiSDHostIoProtocolGuid \r\n")); + goto Exit; + } + + Status = SDHostIo->DetectCardAndInitHost (SDHostIo); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: Fail to DetectCardAndInitHost \r\n")); + goto Exit; + } + + CardData = (CARD_DATA*)AllocateZeroPool(sizeof (CARD_DATA)); + if (CardData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to AllocateZeroPool(CARD_DATA) \r\n")); + goto Exit; + } + + ASSERT (SDHostIo->HostCapability.BoundarySize >= 4 * 1024); + CardData->RawBufferPointer = (UINT8*)((UINTN)DMA_MEMORY_TOP); + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (2 * SDHostIo->HostCapability.BoundarySize), + (EFI_PHYSICAL_ADDRESS *)(&CardData->RawBufferPointer) + ); + + if (CardData->RawBufferPointer == NULL) { + DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to AllocateZeroPool(2*x) \r\n")); + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + CardData->AlignedBuffer = CardData->RawBufferPointer - ((UINTN)(CardData->RawBufferPointer) & (SDHostIo->HostCapability.BoundarySize - 1)) + SDHostIo->HostCapability.BoundarySize; + + CardData->Signature = CARD_DATA_SIGNATURE; + CardData->SDHostIo = SDHostIo; + + Status = MMCSDCardInit (CardData); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to MMCSDCardInit \r\n")); + goto Exit; + } + DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: MMCSDCardInit SuccessFul\n")); + + if (CardData->CardType == CEATACard) { + Status = CEATABlockIoInit (CardData); + } else { + Status = MMCSDBlockIoInit (CardData); + } + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to BlockIoInit \r\n")); + goto Exit; + } + DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: BlockIo is successfully installed\n")); + + + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiBlockIoProtocolGuid, + EFI_NATIVE_INTERFACE, + &CardData->BlockIo + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to install gEfiBlockIoProtocolGuid \r\n")); + goto Exit; + } + + // + // Install the component name protocol + // + CardData->ControllerNameTable = NULL; + + AddUnicodeString2 ( + "eng", + gSDMediaDeviceName.SupportedLanguages, + &CardData->ControllerNameTable, + L"MMC/SD Media Device", + TRUE + ); + AddUnicodeString2 ( + "en", + gSDMediaDeviceName2.SupportedLanguages, + &CardData->ControllerNameTable, + L"MMC/SD Media Device", + FALSE + ); + +Exit: + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: End with failure\r\n")); + if (CardData != NULL) { + if (CardData->RawBufferPointer != NULL) { + gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * SDHostIo->HostCapability.BoundarySize)); + } + FreePool (CardData); + } + } + + return Status; +} + + +/** + Stop this driver on ControllerHandle. Support stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +SDMediaDeviceStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + CARD_DATA *CardData; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + + // + // First find BlockIo Protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiBlockIoProtocolGuid, + (VOID **)&BlockIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CardData = CARD_DATA_FROM_THIS(BlockIo); + + // + // Uninstall Block I/O protocol from the device handle + // + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiBlockIoProtocolGuid, + BlockIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (CardData != NULL) { + if (CardData->RawBufferPointer != NULL) { + gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * CardData->SDHostIo->HostCapability.BoundarySize)); + } + FreeUnicodeStringTable (CardData->ControllerNameTable); + FreePool (CardData); + } + + gBS->CloseProtocol ( + Controller, + &gEfiSDHostIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; +} + + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h new file mode 100644 index 0000000000..ac70f5a8bf --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDevice.h @@ -0,0 +1,462 @@ +/** @file + +The definition for SD media device driver model and blkio protocol routines. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SD_MEDIA_DEVICE_H_ +#define _SD_MEDIA_DEVICE_H_ + + +#include + +#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 stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +SDMediaDeviceStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +/** + MMC/SD card init function + + @param CardData Pointer to CARD_DATA. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +MMCSDCardInit ( + IN CARD_DATA *CardData + ); + +/** + Send command by using Host IO protocol + + @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance. + @param CommandIndex The command index to set the command index field of command register. + @param Argument Command argument to set the argument field of command register. + @param DataType TRANSFER_TYPE, indicates no data, data in or data out. + @param Buffer Contains the data read from / write to the device. + @param BufferSize The size of the buffer. + @param ResponseType RESPONSE_TYPE. + @param TimeOut Time out value in 1 ms unit. + @param ResponseData Depending on the ResponseType, such as CSD or card status. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_UNSUPPORTED + @retval EFI_DEVICE_ERROR + +**/ +EFI_STATUS +SendCommand ( + IN CARD_DATA *CardData, + IN UINT16 CommandIndex, + IN UINT32 Argument, + IN TRANSFER_TYPE DataType, + IN UINT8 *Buffer, OPTIONAL + IN UINT32 BufferSize, + IN RESPONSE_TYPE ResponseType, + IN UINT32 TimeOut, + OUT UINT32 *ResponseData + ); + +/** + Send the card APP_CMD command with the following command indicated by CommandIndex + + @param CardData Pointer to CARD_DATA. + @param CommandIndex The command index to set the command index field of command register. + @param Argument Command argument to set the argument field of command register. + @param DataType TRANSFER_TYPE, indicates no data, data in or data out. + @param Buffer Contains the data read from / write to the device. + @param BufferSize The size of the buffer. + @param ResponseType RESPONSE_TYPE. + @param TimeOut Time out value in 1 ms unit. + @param ResponseData Depending on the ResponseType, such as CSD or card status. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_UNSUPPORTED + @retval EFI_DEVICE_ERROR + +**/ +EFI_STATUS +SendAppCommand ( + IN CARD_DATA *CardData, + IN UINT16 CommandIndex, + IN UINT32 Argument, + IN TRANSFER_TYPE DataType, + IN UINT8 *Buffer, OPTIONAL + IN UINT32 BufferSize, + IN RESPONSE_TYPE ResponseType, + IN UINT32 TimeOut, + OUT UINT32 *ResponseData + ); + +/** + Send the card FAST_IO command + + @param CardData Pointer to CARD_DATA. + @param RegisterAddress Register Address. + @param RegisterData Pointer to register Data. + @param Write TRUE for write, FALSE for read. + + @retval EFI_SUCCESS + @retval EFI_UNSUPPORTED + @retval EFI_INVALID_PARAMETER + @retval EFI_DEVICE_ERROR + +**/ +EFI_STATUS +FastIO ( + IN CARD_DATA *CardData, + IN UINT8 RegisterAddress, + IN OUT UINT8 *RegisterData, + IN BOOLEAN Write + ); + +/** + Judge whether it is CE-ATA device or not. + + @param CardData Pointer to CARD_DATA. + + @retval TRUE + @retval FALSE + +**/ +BOOLEAN +IsCEATADevice ( + IN CARD_DATA *CardData + ); + +/** + Send software reset + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +SoftwareReset ( + IN CARD_DATA *CardData + ); + +/** + SendATACommand specificed in Taskfile + + @param CardData Pointer to CARD_DATA. + @param TaskFile Pointer to TASK_FILE. + @param Write TRUE means write, FALSE means read. + @param Buffer If NULL, means no data transfer, neither read nor write. + @param SectorCount Buffer size in 512 bytes unit. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +SendATACommand ( + IN CARD_DATA *CardData, + IN TASK_FILE *TaskFile, + IN BOOLEAN Write, + IN UINT8 *Buffer, + IN UINT16 SectorCount + ); + +/** + IDENTIFY_DEVICE command + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +IndentifyDevice ( + IN CARD_DATA *CardData + ); + +/** + FLUSH_CACHE_EXT command + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +FlushCache ( + IN CARD_DATA *CardData + ); + +/** + STANDBY_IMMEDIATE command + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +StandByImmediate ( + IN CARD_DATA *CardData + ); + +/** + READ_DMA_EXT command + + @param CardData Pointer to CARD_DATA. + @param LBA The starting logical block address to read from on the device. + @param Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + @param SectorCount Size in 512 bytes unit. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +ReadDMAExt ( + IN CARD_DATA *CardData, + IN EFI_LBA LBA, + IN UINT8 *Buffer, + IN UINT16 SectorCount + ); + +/** + WRITE_DMA_EXT command + + @param CardData Pointer to CARD_DATA. + @param LBA The starting logical block address to read from on the device. + @param Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + @param SectorCount Size in 512 bytes unit. + + @retval EFI_SUCCESS Success + @retval EFI_DEVICE_ERROR Hardware Error + @retval EFI_INVALID_PARAMETER Parameter is error + @retval EFI_NO_MEDIA No media + @retval EFI_MEDIA_CHANGED Media Change + @retval EFI_BAD_BUFFER_SIZE Buffer size is bad + +**/ +EFI_STATUS +WriteDMAExt ( + IN CARD_DATA *CardData, + IN EFI_LBA LBA, + IN UINT8 *Buffer, + IN UINT16 SectorCount + ); + +/** + CEATA card BlockIo init function. + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS + @retval Others +**/ +EFI_STATUS +CEATABlockIoInit ( + IN CARD_DATA *CardData + ); + +/** + MMC/SD card BlockIo init function. + + @param CardData Pointer to CARD_DATA. + + @retval EFI_SUCCESS + @retval Others +**/ +EFI_STATUS +MMCSDBlockIoInit ( + IN CARD_DATA *CardData + ); +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf new file mode 100644 index 0000000000..eb85b9c0a6 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf @@ -0,0 +1,60 @@ +## @file +# +# Component Description File For SDMediaDeviceDxe Module. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SDMediaDevice + FILE_GUID = 80897901-91F6-4efe-9579-3353A0C02DAB + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeSDMediaDevice + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# DRIVER_BINDING = gSDMediaDeviceDriverBinding +# COMPONENT_NAME = gSDMediaDeviceName +# COMPONENT_NAME2 = gSDMediaDeviceName2 +# + +[Sources] + SDMediaDevice.c + SDMediaDevice.h + MMCSDTransfer.c + CEATA.c + CEATABlockIo.c + MMCSDBlockIo.c + ComponentName.c + ComponentName.h + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + DebugLib + PcdLib + +[Protocols] + gEfiPciIoProtocolGuid ## TO_START + gEfiSDHostIoProtocolGuid ## TO_START + gEfiBlockIoProtocolGuid ## BY_START + +[Pcd.common] diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c new file mode 100644 index 0000000000..f393aa8643 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.c @@ -0,0 +1,320 @@ +/** @file +Implementation of Usb Controller PPI. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#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/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h new file mode 100644 index 0000000000..c270fea46e --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.h @@ -0,0 +1,38 @@ +/** @file +Define private data structure for UHCI and EHCI. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _USB_PEI_H +#define _USB_PEI_H + +#include "Ioh.h" + +#define PEI_IOH_OHCI_SIGNATURE SIGNATURE_32 ('O', 'H', 'C', 'I') +#define PEI_IOH_EHCI_SIGNATURE SIGNATURE_32 ('E', 'H', 'C', 'I') + +typedef struct { + UINTN Signature; + PEI_USB_CONTROLLER_PPI UsbControllerPpi; + EFI_PEI_PPI_DESCRIPTOR PpiList; + UINTN MmioBase[IOH_MAX_OHCI_USB_CONTROLLERS]; +} IOH_OHCI_DEVICE; + +typedef struct { + UINTN Signature; + PEI_USB_CONTROLLER_PPI UsbControllerPpi; + EFI_PEI_PPI_DESCRIPTOR PpiList; + UINTN MmioBase[IOH_MAX_EHCI_USB_CONTROLLERS]; +} IOH_EHCI_DEVICE; + +#define IOH_OHCI_DEVICE_FROM_THIS(a) \ + CR(a, IOH_OHCI_DEVICE, UsbControllerPpi, PEI_IOH_OHCI_SIGNATURE) + +#define IOH_EHCI_DEVICE_FROM_THIS(a) \ + CR (a, IOH_EHCI_DEVICE, UsbControllerPpi, PEI_IOH_EHCI_SIGNATURE) + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf new file mode 100644 index 0000000000..ab57ff87d3 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf @@ -0,0 +1,53 @@ +## @file +# Component description file for UsbPei module. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UsbPei + FILE_GUID = 73E6F6B4-D029-4e87-8405-6067C8BD02A6 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = PeimInitializeIchUsb + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + UsbPei.c + UsbPei.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + IoLib + PciLib + PcdLib + BaseMemoryLib + PeimEntryPoint + DebugLib + +[Ppis] + gPeiUsbControllerPpiGuid # PPI ALWAYS_PRODUCED + +[FeaturePcd] + gEfiQuarkSCSocIdTokenSpaceGuid.PcdEhciRecoveryEnabled + +[Pcd] + gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiQNCUsbControllerMemoryBaseAddress + gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiP2PMemoryBaseAddress + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c new file mode 100644 index 0000000000..3c2ba51ad4 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.c @@ -0,0 +1,219 @@ +/** @file +UEFI Component Name and Name2 protocol for OHCI driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName = { + OhciComponentNameGetDriverName, + OhciComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) OhciComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) OhciComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOhciDriverNameTable[] = { + { "eng;en", L"Usb Ohci Driver" }, + { NULL, NULL } +}; + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mOhciDriverNameTable, + DriverName, + (BOOLEAN)(This == &gOhciComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + USB_OHCI_HC_DEV *OhciDev; + EFI_USB_HC_PROTOCOL *UsbHc; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + // + // Make sure this driver is currently managing ControllerHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gOhciDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbHcProtocolGuid, + (VOID **) &UsbHc, + gOhciDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + OhciDev = USB_OHCI_HC_DEV_FROM_THIS (UsbHc); + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + OhciDev->ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gOhciComponentName) + ); + +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h new file mode 100644 index 0000000000..c54cd6356c --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/ComponentName.h @@ -0,0 +1,141 @@ +/** @file +This file contains the delarations for componet name routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _COMPONENT_NAME_H_ +#define _COMPONENT_NAME_H_ + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +#endif + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h new file mode 100644 index 0000000000..14a619bb3f --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Descriptor.h @@ -0,0 +1,132 @@ +/** @file +This file contains the descriptor definination of OHCI spec + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _DESCRIPTOR_H +#define _DESCRIPTOR_H + +#define ED_FUNC_ADD 0x0001 +#define ED_ENDPT_NUM 0x0002 +#define ED_DIR 0x0004 +#define ED_SPEED 0x0008 +#define ED_SKIP 0x0010 +#define ED_FORMAT 0x0020 +#define ED_MAX_PACKET 0x0040 +#define ED_TDTAIL_PTR 0x0080 +#define ED_HALTED 0x0100 +#define ED_DTTOGGLE 0x0200 +#define ED_TDHEAD_PTR 0x0400 +#define ED_NEXT_EDPTR 0x0800 +#define ED_PDATA 0x1000 +#define ED_ZERO 0x2000 + +#define TD_BUFFER_ROUND 0x0001 +#define TD_DIR_PID 0x0002 +#define TD_DELAY_INT 0x0004 +#define TD_DT_TOGGLE 0x0008 +#define TD_ERROR_CNT 0x0010 +#define TD_COND_CODE 0x0020 +#define TD_CURR_BUFFER_PTR 0x0040 +#define TD_NEXT_PTR 0x0080 +#define TD_BUFFER_END_PTR 0x0100 +#define TD_PDATA 0x0200 + +#define ED_FROM_TD_DIR 0x0 +#define ED_OUT_DIR 0x1 +#define ED_IN_DIR 0x2 +#define ED_FROM_TD_ALSO_DIR 0x3 + +#define TD_SETUP_PID 0x00 +#define TD_OUT_PID 0x01 +#define TD_IN_PID 0x02 +#define TD_NODATA_PID 0x03 + +#define HI_SPEED 0 +#define LO_SPEED 1 + +#define TD_NO_ERROR 0x00 +#define TD_CRC_ERROR 0x01 +#define TD_BITSTUFFING_ERROR 0x02 +#define TD_TOGGLE_ERROR 0x03 +#define TD_DEVICE_STALL 0x04 +#define TD_NO_RESPONSE 0x05 +#define TD_PIDCHK_FAIL 0x06 +#define TD_PID_UNEXPECTED 0x07 +#define TD_DATA_OVERRUN 0x08 +#define TD_DATA_UNDERRUN 0x09 +#define TD_BUFFER_OVERRUN 0x0C +#define TD_BUFFER_UNDERRUN 0x0D +#define TD_TOBE_PROCESSED 0x0E +#define TD_TOBE_PROCESSED_2 0x0F + +#define TD_NO_DELAY 0x7 + +#define TD_INT 0x1 +#define TD_CTL 0x2 +#define TD_BLK 0x3 + +typedef struct { + UINT32 Reserved:18; + UINT32 BufferRounding:1; + UINT32 DirPID:2; + UINT32 DelayInterrupt:3; + UINT32 DataToggle:2; + UINT32 ErrorCount:2; + UINT32 ConditionCode:4; +} TD_DESCRIPTOR_WORD0; + +typedef struct _TD_DESCRIPTOR { + TD_DESCRIPTOR_WORD0 Word0; + UINT32 CurrBufferPointer; // 32-bit Physical Address of buffer + UINT32 NextTD; // 32-bit Physical Address of TD_DESCRIPTOR + UINT32 BufferEndPointer; // 32-bit Physical Address of buffer + UINT32 NextTDPointer; // 32-bit Physical Address of TD_DESCRIPTOR + UINT32 DataBuffer; // 32-bit Physical Address of buffer + UINT32 ActualSendLength; + UINT32 Reserved; +} TD_DESCRIPTOR; + +typedef struct { + UINT32 FunctionAddress:7; + UINT32 EndPointNum:4; + UINT32 Direction:2; + UINT32 Speed:1; + UINT32 Skip:1; + UINT32 Format:1; + UINT32 MaxPacketSize:11; + UINT32 FreeSpace:5; +} ED_DESCRIPTOR_WORD0; + +typedef struct { + UINT32 Halted:1; + UINT32 ToggleCarry:1; + UINT32 Zero:2; + UINT32 TdHeadPointer:28; +} ED_DESCRIPTOR_WORD2; + +typedef struct _ED_DESCRIPTOR { + ED_DESCRIPTOR_WORD0 Word0; + UINT32 TdTailPointer; // 32-bit Physical Address of TD_DESCRIPTOR + ED_DESCRIPTOR_WORD2 Word2; + UINT32 NextED; // 32-bit Physical Address of ED_DESCRIPTOR +} ED_DESCRIPTOR; + +#define TD_PTR(p) ((TD_DESCRIPTOR *)(UINTN)((p) << 4)) +#define ED_PTR(p) ((ED_DESCRIPTOR *)(UINTN)((p) << 4)) +#define RIGHT_SHIFT_4(p) ((UINT32)(p) >> 4) + +typedef enum { + CONTROL_LIST, + BULK_LIST, + INTERRUPT_LIST, + ISOCHRONOUS_LIST +} DESCRIPTOR_LIST_TYPE; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c new file mode 100644 index 0000000000..dbff8f1fcb --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c @@ -0,0 +1,2473 @@ +/** @file +This file contains the implementation of Usb Hc Protocol. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + +/** + Provides software reset for the USB host controller. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param Attributes A bit mask of the reset operation to perform. + + @retval EFI_SUCCESS The reset operation succeeded. + @retval EFI_INVALID_PARAMETER Attributes is not valid. + @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is + not currently supported by the host controller. + @retval EFI_DEVICE_ERROR Host controller isn't halted to reset. + +**/ +EFI_STATUS +EFIAPI +OhciReset ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT16 Attributes + ) +{ + EFI_STATUS Status; + USB_OHCI_HC_DEV *Ohc; + UINT8 Index; + UINT8 NumOfPorts; + UINT32 PowerOnGoodTime; + UINT32 Data32; + BOOLEAN Flag = FALSE; + + if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_SUCCESS; + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) { + gBS->Stall (50 * 1000); + Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + gBS->Stall (50 * 1000); + // + // Wait for host controller reset. + // + PowerOnGoodTime = 50; + do { + gBS->Stall (1 * 1000); + Data32 = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + if ((Data32 & HC_RESET) == 0) { + Flag = TRUE; + break; + } + }while(PowerOnGoodTime--); + if (!Flag){ + return EFI_DEVICE_ERROR; + } + } + OhciFreeIntTransferMemory (Ohc); + Status = OhciInitializeInterruptList (Ohc); + OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); + if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) { + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + gBS->Stall (50 * 1000); + } + // + // Initialize host controller operational registers + // + OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778); + OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); + OhciSetPeriodicStart (Ohc, 0x2a2f); + OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x3); + OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0); + OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0); + OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1); + //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0); + //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1); + + OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0); + OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff); + OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE); + OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER); + OhciGetRootHubNumOfPorts (This, &NumOfPorts); + for (Index = 0; Index < NumOfPorts; Index++) { + if (!EFI_ERROR (OhciSetRootHubPortFeature (This, Index, EfiUsbPortReset))) { + gBS->Stall (200 * 1000); + OhciClearRootHubPortFeature (This, Index, EfiUsbPortReset); + gBS->Stall (1000); + OhciSetRootHubPortFeature (This, Index, EfiUsbPortEnable); + gBS->Stall (1000); + } + } + OhciSetMemoryPointer (Ohc, HC_HCCA, Ohc->HccaMemoryBlock); + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); + OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | BULK_ENABLE, 1); /*ISOCHRONOUS_ENABLE*/ + OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL); + gBS->Stall (50*1000); + // + // Wait till first SOF occurs, and then clear it + // + while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0); + OhciClearInterruptStatus (Ohc, START_OF_FRAME); + gBS->Stall (1000); + + return Status; +} + +/** + Retrieve the current state of the USB host controller. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param State Variable to return the current host controller + state. + + @retval EFI_SUCCESS Host controller state was returned in State. + @retval EFI_INVALID_PARAMETER State is NULL. + @retval EFI_DEVICE_ERROR An error was encountered while attempting to + retrieve the host controller's current state. + +**/ + +EFI_STATUS +EFIAPI +OhciGetState ( + IN EFI_USB_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State + ) +{ + USB_OHCI_HC_DEV *Ohc; + UINT32 FuncState; + + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + FuncState = OhciGetHcControl (Ohc, HC_FUNCTIONAL_STATE); + + switch (FuncState) { + case HC_STATE_RESET: + case HC_STATE_RESUME: + *State = EfiUsbHcStateHalt; + break; + + case HC_STATE_OPERATIONAL: + *State = EfiUsbHcStateOperational; + break; + + case HC_STATE_SUSPEND: + *State = EfiUsbHcStateSuspend; + break; + + default: + ASSERT (FALSE); + } + return EFI_SUCCESS; +} + +/** + Sets the USB host controller to a specific state. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param State The state of the host controller that will be set. + + @retval EFI_SUCCESS The USB host controller was successfully placed + in the state specified by State. + @retval EFI_INVALID_PARAMETER State is invalid. + @retval EFI_DEVICE_ERROR Failed to set the state due to device error. + +**/ + +EFI_STATUS +EFIAPI +OhciSetState( + IN EFI_USB_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State + ) +{ + EFI_STATUS Status; + USB_OHCI_HC_DEV *Ohc; + + Ohc = USB_OHCI_HC_DEV_FROM_THIS(This); + + switch (State) { + case EfiUsbHcStateHalt: + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET); + break; + + case EfiUsbHcStateOperational: + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL); + break; + + case EfiUsbHcStateSuspend: + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_SUSPEND); + break; + + default: + Status = EFI_INVALID_PARAMETER; + } + + gBS->Stall (1000); + + return Status; +} + +/** + + Submits control transfer to a target USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPaketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Request A pointer to the USB device request that will be sent + to the USB device. + @param TransferDirection Specifies the data direction for the transfer. + There are three values available, DataIn, DataOut + and NoData. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength Indicates the size, in bytes, of the data buffer + specified by Data. + @param TimeOut Indicates the maximum time, in microseconds, + which the transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information generated + by this control transfer. + + @retval EFI_SUCCESS The control transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The control transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +--*/ + + +EFI_STATUS +EFIAPI +OhciControlTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data OPTIONAL, + IN OUT UINTN *DataLength OPTIONAL, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + USB_OHCI_HC_DEV *Ohc; + ED_DESCRIPTOR *HeadEd; + ED_DESCRIPTOR *Ed; + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *SetupTd; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *StatusTd; + TD_DESCRIPTOR *EmptyTd; + EFI_STATUS Status; + UINT32 DataPidDir; + UINT32 StatusPidDir; + UINTN TimeCount; + OHCI_ED_RESULT EdResult; + + EFI_PCI_IO_PROTOCOL_OPERATION MapOp; + + UINTN ActualSendLength; + UINTN LeftLength; + UINT8 DataToggle; + + VOID *ReqMapping = NULL; + UINTN ReqMapLength = 0; + EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0; + + VOID *DataMapping = NULL; + UINTN DataMapLength = 0; + EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0; + + HeadTd = NULL; + DataTd = NULL; + + if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn && + TransferDirection != EfiUsbNoData) || + Request == NULL || DataLength == NULL || TransferResult == NULL || + (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) || + (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) || + (IsSlowDevice && MaxPacketLength != 8) || + (MaxPacketLength != 8 && MaxPacketLength != 16 && + MaxPacketLength != 32 && MaxPacketLength != 64)) { + return EFI_INVALID_PARAMETER; + } + + if (*DataLength > MAX_BYTES_PER_TD) { + DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\r\n")); + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS(This); + + if (TransferDirection == EfiUsbDataIn) { + DataPidDir = TD_IN_PID; + StatusPidDir = TD_OUT_PID; + } else { + DataPidDir = TD_OUT_PID; + StatusPidDir = TD_IN_PID; + } + + Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 0); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 0); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + gBS->Stall(20 * 1000); + + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); + Ed = OhciCreateED (Ohc); + if (Ed == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\r\n")); + goto CTRL_EXIT; + } + OhciSetEDField (Ed, ED_SKIP, 1); + OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); + OhciSetEDField (Ed, ED_ENDPT_NUM, 0); + OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); + OhciSetEDField (Ed, ED_SPEED, IsSlowDevice); + OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); + OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); + OhciSetEDField (Ed, ED_PDATA, 0); + OhciSetEDField (Ed, ED_ZERO, 0); + OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); + OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); + OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); + HeadEd = OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL); + // + // Setup Stage + // + if(Request != NULL) { + ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST); + MapOp = EfiPciIoOperationBusMasterRead; + Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Request, &ReqMapLength, &ReqMapPhyAddr, &ReqMapping); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to Map Request Buffer\r\n")); + goto FREE_ED_BUFF; + } + } + SetupTd = OhciCreateTD (Ohc); + if (SetupTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n")); + goto UNMAP_SETUP_BUFF; + } + HeadTd = SetupTd; + OhciSetTDField (SetupTd, TD_PDATA, 0); + OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID); + OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2); + OhciSetTDField (SetupTd, TD_ERROR_CNT, 0); + OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINT32)ReqMapPhyAddr); + OhciSetTDField (SetupTd, TD_NEXT_PTR, 0); + OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINT32)(ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1)); + SetupTd->ActualSendLength = sizeof (EFI_USB_DEVICE_REQUEST); + SetupTd->DataBuffer = (UINT32)ReqMapPhyAddr; + SetupTd->NextTDPointer = 0; + + if (TransferDirection == EfiUsbDataIn) { + MapOp = EfiPciIoOperationBusMasterWrite; + } else { + MapOp = EfiPciIoOperationBusMasterRead; + } + DataMapLength = *DataLength; + if ((Data != NULL) && (DataMapLength != 0)) { + Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, Data, &DataMapLength, &DataMapPhyAddr, &DataMapping); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail To Map Data Buffer\r\n")); + goto FREE_TD_BUFF; + } + } + // + //Data Stage + // + LeftLength = DataMapLength; + ActualSendLength = DataMapLength; + DataToggle = 1; + while (LeftLength > 0) { + ActualSendLength = LeftLength; + if (LeftLength > MaxPacketLength) { + ActualSendLength = MaxPacketLength; + } + DataTd = OhciCreateTD (Ohc); + if (DataTd == NULL) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n")); + Status = EFI_OUT_OF_RESOURCES; + goto UNMAP_DATA_BUFF; + } + OhciSetTDField (DataTd, TD_PDATA, 0); + OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); + OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle); + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr); + OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(DataMapPhyAddr + ActualSendLength - 1)); + OhciSetTDField (DataTd, TD_NEXT_PTR, 0); + DataTd->ActualSendLength = (UINT32)ActualSendLength; + DataTd->DataBuffer = (UINT32)DataMapPhyAddr; + DataTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, DataTd); + DataToggle ^= 1; + DataMapPhyAddr += ActualSendLength; + LeftLength -= ActualSendLength; + } + // + // Status Stage + // + StatusTd = OhciCreateTD (Ohc); + if (StatusTd == NULL) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n")); + Status = EFI_OUT_OF_RESOURCES; + goto UNMAP_DATA_BUFF; + } + OhciSetTDField (StatusTd, TD_PDATA, 0); + OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir); + OhciSetTDField (StatusTd, TD_DELAY_INT, 7); + OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3); + OhciSetTDField (StatusTd, TD_ERROR_CNT, 0); + OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (StatusTd, TD_NEXT_PTR, 0); + OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, 0); + StatusTd->ActualSendLength = 0; + StatusTd->DataBuffer = 0; + StatusTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, StatusTd); + // + // Empty Stage + // + EmptyTd = OhciCreateTD (Ohc); + if (EmptyTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto UNMAP_DATA_BUFF; + } + OhciSetTDField (EmptyTd, TD_PDATA, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); + OhciSetTDField (EmptyTd, TD_DIR_PID, 0); + OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); + //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); + EmptyTd->Word0.DataToggle = 0; + OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); + OhciSetTDField (EmptyTd, TD_COND_CODE, 0); + OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); + OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); + EmptyTd->ActualSendLength = 0; + EmptyTd->DataBuffer = 0; + EmptyTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, EmptyTd); + Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd; + OhciAttachTDListToED (Ed, HeadTd); + // + // For debugging, dump ED & TD buffer befor transferring + // + // + //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE); + // + OhciSetEDField (Ed, ED_SKIP, 0); + Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 1); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + goto UNMAP_DATA_BUFF; + } + Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + goto UNMAP_DATA_BUFF; + } + gBS->Stall(20 * 1000); + + + TimeCount = 0; + Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult); + + while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { + gBS->Stall (1000); + TimeCount++; + Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult); + } + // + // For debugging, dump ED & TD buffer after transferring + // + //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE); + // + *TransferResult = ConvertErrorCode (EdResult.ErrorCode); + + if (EdResult.ErrorCode != TD_NO_ERROR) { + if (EdResult.ErrorCode == TD_TOBE_PROCESSED) { + DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut)); + } else { + DEBUG ((EFI_D_INFO, "Control pipe broken\r\n")); + } + *DataLength = 0; + } else { + DEBUG ((EFI_D_INFO, "Control transfer successed\r\n")); + } + +UNMAP_DATA_BUFF: + OhciSetEDField (Ed, ED_SKIP, 1); + if (HeadEd == Ed) { + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); + } else { + HeadEd->NextED = Ed->NextED; + } + if(DataMapping != NULL) { + Ohc->PciIo->Unmap(Ohc->PciIo, DataMapping); + } + +FREE_TD_BUFF: + while (HeadTd) { + DataTd = HeadTd; + HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); + UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); + } + +UNMAP_SETUP_BUFF: + if(ReqMapping != NULL) { + Ohc->PciIo->Unmap(Ohc->PciIo, ReqMapping); + } + +FREE_ED_BUFF: + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + +CTRL_EXIT: + return Status; +} + +/** + + Submits bulk transfer to a bulk endpoint of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an + endpoint direction of the target USB device. + Each endpoint address supports data transfer in + one direction except the control endpoint + (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents a bulk endpoint. + @param MaximumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength When input, indicates the size, in bytes, of the data buffer + specified by Data. When output, indicates the actually + transferred data size. + @param DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the bulk transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent bulk transfer. + @param TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + TransferResult A pointer to the detailed result information of the + bulk transfer. + + @retval EFI_SUCCESS The bulk transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The bulk transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +**/ + + +EFI_STATUS +EFIAPI +OhciBulkTransfer( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + USB_OHCI_HC_DEV *Ohc; + ED_DESCRIPTOR *HeadEd; + ED_DESCRIPTOR *Ed; + UINT32 DataPidDir; + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *EmptyTd; + EFI_STATUS Status; + UINT8 EndPointNum; + UINTN TimeCount; + OHCI_ED_RESULT EdResult; + + EFI_PCI_IO_PROTOCOL_OPERATION MapOp; + VOID *Mapping; + UINTN MapLength; + EFI_PHYSICAL_ADDRESS MapPyhAddr; + UINTN LeftLength; + UINTN ActualSendLength; + BOOLEAN FirstTD; + + Mapping = NULL; + MapLength = 0; + MapPyhAddr = 0; + LeftLength = 0; + Status = EFI_SUCCESS; + + if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL || + *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) || + (MaxPacketLength != 8 && MaxPacketLength != 16 && + MaxPacketLength != 32 && MaxPacketLength != 64)) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + if ((EndPointAddress & 0x80) != 0) { + DataPidDir = TD_IN_PID; + MapOp = EfiPciIoOperationBusMasterWrite; + } else { + DataPidDir = TD_OUT_PID; + MapOp = EfiPciIoOperationBusMasterRead; + } + + EndPointNum = (EndPointAddress & 0xF); + EdResult.NextToggle = *DataToggle; + + Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + gBS->Stall(20 * 1000); + + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); + + Ed = OhciCreateED (Ohc); + if (Ed == NULL) { + return EFI_OUT_OF_RESOURCES; + } + OhciSetEDField (Ed, ED_SKIP, 1); + OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); + OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); + OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); + OhciSetEDField (Ed, ED_SPEED, HI_SPEED); + OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); + OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); + OhciSetEDField (Ed, ED_PDATA, 0); + OhciSetEDField (Ed, ED_ZERO, 0); + OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); + OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); + OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); + HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL); + + if(Data != NULL) { + MapLength = *DataLength; + Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n")); + goto FREE_ED_BUFF; + } + } + // + //Data Stage + // + LeftLength = MapLength; + ActualSendLength = MapLength; + HeadTd = NULL; + FirstTD = TRUE; + while (LeftLength > 0) { + ActualSendLength = LeftLength; + if (LeftLength > MaxPacketLength) { + ActualSendLength = MaxPacketLength; + } + DataTd = OhciCreateTD (Ohc); + if (DataTd == NULL) { + DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n")); + Status = EFI_OUT_OF_RESOURCES; + goto FREE_OHCI_TDBUFF; + } + OhciSetTDField (DataTd, TD_PDATA, 0); + OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); + OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle); + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); + OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1)); + OhciSetTDField (DataTd, TD_NEXT_PTR, 0); + DataTd->ActualSendLength = (UINT32)ActualSendLength; + DataTd->DataBuffer = (UINT32)MapPyhAddr; + DataTd->NextTDPointer = 0; + if (FirstTD) { + HeadTd = DataTd; + FirstTD = FALSE; + } else { + OhciLinkTD (HeadTd, DataTd); + } + *DataToggle ^= 1; + MapPyhAddr += ActualSendLength; + LeftLength -= ActualSendLength; + } + // + // Empty Stage + // + EmptyTd = OhciCreateTD (Ohc); + if (EmptyTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n")); + goto FREE_OHCI_TDBUFF; + } + OhciSetTDField (EmptyTd, TD_PDATA, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); + OhciSetTDField (EmptyTd, TD_DIR_PID, 0); + OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); + //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); + EmptyTd->Word0.DataToggle = 0; + OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); + OhciSetTDField (EmptyTd, TD_COND_CODE, 0); + OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); + OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); + EmptyTd->ActualSendLength = 0; + EmptyTd->DataBuffer = 0; + EmptyTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, EmptyTd); + Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd; + OhciAttachTDListToED (Ed, HeadTd); + + OhciSetEDField (Ed, ED_SKIP, 0); + Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1); + if (EFI_ERROR(Status)) { + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n")); + goto FREE_OHCI_TDBUFF; + } + Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1); + if (EFI_ERROR(Status)) { + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n")); + goto FREE_OHCI_TDBUFF; + } + gBS->Stall(20 * 1000); + + TimeCount = 0; + Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult); + while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { + gBS->Stall (1000); + TimeCount++; + Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult); + } + + *TransferResult = ConvertErrorCode (EdResult.ErrorCode); + + if (EdResult.ErrorCode != TD_NO_ERROR) { + if (EdResult.ErrorCode == TD_TOBE_PROCESSED) { + DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut)); + } else { + DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n")); + *DataToggle = EdResult.NextToggle; + } + *DataLength = 0; + } else { + DEBUG ((EFI_D_INFO, "Bulk transfer successed\r\n")); + } + //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); + +FREE_OHCI_TDBUFF: + OhciSetEDField (Ed, ED_SKIP, 1); + if (HeadEd == Ed) { + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); + }else { + HeadEd->NextED = Ed->NextED; + } + while (HeadTd) { + DataTd = HeadTd; + HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); + UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); + } + + if(Mapping != NULL) { + Ohc->PciIo->Unmap(Ohc->PciIo, Mapping); + } + +FREE_ED_BUFF: + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + + return Status; +} +/** + + Submits an interrupt transfer to an interrupt endpoint of a USB device. + + @param Ohc Device private data + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint address + supports data transfer in one direction except the + control endpoint (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between + the host and the target interrupt endpoint. + If FALSE, the specified asynchronous interrupt pipe + is canceled. + @param DataToggle A pointer to the data toggle value. On input, it is valid + when IsNewTransfer is TRUE, and it indicates the initial + data toggle value the asynchronous interrupt transfer + should adopt. + On output, it is valid when IsNewTransfer is FALSE, + and it is updated to indicate the data toggle value of + the subsequent asynchronous interrupt transfer. + @param PollingInterval Indicates the interval, in milliseconds, that the + asynchronous interrupt transfer is polled. + This parameter is required when IsNewTransfer is TRUE. + @param UCBuffer Uncacheable buffer + @param DataLength Indicates the length of data to be received at the + rate specified by PollingInterval from the target + asynchronous interrupt endpoint. This parameter + is only required when IsNewTransfer is TRUE. + @param CallBackFunction The Callback function.This function is called at the + rate specified by PollingInterval.This parameter is + only required when IsNewTransfer is TRUE. + @param Context The context that is passed to the CallBackFunction. + This is an optional parameter and may be NULL. + @param IsPeriodic Periodic interrupt or not + @param OutputED The correspoding ED carried out + @param OutputTD The correspoding TD carried out + + + @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully + submitted or canceled. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ + +EFI_STATUS +OhciInterruptTransfer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle OPTIONAL, + IN UINTN PollingInterval OPTIONAL, + IN VOID *UCBuffer OPTIONAL, + IN UINTN DataLength OPTIONAL, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, + IN VOID *Context OPTIONAL, + IN BOOLEAN IsPeriodic OPTIONAL, + OUT ED_DESCRIPTOR **OutputED OPTIONAL, + OUT TD_DESCRIPTOR **OutputTD OPTIONAL + ) +{ + ED_DESCRIPTOR *Ed; + UINT8 EdDir; + ED_DESCRIPTOR *HeadEd; + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *EmptTd; + UINTN Depth; + UINTN Index; + EFI_STATUS Status; + UINT8 EndPointNum; + UINT32 DataPidDir; + INTERRUPT_CONTEXT_ENTRY *Entry; + EFI_TPL OldTpl; + BOOLEAN FirstTD; + + VOID *Mapping; + UINTN MapLength; + EFI_PHYSICAL_ADDRESS MapPyhAddr; + UINTN LeftLength; + UINTN ActualSendLength; + + + if (DataLength > MAX_BYTES_PER_TD) { + DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Error param\r\n")); + return EFI_INVALID_PARAMETER; + } + + if ((EndPointAddress & 0x80) != 0) { + EdDir = ED_IN_DIR; + DataPidDir = TD_IN_PID; + } else { + EdDir = ED_OUT_DIR; + DataPidDir = TD_OUT_PID; + } + + EndPointNum = (EndPointAddress & 0xF); + + if (!IsNewTransfer) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0); + OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle); + Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum); + OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1); + gBS->RestoreTPL (OldTpl); + return Status; + } + MapLength = DataLength; + Status = Ohc->PciIo->Map( + Ohc->PciIo, + EfiPciIoOperationBusMasterWrite, + UCBuffer, + &MapLength, + &MapPyhAddr, + &Mapping + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n")); + goto EXIT; + } + Depth = 5; + Index = 1; + while (PollingInterval >= Index * 2 && Depth > 0) { + Index *= 2; + Depth--; + } + // + //ED Stage + // + HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth); + if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) { + OhciSetEDField (Ed, ED_SKIP, 1); + } else { + Ed = OhciCreateED (Ohc); + if (Ed == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n")); + goto UNMAP_OHCI_XBUFF; + } + OhciSetEDField (Ed, ED_SKIP, 1); + OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); + OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); + OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); + OhciSetEDField (Ed, ED_SPEED, IsSlowDevice); + OhciSetEDField (Ed, ED_FORMAT, 0); + OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); + OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0); + OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); + OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); + OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); + OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd); + } + // + //Data Stage + // + LeftLength = MapLength; + ActualSendLength = MapLength; + HeadTd = NULL; + FirstTD = TRUE; + while (LeftLength > 0) { + ActualSendLength = LeftLength; + if (LeftLength > MaxPacketLength) { + ActualSendLength = MaxPacketLength; + } + DataTd = OhciCreateTD (Ohc); + if (DataTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n")); + goto FREE_OHCI_TDBUFF; + } + OhciSetTDField (DataTd, TD_PDATA, 0); + OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); + OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle); + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); + OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1)); + OhciSetTDField (DataTd, TD_NEXT_PTR, 0); + DataTd->ActualSendLength = (UINT32)ActualSendLength; + DataTd->DataBuffer = (UINT32)MapPyhAddr; + DataTd->NextTDPointer = 0; + if (FirstTD) { + HeadTd = DataTd; + FirstTD = FALSE; + } else { + OhciLinkTD (HeadTd, DataTd); + } + *DataToggle ^= 1; + MapPyhAddr += ActualSendLength; + LeftLength -= ActualSendLength; + } + + EmptTd = OhciCreateTD (Ohc); + if (EmptTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n")); + goto FREE_OHCI_TDBUFF; + } + OhciSetTDField (EmptTd, TD_PDATA, 0); + OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0); + OhciSetTDField (EmptTd, TD_DIR_PID, 0); + OhciSetTDField (EmptTd, TD_DELAY_INT, 0); + //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle); + EmptTd->Word0.DataToggle = 0; + OhciSetTDField (EmptTd, TD_ERROR_CNT, 0); + OhciSetTDField (EmptTd, TD_COND_CODE, 0); + OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0); + OhciSetTDField (EmptTd, TD_NEXT_PTR, 0); + EmptTd->ActualSendLength = 0; + EmptTd->DataBuffer = 0; + EmptTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, EmptTd); + Ed->TdTailPointer = (UINT32)(UINTN)EmptTd; + OhciAttachTDListToED (Ed, HeadTd); + + if (OutputED != NULL) { + *OutputED = Ed; + } + if (OutputTD != NULL) { + *OutputTD = HeadTd; + } + + if (CallBackFunction != NULL) { + Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY)); + if (Entry == NULL) { + goto FREE_OHCI_TDBUFF; + } + + Entry->DeviceAddress = DeviceAddress; + Entry->EndPointAddress = EndPointAddress; + Entry->Ed = Ed; + Entry->DataTd = HeadTd; + Entry->IsSlowDevice = IsSlowDevice; + Entry->MaxPacketLength = MaxPacketLength; + Entry->PollingInterval = PollingInterval; + Entry->CallBackFunction = CallBackFunction; + Entry->Context = Context; + Entry->IsPeriodic = IsPeriodic; + Entry->UCBuffer = UCBuffer; + Entry->UCBufferMapping = Mapping; + Entry->DataLength = DataLength; + Entry->Toggle = DataToggle; + Entry->NextEntry = NULL; + OhciAddInterruptContextEntry (Ohc, Entry); + } + OhciSetEDField (Ed, ED_SKIP, 0); + + if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) { + Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1); + gBS->Stall (1000); + } + + return EFI_SUCCESS; + +FREE_OHCI_TDBUFF: + while (HeadTd) { + DataTd = HeadTd; + HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); + UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); + } + +//FREE_OHCI_EDBUFF: + if ((HeadEd != Ed) && HeadEd && Ed) { + while(HeadEd->NextED != (UINT32)(UINTN)Ed) { + HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED); + } + HeadEd->NextED = Ed->NextED; + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + } + +UNMAP_OHCI_XBUFF: + Ohc->PciIo->Unmap(Ohc->PciIo, Mapping); + +EXIT: + return Status; +} + +/** + + Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint address + supports data transfer in one direction except the + control endpoint (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxiumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between + the host and the target interrupt endpoint. + If FALSE, the specified asynchronous interrupt pipe + is canceled. + @param DataToggle A pointer to the data toggle value. On input, it is valid + when IsNewTransfer is TRUE, and it indicates the initial + data toggle value the asynchronous interrupt transfer + should adopt. + On output, it is valid when IsNewTransfer is FALSE, + and it is updated to indicate the data toggle value of + the subsequent asynchronous interrupt transfer. + @param PollingInterval Indicates the interval, in milliseconds, that the + asynchronous interrupt transfer is polled. + This parameter is required when IsNewTransfer is TRUE. + @param DataLength Indicates the length of data to be received at the + rate specified by PollingInterval from the target + asynchronous interrupt endpoint. This parameter + is only required when IsNewTransfer is TRUE. + @param CallBackFunction The Callback function.This function is called at the + rate specified by PollingInterval.This parameter is + only required when IsNewTransfer is TRUE. + @param Context The context that is passed to the CallBackFunction. + This is an optional parameter and may be NULL. + + @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully + submitted or canceled. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ + + +EFI_STATUS +EFIAPI +OhciAsyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle OPTIONAL, + IN UINTN PollingInterval OPTIONAL, + IN UINTN DataLength OPTIONAL, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, + IN VOID *Context OPTIONAL + ) +{ + EFI_STATUS Status; + USB_OHCI_HC_DEV *Ohc; + VOID *UCBuffer; + + if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 || + (IsNewTransfer && (DataLength == 0 || + (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + if ( IsNewTransfer ) { + UCBuffer = AllocatePool(DataLength); + if (UCBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + UCBuffer = NULL; + } + Status = OhciInterruptTransfer ( + Ohc, + DeviceAddress, + EndPointAddress, + IsSlowDevice, + MaxPacketLength, + IsNewTransfer, + DataToggle, + PollingInterval, + UCBuffer, + DataLength, + CallBackFunction, + Context, + TRUE, + NULL, + NULL + ); + if ( IsNewTransfer ) { + if (EFI_ERROR(Status)) { + gBS->FreePool (UCBuffer); + } + } + return Status; +} + + +/** + + Submits synchronous interrupt transfer to an interrupt endpoint + of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint + address supports data transfer in one direction + except the control endpoint (whose default + endpoint address is 0). It is the caller's responsibility + to make sure that the EndPointAddress represents + an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength On input, the size, in bytes, of the data buffer specified + by Data. On output, the number of bytes transferred. + @param DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the synchronous interrupt + transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent synchronous interrupt transfer. + @param TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information from + the synchronous interrupt transfer. + + @retval EFI_UNSUPPORTED This interface not available. + @retval EFI_INVALID_PARAMETER Parameters not follow spec + +**/ + + +EFI_STATUS +EFIAPI +OhciSyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + ED_DESCRIPTOR *Ed; + TD_DESCRIPTOR *HeadTd; + OHCI_ED_RESULT EdResult; + VOID *UCBuffer; + + if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 || + (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) || + DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + UCBuffer = AllocatePool (*DataLength); + if (UCBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = OhciInterruptTransfer ( + Ohc, + DeviceAddress, + EndPointAddress, + IsSlowDevice, + MaxPacketLength, + TRUE, + DataToggle, + 1, + UCBuffer, + *DataLength, + NULL, + NULL, + FALSE, + &Ed, + &HeadTd + ); + + if (!EFI_ERROR (Status)) { + Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult); + while (Status == EFI_NOT_READY && TimeOut > 0) { + gBS->Stall (1000); + TimeOut--; + Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult); + } + + *TransferResult = ConvertErrorCode (EdResult.ErrorCode); + } + CopyMem(Data, UCBuffer, *DataLength); + Status = OhciInterruptTransfer ( + Ohc, + DeviceAddress, + EndPointAddress, + IsSlowDevice, + MaxPacketLength, + FALSE, + DataToggle, + 0, + NULL, + 0, + NULL, + NULL, + FALSE, + NULL, + NULL + ); + + return Status; +} +/** + + Submits isochronous transfer to a target USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress End point address + @param MaximumPacketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength Indicates the size, in bytes, of the data buffer + specified by Data. + @param TransferResult A pointer to the detailed result information generated + by this control transfer. + + @retval EFI_UNSUPPORTED This interface not available + @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL + +**/ + + +EFI_STATUS +EFIAPI +OhciIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN DataLength, + OUT UINT32 *TransferResult + ) +{ + if (Data == NULL || DataLength == 0 || TransferResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_UNSUPPORTED; +} + +/** + + Submits Async isochronous transfer to a target USB device. + + @param his A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress End point address + @param MaximumPacketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param IsochronousCallBack When the transfer complete, the call back function will be called + @param Context Pass to the call back function as parameter + + @retval EFI_UNSUPPORTED This interface not available + @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0 + +**/ + +EFI_STATUS +EFIAPI +OhciAsyncIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context OPTIONAL + ) +{ + + if (Data == NULL || DataLength == 0) { + return EFI_INVALID_PARAMETER; + } + + return EFI_UNSUPPORTED; +} + +/** + + Retrieves the number of root hub ports. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param NumOfPorts A pointer to the number of the root hub ports. + + @retval EFI_SUCCESS The port number was retrieved successfully. +**/ +EFI_STATUS +EFIAPI +OhciGetRootHubNumOfPorts ( + IN EFI_USB_HC_PROTOCOL *This, + OUT UINT8 *NumOfPorts + ) +{ + USB_OHCI_HC_DEV *Ohc; + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + if (NumOfPorts == NULL) { + return EFI_INVALID_PARAMETER; + } + + *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS); + + return EFI_SUCCESS; +} +/** + + Retrieves the current status of a USB root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL. + @param PortNumber Specifies the root hub port from which the status + is to be retrieved. This value is zero-based. For example, + if a root hub has two ports, then the first port is numbered 0, + and the second port is numbered 1. + @param PortStatus A pointer to the current port status bits and + port status change bits. + + @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber + was returned in PortStatus. + @retval EFI_INVALID_PARAMETER Port number not valid +**/ + + +EFI_STATUS +EFIAPI +OhciGetRootHubPortStatus ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus + ) +{ + USB_OHCI_HC_DEV *Ohc; + UINT8 NumOfPorts; + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + OhciGetRootHubNumOfPorts (This, &NumOfPorts); + if (PortNumber >= NumOfPorts) { + return EFI_INVALID_PARAMETER; + } + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) { + PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_RESET; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_POWER; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) { + PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET; + } + + return EFI_SUCCESS; +} +/** + + Sets a feature for the specified root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL. + @param PortNumber Specifies the root hub port whose feature + is requested to be set. + @param PortFeature Indicates the feature selector associated + with the feature set request. + + @retval EFI_SUCCESS The feature specified by PortFeature was set for the + USB root hub port specified by PortNumber. + @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. +**/ +EFI_STATUS +EFIAPI +OhciSetRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + UINT8 NumOfPorts; + UINTN RetryTimes; + + OhciGetRootHubNumOfPorts (This, &NumOfPorts); + if (PortNumber >= NumOfPorts) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + Status = EFI_SUCCESS; + + + switch (PortFeature) { + case EfiUsbPortPower: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortReset: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 || + OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + + OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); + break; + + case EfiUsbPortEnable: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + + case EfiUsbPortSuspend: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + + Clears a feature for the specified root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param PortNumber Specifies the root hub port whose feature + is requested to be cleared. + @param PortFeature Indicates the feature selector associated with the + feature clear request. + + @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the + USB root hub port specified by PortNumber. + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. + @retval EFI_DEVICE_ERROR Some error happened when clearing feature +**/ +EFI_STATUS +EFIAPI +OhciClearRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + UINT8 NumOfPorts; + UINTN RetryTimes; + + + OhciGetRootHubNumOfPorts (This, &NumOfPorts); + if (PortNumber >= NumOfPorts) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + Status = EFI_SUCCESS; + + switch (PortFeature) { + case EfiUsbPortEnable: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortSuspend: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortReset: + break; + + case EfiUsbPortPower: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortConnectChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortResetChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + + case EfiUsbPortEnableChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortSuspendChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortOverCurrentChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return Status; +} + +EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = { + OHCIDriverBindingSupported, + OHCIDriverBindingStart, + OHCIDriverBindingStop, + 0x10, + NULL, + NULL +}; + + +/** + Entry point for EFI drivers. + + @param ImageHandle EFI_HANDLE. + @param SystemTable EFI_SYSTEM_TABLE. + + @retval EFI_SUCCESS Driver is successfully loaded. + @return Others Failed. + +**/ +EFI_STATUS +EFIAPI +OHCIDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gOhciDriverBinding, + ImageHandle, + &gOhciComponentName, + &gOhciComponentName2 + ); +} + + +/** + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that has UsbHcProtocol installed will be supported. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS This driver supports this device. + @return EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +OHCIDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + USB_CLASSC UsbClassCReg; + // + // Test whether there is PCI IO Protocol attached on the controller handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (USB_CLASSC) / sizeof (UINT8), + &UsbClassCReg + ); + + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + // + // Test whether the controller belongs to OHCI type + // + if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || + (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) || + (UsbClassCReg.ProgInterface != PCI_IF_OHCI) + ) { + + Status = EFI_UNSUPPORTED; + } +ON_EXIT: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; + +} + +/** + + Allocate and initialize the empty OHCI device. + + @param PciIo The PCIIO to use. + @param OriginalPciAttributes The original PCI attributes. + + @return Allocated OHCI device If err, return NULL. + +**/ + +USB_OHCI_HC_DEV * +OhciAllocateDev ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT64 OriginalPciAttributes + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + VOID *Buf; + EFI_PHYSICAL_ADDRESS PhyAddr; + VOID *Map; + UINTN Pages; + UINTN Bytes; + + Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV)); + if (Ohc == NULL) { + return NULL; + } + + Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE; + Ohc->PciIo = PciIo; + + Ohc->UsbHc.Reset = OhciReset; + Ohc->UsbHc.GetState = OhciGetState; + Ohc->UsbHc.SetState = OhciSetState; + Ohc->UsbHc.ControlTransfer = OhciControlTransfer; + Ohc->UsbHc.BulkTransfer = OhciBulkTransfer; + Ohc->UsbHc.AsyncInterruptTransfer = OhciAsyncInterruptTransfer; + Ohc->UsbHc.SyncInterruptTransfer = OhciSyncInterruptTransfer; + Ohc->UsbHc.IsochronousTransfer = OhciIsochronousTransfer; + Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer; + Ohc->UsbHc.GetRootHubPortNumber = OhciGetRootHubNumOfPorts; + Ohc->UsbHc.GetRootHubPortStatus = OhciGetRootHubPortStatus; + Ohc->UsbHc.SetRootHubPortFeature = OhciSetRootHubPortFeature; + Ohc->UsbHc.ClearRootHubPortFeature = OhciClearRootHubPortFeature; + Ohc->UsbHc.MajorRevision = 0x1; + Ohc->UsbHc.MinorRevision = 0x1; + + Ohc->OriginalPciAttributes = OriginalPciAttributes; + + Ohc->HccaMemoryBlock = NULL; + Ohc->HccaMemoryMapping = NULL; + Ohc->HccaMemoryBuf = NULL; + Ohc->HccaMemoryPages = 0; + Ohc->InterruptContextList = NULL; + Ohc->ControllerNameTable = NULL; + Ohc->HouseKeeperTimer = NULL; + + Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0); + if(Ohc->MemPool == NULL) { + goto FREE_DEV_BUFFER; + } + + Bytes = 4096; + Pages = EFI_SIZE_TO_PAGES (Bytes); + + Status = PciIo->AllocateBuffer ( + PciIo, + AllocateAnyPages, + EfiBootServicesData, + Pages, + &Buf, + 0 + ); + + if (EFI_ERROR (Status)) { + goto FREE_MEM_POOL; + } + + Status = PciIo->Map ( + PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + Buf, + &Bytes, + &PhyAddr, + &Map + ); + + if (EFI_ERROR (Status) || (Bytes != 4096)) { + goto FREE_MEM_PAGE; + } + + Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr; + Ohc->HccaMemoryMapping = Map; + Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf; + Ohc->HccaMemoryPages = Pages; + + return Ohc; + +FREE_MEM_PAGE: + PciIo->FreeBuffer (PciIo, Pages, Buf); +FREE_MEM_POOL: + UsbHcFreeMemPool (Ohc->MemPool); +FREE_DEV_BUFFER: + FreePool(Ohc); + + return NULL; +} +/** + + Free the OHCI device and release its associated resources. + + @param Ohc The OHCI device to release. + +**/ +VOID +OhciFreeDev ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + OhciFreeFixedIntMemory (Ohc); + + if (Ohc->HouseKeeperTimer != NULL) { + gBS->CloseEvent (Ohc->HouseKeeperTimer); + } + + if (Ohc->ExitBootServiceEvent != NULL) { + gBS->CloseEvent (Ohc->ExitBootServiceEvent); + } + + if (Ohc->MemPool != NULL) { + UsbHcFreeMemPool (Ohc->MemPool); + } + + if (Ohc->HccaMemoryMapping != NULL ) { + Ohc->PciIo->FreeBuffer (Ohc->PciIo, Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf); + } + + if (Ohc->ControllerNameTable != NULL) { + FreeUnicodeStringTable (Ohc->ControllerNameTable); + } + + FreePool (Ohc); +} +/** + + Uninstall all Ohci Interface. + + @param Controller Controller handle. + @param This Protocol instance pointer. + +**/ +VOID +OhciCleanDevUp ( + IN EFI_HANDLE Controller, + IN EFI_USB_HC_PROTOCOL *This + ) +{ + USB_OHCI_HC_DEV *Ohc; + + // + // Retrieve private context structure + // + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + // + // Uninstall the USB_HC and USB_HC2 protocol + // + gBS->UninstallProtocolInterface ( + Controller, + &gEfiUsbHcProtocolGuid, + &Ohc->UsbHc + ); + + // + // Cancel the timer event + // + gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0); + + // + // Stop the host controller + // + OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0); + This->Reset (This, EFI_USB_HC_RESET_GLOBAL); + This->SetState (This, EfiUsbHcStateHalt); + + // + // Free resources + // + OhciFreeDynamicIntMemory (Ohc); + + // + // Restore original PCI attributes + // + Ohc->PciIo->Attributes ( + Ohc->PciIo, + EfiPciIoAttributeOperationSet, + Ohc->OriginalPciAttributes, + NULL + ); + + // + // Free the private context structure + // + OhciFreeDev (Ohc); +} + +/** + + One notified function to stop the Host Controller when gBS->ExitBootServices() called. + + @param Event Pointer to this event + @param Context Event handler private data +**/ +VOID +EFIAPI +OhcExitBootService ( + EFI_EVENT Event, + VOID *Context + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_USB_HC_PROTOCOL *UsbHc; + Ohc = (USB_OHCI_HC_DEV *) Context; + + UsbHc = &Ohc->UsbHc; + // + // Stop the Host Controller + // + //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); + OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0); + UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL); + UsbHc->SetState (UsbHc, EfiUsbHcStateHalt); + + return; +} + + +/** + Starting the Usb OHCI Driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. + EFI_OUT_OF_RESOURCES- Failed due to resource shortage. + +**/ +EFI_STATUS +EFIAPI +OHCIDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + USB_OHCI_HC_DEV *Ohc; + UINT64 Supports; + UINT64 OriginalPciAttributes; + BOOLEAN PciAttributesSaved; + + // + // Open PCIIO, then enable the HC device and turn off emulation + // + Ohc = NULL; + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + PciAttributesSaved = FALSE; + // + // Save original PCI attributes + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationGet, + 0, + &OriginalPciAttributes + ); + + if (EFI_ERROR (Status)) { + goto CLOSE_PCIIO; + } + PciAttributesSaved = TRUE; + + // + // Robustnesss improvement such as for UoL + // Default is not required. + // + //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) { + // OhciTurnOffUsbEmulation (PciIo); + //} + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + if (!EFI_ERROR (Status)) { + Supports &= EFI_PCI_DEVICE_ENABLE; + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + } + + if (EFI_ERROR (Status)) { + goto CLOSE_PCIIO; + } + // + //Allocate memory for OHC private data structure + // + Ohc = OhciAllocateDev(PciIo, OriginalPciAttributes); + if (Ohc == NULL){ + Status = EFI_OUT_OF_RESOURCES; + goto CLOSE_PCIIO; + } + + //Status = OhciInitializeInterruptList ( Uhc ); + //if (EFI_ERROR (Status)) { + // goto FREE_OHC; + //} + + // + // Set 0.01 s timer + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OhciHouseKeeper, + Ohc, + &Ohc->HouseKeeperTimer + ); + if (EFI_ERROR (Status)) { + goto FREE_OHC; + } + + Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10); + if (EFI_ERROR (Status)) { + goto FREE_OHC; + } + + // + //Install Host Controller Protocol + // + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiUsbHcProtocolGuid, + EFI_NATIVE_INTERFACE, + &Ohc->UsbHc + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Install protocol error")); + goto FREE_OHC; + } + // + // Create event to stop the HC when exit boot service. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OhcExitBootService, + Ohc, + &gEfiEventExitBootServicesGuid, + &Ohc->ExitBootServiceEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Create exit boot event error")); + goto UNINSTALL_USBHC; + } + AddUnicodeString2 ( + "eng", + gOhciComponentName.SupportedLanguages, + &Ohc->ControllerNameTable, + L"Usb Universal Host Controller", + TRUE + ); + AddUnicodeString2 ( + "en", + gOhciComponentName2.SupportedLanguages, + &Ohc->ControllerNameTable, + L"Usb Universal Host Controller", + FALSE + ); + + return EFI_SUCCESS; + +UNINSTALL_USBHC: + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiUsbHcProtocolGuid, + &Ohc->UsbHc, + NULL + ); + +FREE_OHC: + OhciFreeDev (Ohc); + +CLOSE_PCIIO: + if (PciAttributesSaved) { + // + // Restore original PCI attributes + // + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + OriginalPciAttributes, + NULL + ); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; +} + +/** + Stop this driver on ControllerHandle. Support stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +OHCIDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_USB_HC_PROTOCOL *UsbHc; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + (VOID **)&UsbHc, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + OhciCleanDevUp(Controller, UsbHc); + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_SUCCESS; +} + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h new file mode 100644 index 0000000000..4c374ab9e2 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.h @@ -0,0 +1,663 @@ +/** @file +Provides the definition of Usb Hc Protocol and OHCI controller +private data structure. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _OHCI_H +#define _OHCI_H + + +#include + +#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 stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +OHCIDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c new file mode 100644 index 0000000000..cf60794a99 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.c @@ -0,0 +1,78 @@ +/** @file +This file provides the information dump support for OHCI when in debug mode. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + + +/*++ + + Print the data of ED and the TDs attached to the ED + + @param Uhc Pointer to OHCI private data + @param Ed Pointer to a ED to free + @param Td Pointer to the Td head + + @retval EFI_SUCCESS ED + +**/ +EFI_STATUS +OhciDumpEdTdInfo ( + IN USB_OHCI_HC_DEV *Uhc, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *Td, + BOOLEAN Stage + ) +{ + UINT32 Index; + + if (Stage) { + DEBUG ((EFI_D_INFO, "\n Before executing command\n")); + }else{ + DEBUG ((EFI_D_INFO, "\n after executing command\n")); + } + if (Ed != NULL) { + DEBUG ((EFI_D_INFO, "\nED Address:%p, ED buffer:\n", Ed)); + DEBUG ((EFI_D_INFO, "DWord0 :TD Tail :TD Head :Next ED\n")); + for (Index = 0; Index < sizeof (ED_DESCRIPTOR)/4; Index ++) { + DEBUG ((EFI_D_INFO, "%8x ", *((UINT32*)(Ed) + Index) )); + } + DEBUG ((EFI_D_INFO, "\nNext TD buffer:%p\n", Td)); + } + while (Td != NULL) { + if (Td->Word0.DirPID == TD_SETUP_PID) { + DEBUG ((EFI_D_INFO, "\nSetup PID ")); + }else if (Td->Word0.DirPID == TD_OUT_PID) { + DEBUG ((EFI_D_INFO, "\nOut PID ")); + }else if (Td->Word0.DirPID == TD_IN_PID) { + DEBUG ((EFI_D_INFO, "\nIn PID ")); + }else if (Td->Word0.DirPID == TD_NODATA_PID) { + DEBUG ((EFI_D_INFO, "\nNo data PID ")); + } + DEBUG ((EFI_D_INFO, "TD Address:%p, TD buffer:\n", Td)); + DEBUG ((EFI_D_INFO, "DWord0 :CuBuffer:Next TD :Buff End:Next TD :DataBuff:ActLength\n")); + for (Index = 0; Index < sizeof (TD_DESCRIPTOR)/4; Index ++) { + DEBUG ((EFI_D_INFO, "%8x ", *((UINT32*)(Td) + Index) )); + } + DEBUG ((EFI_D_INFO, "\nCurrent TD Data buffer(size%d)\n", (UINT32)Td->ActualSendLength)); + for (Index = 0; Index < Td->ActualSendLength; Index ++) { + DEBUG ((EFI_D_INFO, "%2x ", *(UINT8 *)(UINTN)(Td->DataBuffer + Index) )); + } + Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer); + } + DEBUG ((EFI_D_INFO, "\n TD buffer End\n")); + + return EFI_SUCCESS; +} + + + + + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h new file mode 100644 index 0000000000..a2d79ff7e5 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDebug.h @@ -0,0 +1,42 @@ +/** @file +This file contains the definination for host controller +debug support routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +/*++ + +Routine Description: + + Print the data of ED and the TDs attached to the ED + + @param Uhc Pointer to OHCI private data + @param Ed Pointer to a ED to free + @param Td Pointer to the Td head + + @retval EFI_SUCCESS ED + +**/ +EFI_STATUS +OhciDumpEdTdInfo ( + IN USB_OHCI_HC_DEV *Uhc, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *Td, + BOOLEAN Stage + ); + + + + + + + + + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf new file mode 100644 index 0000000000..9b8f455969 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf @@ -0,0 +1,71 @@ +## @file +# OHCI USB Host Controller UEFI Driver +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = OhciDxe + FILE_GUID = 4ACA697E-F883-446f-98F7-096416FFFFFF + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = OHCIDriverEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# DRIVER_BINDING = gOhciDriverBinding +# COMPONENT_NAME = gOhciComponentName +# COMPONENT_NAME2 = gOhciComponentName2 +# +[Sources] + Descriptor.h + Ohci.c + Ohci.h + OhciSched.c + OhciSched.h + OhciReg.c + OhciReg.h + OhciUrb.c + OhciUrb.h + OhciDebug.c + OhciDebug.h + ComponentName.c + ComponentName.h + UsbHcMem.c + UsbHcMem.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + DebugLib + +[Guids] + gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event + +[Protocols] + gEfiPciIoProtocolGuid ## TO_START + gEfiUsbHcProtocolGuid ## BY_START + +# +# [Event] +# ## +# # Periodic timer event for checking the result of interrupt transfer execution. +# # +# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES +# diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c new file mode 100644 index 0000000000..f9cdd049be --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.c @@ -0,0 +1,1390 @@ +/** @file +The OHCI register operation routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + +/** + + Get OHCI operational reg value + + @param PciIo PciIo protocol instance + @param Offset Offset of the operational reg + + @retval Value of the register + +**/ +UINT32 +OhciGetOperationalReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Offset + ) +{ + UINT32 Value; + + PciIo->Mem.Read(PciIo, EfiPciIoWidthUint32, OHC_BAR_INDEX, Offset, 1, &Value); + + return Value; +} +/** + + Set OHCI operational reg value + + @param PciIo PCI Bus Io protocol instance + @param Offset Offset of the operational reg + @param Value Value to set + + @retval EFI_SUCCESS Value set to the reg + +**/ + + +EFI_STATUS +OhciSetOperationalReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Offset, + IN VOID *Value + ) +{ + EFI_STATUS Status; + + Status = PciIo->Mem.Write(PciIo, EfiPciIoWidthUint32, OHC_BAR_INDEX, Offset, 1, Value); + + return Status; +} +/** + + Get HcRevision reg value + + @param PciIo PCI Bus Io protocol instance + + @retval Value of the register + +**/ + + +UINT32 +OhciGetHcRevision ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + return OhciGetOperationalReg (PciIo, HC_REVISION); +} +/** + + Set HcReset reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field, + IN UINT32 Value + ) +{ + HcRESET Reset; + + *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR); + + if (Field & RESET_SYSTEM_BUS) { + Reset.FSBIR = Value; + } + + if (Field & RESET_HOST_CONTROLLER) { + Reset.FHR = Value; + } + + if (Field & RESET_CLOCK_GENERATION) { + Reset.CGR = Value; + } + + if (Field & RESET_SSE_GLOBAL) { + Reset.SSE = Value; + } + + if (Field & RESET_PSPL) { + Reset.PSPL = Value; + } + + if (Field & RESET_PCPL) { + Reset.PCPL = Value; + } + + if (Field & RESET_SSEP1) { + Reset.SSEP1 = Value; + } + + if (Field & RESET_SSEP2) { + Reset.SSEP2 = Value; + } + + if (Field & RESET_SSEP3) { + Reset.SSEP3 = Value; + } + + OhciSetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR, &Reset); + + return EFI_SUCCESS; +} + +/** + + Get specific field of HcReset reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field + ) +{ + HcRESET Reset; + UINT32 Value; + + + *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR); + Value = 0; + + switch (Field) { + case RESET_SYSTEM_BUS: + Value = Reset.FSBIR; + break; + + case RESET_HOST_CONTROLLER: + Value = Reset.FHR; + break; + + case RESET_CLOCK_GENERATION: + Value = Reset.CGR; + break; + + case RESET_SSE_GLOBAL: + Value = Reset.SSE; + break; + + case RESET_PSPL: + Value = Reset.PSPL; + break; + + case RESET_PCPL: + Value = Reset.PCPL; + break; + + case RESET_SSEP1: + Value = Reset.SSEP1; + break; + + case RESET_SSEP2: + Value = Reset.SSEP2; + break; + + case RESET_SSEP3: + Value = Reset.SSEP3; + break; + + default: + ASSERT (FALSE); + } + + + return Value; +} + +/** + + Set HcControl reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcCONTROL Control; + + + + *(UINT32 *) &Control = OhciGetOperationalReg (Ohc->PciIo, HC_CONTROL); + + if (Field & CONTROL_BULK_RATIO) { + Control.ControlBulkRatio = Value; + } + + if (Field & HC_FUNCTIONAL_STATE) { + Control.FunctionalState = Value; + } + + if (Field & PERIODIC_ENABLE) { + Control.PeriodicEnable = Value; + } + + if (Field & CONTROL_ENABLE) { + Control.ControlEnable = Value; + } + + if (Field & ISOCHRONOUS_ENABLE) { + Control.IsochronousEnable = Value; + } + + if (Field & BULK_ENABLE) { + Control.BulkEnable = Value; + } + + if (Field & INTERRUPT_ROUTING) { + Control.InterruptRouting = Value; + } + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_CONTROL, &Control); + + return Status; +} + + +/** + + Get specific field of HcControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + + +UINT32 +OhciGetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcCONTROL Control; + + *(UINT32 *) &Control = OhciGetOperationalReg (Ohc->PciIo, HC_CONTROL); + + switch (Field) { + case CONTROL_BULK_RATIO: + return Control.ControlBulkRatio; + break; + case PERIODIC_ENABLE: + return Control.PeriodicEnable; + break; + case CONTROL_ENABLE: + return Control.ControlEnable; + break; + case BULK_ENABLE: + return Control.BulkEnable; + break; + case ISOCHRONOUS_ENABLE: + return Control.IsochronousEnable; + break; + case HC_FUNCTIONAL_STATE: + return Control.FunctionalState; + break; + case INTERRUPT_ROUTING: + return Control.InterruptRouting; + break; + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set HcCommand reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcCOMMAND_STATUS CommandStatus; + + ZeroMem (&CommandStatus, sizeof (HcCOMMAND_STATUS)); + + if(Field & HC_RESET){ + CommandStatus.HcReset = Value; + } + + if(Field & CONTROL_LIST_FILLED){ + CommandStatus.ControlListFilled = Value; + } + + if(Field & BULK_LIST_FILLED){ + CommandStatus.BulkListFilled = Value; + } + + if(Field & CHANGE_OWNER_REQUEST){ + CommandStatus.ChangeOwnerRequest = Value; + } + + if(Field & SCHEDULE_OVERRUN_COUNT){ + CommandStatus.ScheduleOverrunCount = Value; + } + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS, &CommandStatus); + + return Status; +} + +/** + + Get specific field of HcCommand reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcCOMMAND_STATUS CommandStatus; + + *(UINT32 *) &CommandStatus = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS); + + switch (Field){ + case HC_RESET: + return CommandStatus.HcReset; + break; + case CONTROL_LIST_FILLED: + return CommandStatus.ControlListFilled; + break; + case BULK_LIST_FILLED: + return CommandStatus.BulkListFilled; + break; + case CHANGE_OWNER_REQUEST: + return CommandStatus.ChangeOwnerRequest; + break; + case SCHEDULE_OVERRUN_COUNT: + return CommandStatus.ScheduleOverrunCount; + break; + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Clear specific fields of Interrupt Status + + @param Ohc UHC private data + @param Field Field to clear + + @retval EFI_SUCCESS Fields cleared + +**/ + +EFI_STATUS +OhciClearInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + EFI_STATUS Status; + HcINTERRUPT_STATUS InterruptStatus; + + ZeroMem (&InterruptStatus, sizeof (HcINTERRUPT_STATUS)); + + if(Field & SCHEDULE_OVERRUN){ + InterruptStatus.SchedulingOverrun = 1; + } + + if(Field & WRITEBACK_DONE_HEAD){ + InterruptStatus.WriteBackDone = 1; + } + if(Field & START_OF_FRAME){ + InterruptStatus.Sof = 1; + } + + if(Field & RESUME_DETECT){ + InterruptStatus.ResumeDetected = 1; + } + + if(Field & UNRECOVERABLE_ERROR){ + InterruptStatus.UnrecoverableError = 1; + } + + if(Field & FRAME_NUMBER_OVERFLOW){ + InterruptStatus.FrameNumOverflow = 1; + } + + if(Field & ROOTHUB_STATUS_CHANGE){ + InterruptStatus.RHStatusChange = 1; + } + + if(Field & OWNERSHIP_CHANGE){ + InterruptStatus.OwnerChange = 1; + } + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_STATUS, &InterruptStatus); + + return Status; +} + +/** + + Get fields of HcInterrupt reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcINTERRUPT_STATUS InterruptStatus; + + *(UINT32 *) &InterruptStatus = OhciGetOperationalReg (Ohc->PciIo, HC_INTERRUPT_STATUS); + + switch (Field){ + case SCHEDULE_OVERRUN: + return InterruptStatus.SchedulingOverrun; + break; + + case WRITEBACK_DONE_HEAD: + return InterruptStatus.WriteBackDone; + break; + + case START_OF_FRAME: + return InterruptStatus.Sof; + break; + + case RESUME_DETECT: + return InterruptStatus.ResumeDetected; + break; + + case UNRECOVERABLE_ERROR: + return InterruptStatus.UnrecoverableError; + break; + + case FRAME_NUMBER_OVERFLOW: + return InterruptStatus.FrameNumOverflow; + break; + + case ROOTHUB_STATUS_CHANGE: + return InterruptStatus.RHStatusChange; + break; + + case OWNERSHIP_CHANGE: + return InterruptStatus.OwnerChange; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set Interrupt Control reg value + + @param Ohc UHC private data + @param StatEnable Enable or Disable + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN BOOLEAN StatEnable, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcINTERRUPT_CONTROL InterruptState; + + + ZeroMem (&InterruptState, sizeof (HcINTERRUPT_CONTROL)); + + if(Field & SCHEDULE_OVERRUN) { + InterruptState.SchedulingOverrunInt = Value; + } + + if(Field & WRITEBACK_DONE_HEAD) { + InterruptState.WriteBackDoneInt = Value; + } + if(Field & START_OF_FRAME) { + InterruptState.SofInt = Value; + } + + if(Field & RESUME_DETECT) { + InterruptState.ResumeDetectedInt = Value; + } + + if(Field & UNRECOVERABLE_ERROR) { + InterruptState.UnrecoverableErrorInt = Value; + } + + if(Field & FRAME_NUMBER_OVERFLOW) { + InterruptState.FrameNumOverflowInt = Value; + } + + if(Field & ROOTHUB_STATUS_CHANGE) { + InterruptState.RHStatusChangeInt = Value; + } + + if(Field & OWNERSHIP_CHANGE) { + InterruptState.OwnerChangedInt = Value; + } + + if(Field & MASTER_INTERRUPT) { + InterruptState.MasterInterruptEnable = Value; + } + + if (StatEnable) { + Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_ENABLE, &InterruptState); + } else { + Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_DISABLE, &InterruptState); + } + + return Status; +} + +/** + + Get field of HcInterruptControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcINTERRUPT_CONTROL InterruptState; + + *(UINT32 *) &InterruptState = OhciGetOperationalReg (Ohc->PciIo, HC_INTERRUPT_ENABLE); + + switch (Field){ + case SCHEDULE_OVERRUN: + return InterruptState.SchedulingOverrunInt; + break; + + case WRITEBACK_DONE_HEAD: + return InterruptState.WriteBackDoneInt; + break; + + case START_OF_FRAME: + return InterruptState.SofInt; + break; + + case RESUME_DETECT: + return InterruptState.ResumeDetectedInt; + break; + + case UNRECOVERABLE_ERROR: + return InterruptState.UnrecoverableErrorInt; + break; + + case FRAME_NUMBER_OVERFLOW: + return InterruptState.FrameNumOverflowInt; + break; + + case ROOTHUB_STATUS_CHANGE: + return InterruptState.RHStatusChangeInt; + break; + + case OWNERSHIP_CHANGE: + return InterruptState.OwnerChangedInt; + break; + + case MASTER_INTERRUPT: + return InterruptState.MasterInterruptEnable; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of the pointer to set + @param Value Value to set + + @retval EFI_SUCCESS Memory pointer set + +**/ + +EFI_STATUS +OhciSetMemoryPointer( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 PointerType, + IN VOID *Value + ) +{ + EFI_STATUS Status; + UINT32 Verify; + + Status = OhciSetOperationalReg (Ohc->PciIo, PointerType, &Value); + + if (EFI_ERROR (Status)) { + return Status; + } + + Verify = OhciGetOperationalReg (Ohc->PciIo, PointerType); + + while (Verify != (UINT32)(UINTN) Value) { + gBS->Stall(1000); + Verify = OhciGetOperationalReg (Ohc->PciIo, PointerType); + }; + + + return Status; +} + +/** + + Get memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of pointer + + @retval Memory pointer of the specific type + +**/ + +VOID * +OhciGetMemoryPointer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 PointerType + ) +{ + + return (VOID *)(UINTN) OhciGetOperationalReg (Ohc->PciIo, PointerType); +} + + +/** + + Set Frame Interval value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcFRM_INTERVAL FrameInterval; + + + *(UINT32 *) &FrameInterval = OhciGetOperationalReg(Ohc->PciIo, HC_FRM_INTERVAL); + + if (Field & FRAME_INTERVAL) { + FrameInterval.FrmIntervalToggle = !FrameInterval.FrmIntervalToggle; + FrameInterval.FrameInterval = Value; + } + + if (Field & FS_LARGEST_DATA_PACKET) { + FrameInterval.FSMaxDataPacket = Value; + } + + if (Field & FRMINT_TOGGLE) { + FrameInterval.FrmIntervalToggle = Value; + } + + Status = OhciSetOperationalReg ( + Ohc->PciIo, + HC_FRM_INTERVAL, + &FrameInterval + ); + + return Status; +} + + +/** + + Get field of frame interval reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcFRM_INTERVAL FrameInterval; + + *(UINT32 *) &FrameInterval = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_INTERVAL); + + switch (Field){ + case FRAME_INTERVAL: + return FrameInterval.FrameInterval; + break; + + case FS_LARGEST_DATA_PACKET: + return FrameInterval.FSMaxDataPacket; + break; + + case FRMINT_TOGGLE: + return FrameInterval.FrmIntervalToggle; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set Frame Remaining reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcFRAME_REMAINING FrameRemaining; + + + *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING); + + FrameRemaining.FrameRemaining = Value; + FrameRemaining.FrameRemainingToggle = !FrameRemaining.FrameRemainingToggle; + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING, &FrameRemaining); + + return Status; +} +/** + + Get value of frame remaining reg + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of frame remaining reg + +**/ +UINT32 +OhciGetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) + +{ + HcFRAME_REMAINING FrameRemaining; + + + *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING); + + switch (Field){ + case FRAME_REMAINING: + return FrameRemaining.FrameRemaining; + break; + + case FRAME_REMAIN_TOGGLE: + return FrameRemaining.FrameRemainingToggle; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set frame number reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameNumber( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_FRM_NUMBER, &Value); + + return Status; +} + +/** + + Get frame number reg value + + @param Ohc UHC private data + + @retval Value of frame number reg + +**/ + +UINT32 +OhciGetFrameNumber ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg(Ohc->PciIo, HC_FRM_NUMBER); +} + +/** + + Set period start reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_PERIODIC_START, &Value); + + return Status; +} + + +/** + + Get periodic start reg value + + @param Ohc UHC private data + + @param Value of periodic start reg + +**/ + +UINT32 +OhciGetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg(Ohc->PciIo, HC_PERIODIC_START); +} + + +/** + + Set Ls Threshold reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_LS_THREASHOLD, &Value); + + return Status; +} + + +/** + + Get Ls Threshold reg value + + @param Ohc UHC private data + + @retval Value of Ls Threshold reg + +**/ + +UINT32 +OhciGetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg(Ohc->PciIo, HC_LS_THREASHOLD); +} + +/** + + Set Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcRH_DESC_A DescriptorA; + HcRH_DESC_B DescriptorB; + + + if (Field & (RH_DEV_REMOVABLE | RH_PORT_PWR_CTRL_MASK)) { + *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_B); + + if(Field & RH_DEV_REMOVABLE) { + DescriptorB.DeviceRemovable = Value; + } + if(Field & RH_PORT_PWR_CTRL_MASK) { + DescriptorB.PortPowerControlMask = Value; + } + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_DESC_B, &DescriptorB); + + return Status; + } + + *(UINT32 *)&DescriptorA = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_A); + + if(Field & RH_NUM_DS_PORTS) { + DescriptorA.NumDownStrmPorts = Value; + } + if(Field & RH_NO_PSWITCH) { + DescriptorA.NoPowerSwitch = Value; + } + if(Field & RH_PSWITCH_MODE) { + DescriptorA.PowerSwitchMode = Value; + } + if(Field & RH_DEVICE_TYPE) { + DescriptorA.DeviceType = Value; + } + if(Field & RH_OC_PROT_MODE) { + DescriptorA.OverCurrentProtMode = Value; + } + if(Field & RH_NOC_PROT) { + DescriptorA.NoOverCurrentProtMode = Value; + } + if(Field & RH_NO_POTPGT) { + DescriptorA.PowerOnToPowerGoodTime = Value; + } + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_DESC_A, &DescriptorA); + + return Status; +} + + +/** + + Get Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcRH_DESC_A DescriptorA; + HcRH_DESC_B DescriptorB; + + + *(UINT32 *) &DescriptorA = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_A); + *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_B); + + switch (Field){ + case RH_DEV_REMOVABLE: + return DescriptorB.DeviceRemovable; + break; + + case RH_PORT_PWR_CTRL_MASK: + return DescriptorB.PortPowerControlMask; + break; + + case RH_NUM_DS_PORTS: + return DescriptorA.NumDownStrmPorts; + break; + + case RH_NO_PSWITCH: + return DescriptorA.NoPowerSwitch; + break; + + case RH_PSWITCH_MODE: + return DescriptorA.PowerSwitchMode; + break; + + case RH_DEVICE_TYPE: + return DescriptorA.DeviceType; + break; + + case RH_OC_PROT_MODE: + return DescriptorA.OverCurrentProtMode; + break; + + case RH_NOC_PROT: + return DescriptorA.NoOverCurrentProtMode; + break; + + case RH_NO_POTPGT: + return DescriptorA.PowerOnToPowerGoodTime; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + + +/** + + Set Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + EFI_STATUS Status; + HcRH_STATUS RootHubStatus; + + + ZeroMem (&RootHubStatus, sizeof(HcRH_STATUS)); + + if(Field & RH_LOCAL_PSTAT){ + RootHubStatus.LocalPowerStat = 1; + } + if(Field & RH_OC_ID){ + RootHubStatus.OverCurrentIndicator = 1; + } + if(Field & RH_REMOTE_WK_ENABLE){ + RootHubStatus.DevRemoteWakeupEnable = 1; + } + if(Field & RH_LOCAL_PSTAT_CHANGE){ + RootHubStatus.LocalPowerStatChange = 1; + } + if(Field & RH_OC_ID_CHANGE){ + RootHubStatus.OverCurrentIndicatorChange = 1; + } + if(Field & RH_CLR_RMT_WK_ENABLE){ + RootHubStatus.ClearRemoteWakeupEnable = 1; + } + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_STATUS, &RootHubStatus); + + return Status; +} + + +/** + + Get Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcRH_STATUS RootHubStatus; + + + *(UINT32 *) &RootHubStatus = OhciGetOperationalReg (Ohc->PciIo, HC_RH_STATUS); + + switch (Field) { + case RH_LOCAL_PSTAT: + return RootHubStatus.LocalPowerStat; + break; + case RH_OC_ID: + return RootHubStatus.OverCurrentIndicator; + break; + case RH_REMOTE_WK_ENABLE: + return RootHubStatus.DevRemoteWakeupEnable; + break; + case RH_LOCAL_PSTAT_CHANGE: + return RootHubStatus.LocalPowerStatChange; + break; + case RH_OC_ID_CHANGE: + return RootHubStatus.OverCurrentIndicatorChange; + break; + case RH_CLR_RMT_WK_ENABLE: + return RootHubStatus.ClearRemoteWakeupEnable; + break; + default: + ASSERT (FALSE); + } + + return 0; +} + + +/** + + Set Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ) +{ + EFI_STATUS Status; + HcRHPORT_STATUS PortStatus; + + + ZeroMem (&PortStatus, sizeof(HcRHPORT_STATUS)); + + if (Field & RH_CLEAR_PORT_ENABLE) { + PortStatus.CurrentConnectStat = 1; + } + if (Field & RH_SET_PORT_ENABLE) { + PortStatus.EnableStat = 1; + } + if (Field & RH_SET_PORT_SUSPEND) { + PortStatus.SuspendStat = 1; + } + if (Field & RH_CLEAR_SUSPEND_STATUS) { + PortStatus.OCIndicator = 1; + } + if (Field & RH_SET_PORT_RESET) { + PortStatus.ResetStat = 1; + } + if (Field & RH_SET_PORT_POWER) { + PortStatus.PowerStat = 1; + } + if (Field & RH_CLEAR_PORT_POWER) { + PortStatus.LsDeviceAttached = 1; + } + if (Field & RH_CONNECT_STATUS_CHANGE) { + PortStatus.ConnectStatChange = 1; + } + if (Field & RH_PORT_ENABLE_STAT_CHANGE) { + PortStatus.EnableStatChange = 1; + } + if (Field & RH_PORT_SUSPEND_STAT_CHANGE) { + PortStatus.SuspendStatChange = 1; + } + if (Field & RH_OC_INDICATOR_CHANGE) { + PortStatus.OCIndicatorChange = 1; + } + if (Field & RH_PORT_RESET_STAT_CHANGE ) { + PortStatus.ResetStatChange = 1; + } + + Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_PORT_STATUS + (Index * 4), &PortStatus); + + return Status; +} + + +/** + + Get Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to get + + @retval Value of the field and index + +**/ + +UINT32 +OhciReadRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ) +{ + HcRHPORT_STATUS PortStatus; + + *(UINT32 *) &PortStatus = OhciGetOperationalReg ( + Ohc->PciIo, + HC_RH_PORT_STATUS + (Index * 4) + ); + + switch (Field){ + case RH_CURR_CONNECT_STAT: + return PortStatus.CurrentConnectStat; + break; + case RH_PORT_ENABLE_STAT: + return PortStatus.EnableStat; + break; + case RH_PORT_SUSPEND_STAT: + return PortStatus.SuspendStat; + break; + case RH_PORT_OC_INDICATOR: + return PortStatus.OCIndicator; + break; + case RH_PORT_RESET_STAT: + return PortStatus.ResetStat; + break; + case RH_PORT_POWER_STAT: + return PortStatus.PowerStat; + break; + case RH_LSDEVICE_ATTACHED: + return PortStatus.LsDeviceAttached; + break; + case RH_CONNECT_STATUS_CHANGE: + return PortStatus.ConnectStatChange; + break; + case RH_PORT_ENABLE_STAT_CHANGE: + return PortStatus.EnableStatChange; + break; + case RH_PORT_SUSPEND_STAT_CHANGE: + return PortStatus.SuspendStatChange; + break; + case RH_OC_INDICATOR_CHANGE: + return PortStatus.OCIndicatorChange; + break; + case RH_PORT_RESET_STAT_CHANGE: + return PortStatus.ResetStatChange; + break; + default: + ASSERT (FALSE); + } + + return 0; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h new file mode 100644 index 0000000000..e4d1008053 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciReg.h @@ -0,0 +1,920 @@ +/** @file +This file contains the definination for host controller +register operation routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _OHCI_REG_H +#define _OHCI_REG_H + +#define HC_STATE_RESET 0x0 +#define HC_STATE_RESUME 0x1 +#define HC_STATE_OPERATIONAL 0x2 +#define HC_STATE_SUSPEND 0x3 + +#define PERIODIC_ENABLE 0x01 +#define ISOCHRONOUS_ENABLE 0x02 +#define CONTROL_ENABLE 0x04 +#define BULK_ENABLE 0x08 +#define CONTROL_BULK_RATIO 0x10 + +#define HC_FUNCTIONAL_STATE 0x20 +#define INTERRUPT_ROUTING 0x40 + +#define HC_RESET 0x01 +#define CONTROL_LIST_FILLED 0x02 +#define BULK_LIST_FILLED 0x04 +#define CHANGE_OWNER_REQUEST 0x08 + +#define SCHEDULE_OVERRUN_COUNT 0x10 + +#define SCHEDULE_OVERRUN 0x00001 +#define WRITEBACK_DONE_HEAD 0x00002 +#define START_OF_FRAME 0x00004 +#define RESUME_DETECT 0x00008 +#define UNRECOVERABLE_ERROR 0x00010 +#define FRAME_NUMBER_OVERFLOW 0x00020 +#define ROOTHUB_STATUS_CHANGE 0x00040 +#define OWNERSHIP_CHANGE 0x00080 + +#define MASTER_INTERRUPT 0x00400 + +#define CONTROL_HEAD 0x001 +#define BULK_HEAD 0x002 +#define DONE_HEAD 0x004 + +#define Hc_HCCA 0x001 +#define Hc_PERIODIC_CURRENT 0x002 +#define Hc_CONTOL_HEAD 0x004 +#define Hc_CONTROL_CURRENT_PTR 0x008 +#define Hc_BULK_HEAD 0x010 +#define Hc_BULK_CURRENT_PTR 0x020 +#define Hc_DONE_HEAD 0x040 + +#define FRAME_INTERVAL 0x008 +#define FS_LARGEST_DATA_PACKET 0x010 +#define FRMINT_TOGGLE 0x020 +#define FRAME_REMAINING 0x040 +#define FRAME_REMAIN_TOGGLE 0x080 + +#define RH_DESC_A 0x00001 +#define RH_DESC_B 0x00002 +#define RH_NUM_DS_PORTS 0x00004 +#define RH_NO_PSWITCH 0x00008 +#define RH_PSWITCH_MODE 0x00010 +#define RH_DEVICE_TYPE 0x00020 +#define RH_OC_PROT_MODE 0x00040 +#define RH_NOC_PROT 0x00080 +#define RH_POTPGT 0x00100 +#define RH_NO_POTPGT 0x00200 +#define RH_DEV_REMOVABLE 0x00400 +#define RH_PORT_PWR_CTRL_MASK 0x00800 + +#define RH_LOCAL_PSTAT 0x00001 +#define RH_OC_ID 0x00002 +#define RH_REMOTE_WK_ENABLE 0x00004 +#define RH_LOCAL_PSTAT_CHANGE 0x00008 +#define RH_OC_ID_CHANGE 0x00010 +#define RH_CLR_RMT_WK_ENABLE 0x00020 + +#define RH_CLEAR_PORT_ENABLE 0x0001 +#define RH_SET_PORT_ENABLE 0x0002 +#define RH_SET_PORT_SUSPEND 0x0004 +#define RH_CLEAR_SUSPEND_STATUS 0x0008 +#define RH_SET_PORT_RESET 0x0010 +#define RH_SET_PORT_POWER 0x0020 +#define RH_CLEAR_PORT_POWER 0x0040 +#define RH_CONNECT_STATUS_CHANGE 0x10000 +#define RH_PORT_ENABLE_STAT_CHANGE 0x20000 +#define RH_PORT_SUSPEND_STAT_CHANGE 0x40000 +#define RH_OC_INDICATOR_CHANGE 0x80000 +#define RH_PORT_RESET_STAT_CHANGE 0x100000 + +#define RH_CURR_CONNECT_STAT 0x0001 +#define RH_PORT_ENABLE_STAT 0x0002 +#define RH_PORT_SUSPEND_STAT 0x0004 +#define RH_PORT_OC_INDICATOR 0x0008 +#define RH_PORT_RESET_STAT 0x0010 +#define RH_PORT_POWER_STAT 0x0020 +#define RH_LSDEVICE_ATTACHED 0x0040 + +#define RESET_SYSTEM_BUS (1 << 0) +#define RESET_HOST_CONTROLLER (1 << 1) +#define RESET_CLOCK_GENERATION (1 << 2) +#define RESET_SSE_GLOBAL (1 << 5) +#define RESET_PSPL (1 << 6) +#define RESET_PCPL (1 << 7) +#define RESET_SSEP1 (1 << 9) +#define RESET_SSEP2 (1 << 10) +#define RESET_SSEP3 (1 << 11) + +#define ONE_SECOND 1000000 +#define ONE_MILLI_SEC 1000 +#define MAX_BYTES_PER_TD 0x1000 +#define MAX_RETRY_TIMES 100 +#define PORT_NUMBER_ON_MAINSTONE2 1 + + +// +// Operational Register Offsets +// + +// +// Command & Status Registers Offsets +// +#define HC_REVISION 0x00 +#define HC_CONTROL 0x04 +#define HC_COMMAND_STATUS 0x08 +#define HC_INTERRUPT_STATUS 0x0C +#define HC_INTERRUPT_ENABLE 0x10 +#define HC_INTERRUPT_DISABLE 0x14 + +// +// Memory Pointer Offsets +// +#define HC_HCCA 0x18 +#define HC_PERIODIC_CURRENT 0x1C +#define HC_CONTROL_HEAD 0x20 +#define HC_CONTROL_CURRENT_PTR 0x24 +#define HC_BULK_HEAD 0x28 +#define HC_BULK_CURRENT_PTR 0x2C +#define HC_DONE_HEAD 0x30 + +// +// Frame Register Offsets +// +#define HC_FRM_INTERVAL 0x34 +#define HC_FRM_REMAINING 0x38 +#define HC_FRM_NUMBER 0x3C +#define HC_PERIODIC_START 0x40 +#define HC_LS_THREASHOLD 0x44 + +// +// Root Hub Register Offsets +// +#define HC_RH_DESC_A 0x48 +#define HC_RH_DESC_B 0x4C +#define HC_RH_STATUS 0x50 +#define HC_RH_PORT_STATUS 0x54 + +#define USBHOST_OFFSET_UHCHR 0x64 // Usb Host reset register + +#define OHC_BAR_INDEX 0 + +// +// Usb Host controller register offset +// +#define USBHOST_OFFSET_UHCREV 0x0 // Usb Host revision register +#define USBHOST_OFFSET_UHCHCON 0x4 // Usb Host control register +#define USBHOST_OFFSET_UHCCOMS 0x8 // Usb Host Command Status register +#define USBHOST_OFFSET_UHCINTS 0xC // Usb Host Interrupt Status register +#define USBHOST_OFFSET_UHCINTE 0x10 // Usb Host Interrupt Enable register +#define USBHOST_OFFSET_UHCINTD 0x14 // Usb Host Interrupt Disable register +#define USBHOST_OFFSET_UHCHCCA 0x18 // Usb Host Controller Communication Area +#define USBHOST_OFFSET_UHCPCED 0x1C // Usb Host Period Current Endpoint Descriptor +#define USBHOST_OFFSET_UHCCHED 0x20 // Usb Host Control Head Endpoint Descriptor +#define USBHOST_OFFSET_UHCCCED 0x24 // Usb Host Control Current Endpoint Descriptor +#define USBHOST_OFFSET_UHCBHED 0x28 // Usb Host Bulk Head Endpoint Descriptor +#define USBHOST_OFFSET_UHCBCED 0x2C // Usb Host Bulk Current Endpoint Descriptor +#define USBHOST_OFFSET_UHCDHEAD 0x30 // Usb Host Done Head register +#define USBHOST_OFFSET_UHCFMI 0x34 // Usb Host Frame Interval register +#define USBHOST_OFFSET_UHCFMR 0x38 // Usb Host Frame Remaining register +#define USBHOST_OFFSET_UHCFMN 0x3C // Usb Host Frame Number register +#define USBHOST_OFFSET_UHCPERS 0x40 // Usb Host Periodic Start register +#define USBHOST_OFFSET_UHCLST 0x44 // Usb Host Low-Speed Threshold register +#define USBHOST_OFFSET_UHCRHDA 0x48 // Usb Host Root Hub Descriptor A register +#define USBHOST_OFFSET_UHCRHDB 0x4C // Usb Host Root Hub Descriptor B register +#define USBHOST_OFFSET_UHCRHS 0x50 // Usb Host Root Hub Status register +#define USBHOST_OFFSET_UHCRHPS1 0x54 // Usb Host Root Hub Port Status 1 register + +// +// Usb Host controller register bit fields +// +#pragma pack(1) + +typedef struct { + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseCode; +} USB_CLASSC; + +typedef struct { + UINT32 Revision:8; + UINT32 Rsvd:24; +} HcREVISION; + +typedef struct { + UINT32 ControlBulkRatio:2; + UINT32 PeriodicEnable:1; + UINT32 IsochronousEnable:1; + UINT32 ControlEnable:1; + UINT32 BulkEnable:1; + UINT32 FunctionalState:2; + UINT32 InterruptRouting:1; + UINT32 RemoteWakeup:1; + UINT32 RemoteWakeupEnable:1; + UINT32 Reserved:21; +} HcCONTROL; + +typedef struct { + UINT32 HcReset:1; + UINT32 ControlListFilled:1; + UINT32 BulkListFilled:1; + UINT32 ChangeOwnerRequest:1; + UINT32 Reserved1:12; + UINT32 ScheduleOverrunCount:2; + UINT32 Reserved:14; +} HcCOMMAND_STATUS; + +typedef struct { + UINT32 SchedulingOverrun:1; + UINT32 WriteBackDone:1; + UINT32 Sof:1; + UINT32 ResumeDetected:1; + UINT32 UnrecoverableError:1; + UINT32 FrameNumOverflow:1; + UINT32 RHStatusChange:1; + UINT32 Reserved1:23; + UINT32 OwnerChange:1; + UINT32 Reserved2:1; +} HcINTERRUPT_STATUS; + +typedef struct { + UINT32 SchedulingOverrunInt:1; + UINT32 WriteBackDoneInt:1; + UINT32 SofInt:1; + UINT32 ResumeDetectedInt:1; + UINT32 UnrecoverableErrorInt:1; + UINT32 FrameNumOverflowInt:1; + UINT32 RHStatusChangeInt:1; + UINT32 Reserved:23; + UINT32 OwnerChangedInt:1; + UINT32 MasterInterruptEnable:1; +} HcINTERRUPT_CONTROL; + +typedef struct { + UINT32 Rerserved:8; + UINT32 Hcca:24; +} HcHCCA; + +typedef struct { + UINT32 Reserved:4; + UINT32 MemoryPtr:28; +} HcMEMORY_PTR; + +typedef struct { + UINT32 FrameInterval:14; + UINT32 Reserved:2; + UINT32 FSMaxDataPacket:15; + UINT32 FrmIntervalToggle:1; +} HcFRM_INTERVAL; + +typedef struct { + UINT32 FrameRemaining:14; + UINT32 Reserved:17; + UINT32 FrameRemainingToggle:1; +} HcFRAME_REMAINING; + +typedef struct { + UINT32 FrameNumber:16; + UINT32 Reserved:16; +} HcFRAME_NUMBER; + +typedef struct { + UINT32 PeriodicStart:14; + UINT32 Reserved:18; +} HcPERIODIC_START; + +typedef struct { + UINT32 LsThreshold:12; + UINT32 Reserved:20; +} HcLS_THRESHOLD; + +typedef struct { + UINT32 NumDownStrmPorts:8; + UINT32 PowerSwitchMode:1; + UINT32 NoPowerSwitch:1; + UINT32 DeviceType:1; + UINT32 OverCurrentProtMode:1; + UINT32 NoOverCurrentProtMode:1; + UINT32 Reserved:11; + UINT32 PowerOnToPowerGoodTime:8; +} HcRH_DESC_A; + +typedef struct { + UINT32 DeviceRemovable:16; + UINT32 PortPowerControlMask:16; +} HcRH_DESC_B; + +typedef struct { + UINT32 LocalPowerStat:1; + UINT32 OverCurrentIndicator:1; + UINT32 Reserved1:13; + UINT32 DevRemoteWakeupEnable:1; + UINT32 LocalPowerStatChange:1; + UINT32 OverCurrentIndicatorChange:1; + UINT32 Reserved2:13; + UINT32 ClearRemoteWakeupEnable:1; +} HcRH_STATUS; + +typedef struct { + UINT32 CurrentConnectStat:1; + UINT32 EnableStat:1; + UINT32 SuspendStat:1; + UINT32 OCIndicator:1; + UINT32 ResetStat:1; + UINT32 Reserved1:3; + UINT32 PowerStat:1; + UINT32 LsDeviceAttached:1; + UINT32 Reserved2:6; + UINT32 ConnectStatChange:1; + UINT32 EnableStatChange:1; + UINT32 SuspendStatChange:1; + UINT32 OCIndicatorChange:1; + UINT32 ResetStatChange:1; + UINT32 Reserved3:11; +} HcRHPORT_STATUS; + +typedef struct { + UINT32 FSBIR:1; + UINT32 FHR:1; + UINT32 CGR:1; + UINT32 SSDC:1; + UINT32 UIT:1; + UINT32 SSE:1; + UINT32 PSPL:1; + UINT32 PCPL:1; + UINT32 Reserved0:1; + UINT32 SSEP1:1; + UINT32 SSEP2:1; + UINT32 SSEP3:1; + UINT32 Reserved1:20; +} HcRESET; + + +#pragma pack() + +// +// Func List +// + + +/** + + Get OHCI operational reg value + + @param PciIo PciIo protocol instance + @param Offset Offset of the operational reg + + @retval Value of the register + +**/ +UINT32 +OhciGetOperationalReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Offset + ); + +/** + + Set OHCI operational reg value + + @param PciIo PCI Bus Io protocol instance + @param Offset Offset of the operational reg + @param Value Value to set + + @retval EFI_SUCCESS Value set to the reg + +**/ + + +EFI_STATUS +OhciSetOperationalReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Offset, + IN VOID *Value + ); + + +/** + + Get HcRevision reg value + + @param PciIo PCI Bus Io protocol instance + + @retval Value of the register + +**/ + + +UINT32 +OhciGetHcRevision ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ); + +/** + + Set HcReset reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field, + IN UINT32 Value + ); +/** + + Get specific field of HcReset reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field + ); +/** + + Set HcControl reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); + + +/** + + Get specific field of HcControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + + +UINT32 +OhciGetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Set HcCommand reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); + +/** + + Get specific field of HcCommand reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Clear specific fields of Interrupt Status + + @param Ohc UHC private data + @param Field Field to clear + + @retval EFI_SUCCESS Fields cleared + +**/ + +EFI_STATUS +OhciClearInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Get fields of HcInterrupt reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Set Interrupt Control reg value + + @param Ohc UHC private data + @param StatEnable Enable or Disable + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN BOOLEAN StatEnable, + IN UINTN Field, + IN UINT32 Value + ); + +/** + + Get field of HcInterruptControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Set memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of the pointer to set + @param Value Value to set + + @retval EFI_SUCCESS Memory pointer set + +**/ + +EFI_STATUS +OhciSetMemoryPointer( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 PointerType, + IN VOID *Value + ); + +/** + + Get memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of pointer + + @retval Memory pointer of the specific type + +**/ + +VOID * +OhciGetMemoryPointer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 PointerType + ); + +/** + + Set Frame Interval value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); + + +/** + + Get field of frame interval reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Set Frame Remaining reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); + +/** + + Get value of frame remaining reg + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of frame remaining reg + +**/ +UINT32 +OhciGetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Set frame number reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameNumber( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); + +/** + + Get frame number reg value + + @param Ohc UHC private data + + @retval Value of frame number reg + +**/ + +UINT32 +OhciGetFrameNumber ( + IN USB_OHCI_HC_DEV *Ohc + ); + + +/** + + Set period start reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); + + +/** + + Get periodic start reg value + + @param Ohc UHC private data + + @param Value of periodic start reg + +**/ + +UINT32 +OhciGetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc + ); + + +/** + + Set Ls Threshold reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); + +/** + + Get Ls Threshold reg value + + @param Ohc UHC private data + + @retval Value of Ls Threshold reg + +**/ + +UINT32 +OhciGetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc + ); + +/** + + Set Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); + + +/** + + Get Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Set Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Get Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Set Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ); + + +/** + + Get Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to get + + @retval Value of the field and index + +**/ + +UINT32 +OhciReadRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c new file mode 100644 index 0000000000..d49b5ec9ad --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.c @@ -0,0 +1,528 @@ +/** @file +OHCI transfer scheduling routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + +/** + + Add an item of interrupt context + + @param Ohc UHC private data + @param NewEntry New entry to add + + @retval EFI_SUCCESS Item successfully added + +**/ +EFI_STATUS +OhciAddInterruptContextEntry ( + IN USB_OHCI_HC_DEV *Ohc, + IN INTERRUPT_CONTEXT_ENTRY *NewEntry + ) +{ + INTERRUPT_CONTEXT_ENTRY *Entry; + EFI_TPL OriginalTPL; + + OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); + + if (Ohc->InterruptContextList == NULL) { + Ohc->InterruptContextList = NewEntry; + } else { + Entry = Ohc->InterruptContextList; + while (Entry->NextEntry != NULL) { + Entry = Entry->NextEntry; + } + Entry->NextEntry = NewEntry; + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} + + +/** + + Free a interrupt context entry + + @param Ohc UHC private data + @param Entry Pointer to an interrupt context entry + + @retval EFI_SUCCESS Entry freed + @retval EFI_INVALID_PARAMETER Entry is NULL + +**/ +EFI_STATUS +OhciFreeInterruptContextEntry ( + IN USB_OHCI_HC_DEV *Ohc, + IN INTERRUPT_CONTEXT_ENTRY *Entry + ) +{ + TD_DESCRIPTOR *Td; + if (Entry == NULL) { + return EFI_INVALID_PARAMETER; + } + if (Entry->UCBufferMapping != NULL) { + Ohc->PciIo->Unmap(Ohc->PciIo, Entry->UCBufferMapping); + } + if (Entry->UCBuffer != NULL) { + FreePool(Entry->UCBuffer); + } + while (Entry->DataTd) { + Td = Entry->DataTd; + Entry->DataTd = (TD_DESCRIPTOR *)(UINTN)(Entry->DataTd->NextTDPointer); + UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR)); + } + FreePool(Entry); + return EFI_SUCCESS; +} + + +/** + + Free entries match the device address and endpoint address + + @Param Ohc UHC private date + @Param DeviceAddress Item to free must match this device address + @Param EndPointAddress Item to free must match this end point address + @Param DataToggle DataToggle for output + + @retval EFI_SUCCESS Items match the requirement removed + +**/ +EFI_STATUS +OhciFreeInterruptContext( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + OUT UINT8 *DataToggle + ) +{ + INTERRUPT_CONTEXT_ENTRY *Entry; + INTERRUPT_CONTEXT_ENTRY *TempEntry; + EFI_TPL OriginalTPL; + + + OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); + + while (Ohc->InterruptContextList != NULL && + Ohc->InterruptContextList->DeviceAddress == DeviceAddress && + Ohc->InterruptContextList->EndPointAddress == EndPointAddress) { + TempEntry = Ohc->InterruptContextList; + Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry; + if (DataToggle != NULL) { + *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1); + } + OhciFreeInterruptContextEntry (Ohc, TempEntry); + } + + Entry = Ohc->InterruptContextList; + if (Entry == NULL) { + gBS->RestoreTPL (OriginalTPL); + return EFI_SUCCESS; + } + while (Entry->NextEntry != NULL) { + if (Entry->NextEntry->DeviceAddress == DeviceAddress && + Entry->NextEntry->EndPointAddress == EndPointAddress) { + TempEntry = Entry->NextEntry; + Entry->NextEntry = Entry->NextEntry->NextEntry; + if (DataToggle != NULL) { + *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1); + } + OhciFreeInterruptContextEntry (Ohc, TempEntry); + } else { + Entry = Entry->NextEntry; + } + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} + + +/** + + Convert Error code from OHCI format to EFI format + + @Param ErrorCode ErrorCode in OHCI format + + @retval ErrorCode in EFI format + +**/ +UINT32 +ConvertErrorCode ( + IN UINT32 ErrorCode + ) +{ + UINT32 TransferResult; + + switch (ErrorCode) { + case TD_NO_ERROR: + TransferResult = EFI_USB_NOERROR; + break; + + case TD_TOBE_PROCESSED: + case TD_TOBE_PROCESSED_2: + TransferResult = EFI_USB_ERR_NOTEXECUTE; + break; + + case TD_DEVICE_STALL: + TransferResult = EFI_USB_ERR_STALL; + break; + + case TD_BUFFER_OVERRUN: + case TD_BUFFER_UNDERRUN: + TransferResult = EFI_USB_ERR_BUFFER; + break; + + case TD_CRC_ERROR: + TransferResult = EFI_USB_ERR_CRC; + break; + + case TD_NO_RESPONSE: + TransferResult = EFI_USB_ERR_TIMEOUT; + break; + + case TD_BITSTUFFING_ERROR: + TransferResult = EFI_USB_ERR_BITSTUFF; + break; + + default: + TransferResult = EFI_USB_ERR_SYSTEM; + } + + return TransferResult; +} + + +/** + + Check TDs Results + + @Param Ohc UHC private data + @Param Td TD_DESCRIPTOR + @Param Result Result to return + + @retval TRUE means OK + @retval FLASE means Error or Short packet + +**/ +BOOLEAN +OhciCheckTDsResults ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td, + OUT UINT32 *Result + ) +{ + UINT32 TdCompletionCode; + + *Result = EFI_USB_NOERROR; + + while (Td) { + TdCompletionCode = Td->Word0.ConditionCode; + + *Result |= ConvertErrorCode(TdCompletionCode); + // + // if any error encountered, stop processing the left TDs. + // + if (*Result) { + return FALSE; + } + + Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer); + } + return TRUE; + +} + + +/** + + Check the task status on an ED + + @Param Ed Pointer to the ED task that TD hooked on + @Param HeadTd TD header for current transaction + + @retval Task Status Code + +**/ + +UINT32 +CheckEDStatus ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT OHCI_ED_RESULT *EdResult + ) +{ + while(HeadTd != NULL) { + if (HeadTd->NextTDPointer == 0) { + return TD_NO_ERROR; + } + if (HeadTd->Word0.ConditionCode != 0) { + return HeadTd->Word0.ConditionCode; + } + EdResult->NextToggle = ((UINT8)(HeadTd->Word0.DataToggle) & BIT0) ^ BIT0; + HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); + } + if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) { + return TD_TOBE_PROCESSED; + } + return TD_NO_ERROR; +} + +/** + + Check the task status + + @Param Ohc UHC private data + @Param ListType Pipe type + @Param Ed Pointer to the ED task hooked on + @Param HeadTd Head of TD corresponding to the task + @Param ErrorCode return the ErrorCode + + @retval EFI_SUCCESS Task done + @retval EFI_NOT_READY Task on processing + @retval EFI_DEVICE_ERROR Some error occured + +**/ +EFI_STATUS +CheckIfDone ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT OHCI_ED_RESULT *EdResult + ) +{ + EdResult->ErrorCode = TD_TOBE_PROCESSED; + + switch (ListType) { + case CONTROL_LIST: + if (OhciGetHcCommandStatus (Ohc, CONTROL_LIST_FILLED) != 0) { + return EFI_NOT_READY; + } + break; + case BULK_LIST: + if (OhciGetHcCommandStatus (Ohc, BULK_LIST_FILLED) != 0) { + return EFI_NOT_READY; + } + break; + default: + break; + } + + EdResult->ErrorCode = CheckEDStatus (Ed, HeadTd, EdResult); + + if (EdResult->ErrorCode == TD_NO_ERROR) { + return EFI_SUCCESS; + } else if (EdResult->ErrorCode == TD_TOBE_PROCESSED) { + return EFI_NOT_READY; + } else { + return EFI_DEVICE_ERROR; + } +} + + +/** + + Convert TD condition code to Efi Status + + @Param ConditionCode Condition code to convert + + @retval EFI_SUCCESS No error occured + @retval EFI_NOT_READY TD still on processing + @retval EFI_DEVICE_ERROR Error occured in processing TD + +**/ + +EFI_STATUS +OhciTDConditionCodeToStatus ( + IN UINT32 ConditionCode + ) +{ + if (ConditionCode == TD_NO_ERROR) { + return EFI_SUCCESS; + } + + if (ConditionCode == TD_TOBE_PROCESSED) { + return EFI_NOT_READY; + } + + return EFI_DEVICE_ERROR; +} + +/** + + Invoke callbacks hooked on done TDs + + @Param Entry Interrupt transfer transaction information data structure + @Param Context Ohc private data + +**/ + +VOID +OhciInvokeInterruptCallBack( + IN INTERRUPT_CONTEXT_ENTRY *Entry, + IN UINT32 Result +) +{ + //Generally speaking, Keyboard driver should not + //check the Keyboard buffer if an error happens, it will be robust + //if we NULLed the buffer once error happens + if (Result) { + Entry->CallBackFunction ( + NULL, + 0, + Entry->Context, + Result + ); + }else{ + Entry->CallBackFunction ( + (VOID *)(UINTN)(Entry->DataTd->DataBuffer), + Entry->DataTd->ActualSendLength, + Entry->Context, + Result + ); + } +} + + +/** + + Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs + + @param Event Event handle + @param Context Device private data + +**/ + +VOID +EFIAPI +OhciHouseKeeper ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + + USB_OHCI_HC_DEV *Ohc; + INTERRUPT_CONTEXT_ENTRY *Entry; + INTERRUPT_CONTEXT_ENTRY *PreEntry; + ED_DESCRIPTOR *Ed; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *HeadTd; + + UINT8 Toggle; + EFI_TPL OriginalTPL; + UINT32 Result; + + Ohc = (USB_OHCI_HC_DEV *) Context; + OriginalTPL = gBS->RaiseTPL(TPL_NOTIFY); + + Entry = Ohc->InterruptContextList; + PreEntry = NULL; + + while(Entry != NULL) { + + OhciCheckTDsResults(Ohc, Entry->DataTd, &Result ); + if (((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) || + ((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)) { + PreEntry = Entry; + Entry = Entry->NextEntry; + continue; + } + + if (Entry->CallBackFunction != NULL) { + OhciInvokeInterruptCallBack (Entry, Result); + if (Ohc->InterruptContextList == NULL) { + gBS->RestoreTPL (OriginalTPL); + return; + } + } + if (Entry->IsPeriodic) { + + Ed = Entry->Ed; + HeadTd = Entry->DataTd; + DataTd = HeadTd; + Toggle = 0; + if (Result == EFI_USB_NOERROR) { + // + // Update toggle if there is no error, and re-submit the interrupt Ed&Tds + // + if ((Ed != NULL) && (DataTd != NULL)) { + Ed->Word0.Skip = 1; + } + // + // From hcir1_0a.pdf 4.2.2 + // ToggleCarry:This bit is the data toggle carry bit, + // Whenever a TD is retired, this bit is written to + // contain the last data toggle value(LSb of data Toggel + // file) from the retired TD. + // This field is not used for Isochronous Endpoints + // + if (Ed == NULL) { + return; + } + Toggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); + while(DataTd != NULL) { + if (DataTd->NextTDPointer == 0) { + DataTd->Word0.DataToggle = 0; + break; + } else { + OhciSetTDField (DataTd, TD_DT_TOGGLE, Toggle); + } + DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer); + Toggle ^= 1; + } + // + // HC will only update DataToggle, ErrorCount, ConditionCode + // CurrentBufferPointer & NextTD, so we only need to update + // them once we want to active them again + // + DataTd = HeadTd; + while (DataTd != NULL) { + if (DataTd->NextTDPointer == 0) { + OhciSetTDField (DataTd, TD_ERROR_CNT | TD_COND_CODE | TD_CURR_BUFFER_PTR | TD_NEXT_PTR, 0); + break; + } + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + DataTd->NextTD = DataTd->NextTDPointer; + DataTd->CurrBufferPointer = DataTd->DataBuffer; + DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer); + } + // + // Active current Ed,Td + // + // HC will only update Halted, ToggleCarry & TDQueueHeadPointer, + // So we only need to update them once we want to active them again. + // + if ((Ed != NULL) && (DataTd != NULL)) { + Ed->Word2.TdHeadPointer = (UINT32)((UINTN)HeadTd>>4); + OhciSetEDField (Ed, ED_HALTED | ED_DTTOGGLE, 0); + Ed->Word0.Skip = 0; + } + } + } else { + if (PreEntry == NULL) { + Ohc->InterruptContextList = Entry->NextEntry; + } else { + PreEntry = Entry; + PreEntry->NextEntry = Entry->NextEntry; + } + OhciFreeInterruptContextEntry (Ohc, PreEntry); + gBS->RestoreTPL (OriginalTPL); + return; + } + PreEntry = Entry; + Entry = Entry->NextEntry; + } + gBS->RestoreTPL (OriginalTPL); +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h new file mode 100644 index 0000000000..1c4114cb00 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciSched.h @@ -0,0 +1,225 @@ +/** @file +This file contains the definination for host controller schedule routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _OHCI_SCHED_H +#define _OHCI_SCHED_H + +#include "Descriptor.h" + +#define HCCA_MEM_SIZE 256 +#define GRID_SIZE 16 +#define GRID_SHIFT 4 + +typedef struct _INTERRUPT_CONTEXT_ENTRY INTERRUPT_CONTEXT_ENTRY; + +struct _INTERRUPT_CONTEXT_ENTRY{ + UINT8 DeviceAddress; + UINT8 EndPointAddress; + ED_DESCRIPTOR *Ed; + TD_DESCRIPTOR *DataTd; + BOOLEAN IsSlowDevice; + UINT8 MaxPacketLength; + UINTN PollingInterval; + EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction; + VOID *Context; + BOOLEAN IsPeriodic; + VOID *Buffer; + UINTN DataLength; + VOID *UCBuffer; + VOID *UCBufferMapping; + UINT8 *Toggle; + INTERRUPT_CONTEXT_ENTRY *NextEntry; +}; + + +typedef struct { + UINT32 ErrorCode; + UINT8 NextToggle; +} OHCI_ED_RESULT; + +/** + + Add an item of interrupt context + + @param Ohc UHC private data + @param NewEntry New entry to add + + @retval EFI_SUCCESS Item successfully added + +**/ +EFI_STATUS +OhciAddInterruptContextEntry ( + IN USB_OHCI_HC_DEV *Ohc, + IN INTERRUPT_CONTEXT_ENTRY *NewEntry + ); + +/** + + Free a interrupt context entry + + @param Ohc UHC private data + @param Entry Pointer to an interrupt context entry + + @retval EFI_SUCCESS Entry freed + @retval EFI_INVALID_PARAMETER Entry is NULL + +**/ +EFI_STATUS +OhciFreeInterruptContextEntry ( + IN USB_OHCI_HC_DEV *Ohc, + IN INTERRUPT_CONTEXT_ENTRY *Entry + ); + +/** + + Free entries match the device address and endpoint address + + @Param Ohc UHC private date + @Param DeviceAddress Item to free must match this device address + @Param EndPointAddress Item to free must match this end point address + @Param DataToggle DataToggle for output + + @retval EFI_SUCCESS Items match the requirement removed + +**/ +EFI_STATUS +OhciFreeInterruptContext( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + OUT UINT8 *DataToggle + ); + + +/** + + Convert Error code from OHCI format to EFI format + + @Param ErrorCode ErrorCode in OHCI format + + @retval ErrorCode in EFI format + +**/ +UINT32 +ConvertErrorCode ( + IN UINT32 ErrorCode + ); + + +/** + + Check TDs Results + + @Param Ohc UHC private data + @Param Td TD_DESCRIPTOR + @Param Result Result to return + + @retval TRUE means OK + @retval FLASE means Error or Short packet + +**/ +BOOLEAN +OhciCheckTDsResults ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td, + OUT UINT32 *Result + ); +/** + + Check the task status on an ED + + @Param Ed Pointer to the ED task that TD hooked on + @Param HeadTd TD header for current transaction + + @retval Task Status Code + +**/ + +UINT32 +CheckEDStatus ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT OHCI_ED_RESULT *EdResult + ); +/** + + Check the task status + + @Param Ohc UHC private data + @Param ListType Pipe type + @Param Ed Pointer to the ED task hooked on + @Param HeadTd Head of TD corresponding to the task + @Param ErrorCode return the ErrorCode + + @retval EFI_SUCCESS Task done + @retval EFI_NOT_READY Task on processing + @retval EFI_DEVICE_ERROR Some error occured + +**/ +EFI_STATUS +CheckIfDone ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT OHCI_ED_RESULT *EdResult + ); + +/** + + Convert TD condition code to Efi Status + + @Param ConditionCode Condition code to convert + + @retval EFI_SUCCESS No error occured + @retval EFI_NOT_READY TD still on processing + @retval EFI_DEVICE_ERROR Error occured in processing TD + +**/ + +EFI_STATUS +OhciTDConditionCodeToStatus ( + IN UINT32 ConditionCode + ); + +/** + + Invoke callbacks hooked on done TDs + + @Param Entry Interrupt transfer transaction information data structure + @Param Context Ohc private data + +**/ + +VOID +OhciInvokeInterruptCallBack( + IN INTERRUPT_CONTEXT_ENTRY *Entry, + IN UINT32 Result +); + + +/** + + Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs + + @param Event Event handle + @param Context Device private data + +**/ + +VOID +EFIAPI +OhciHouseKeeper ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c new file mode 100644 index 0000000000..ccf4c96de4 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.c @@ -0,0 +1,889 @@ +/** @file +This file contains URB request, each request is warpped in a +URB (Usb Request Block). + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#include "Ohci.h" + + +/** + + Create a TD + + @Param Ohc UHC private data + + @retval TD structure pointer + +**/ +TD_DESCRIPTOR * +OhciCreateTD ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + TD_DESCRIPTOR *Td; + + Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR)); + if (Td == NULL) { + DEBUG ((EFI_D_INFO, "STV allocate TD fail !\r\n")); + return NULL; + } + Td->CurrBufferPointer = 0; + Td->NextTD = 0; + Td->BufferEndPointer = 0; + Td->NextTDPointer = 0; + + return Td; +} + + +/** + + Free a TD + + @Param Ohc UHC private data + @Param Td Pointer to a TD to free + + @retval EFI_SUCCESS TD freed + +**/ +EFI_STATUS +OhciFreeTD ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td + ) +{ + if (Td == NULL) { + return EFI_SUCCESS; + } + UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR)); + + return EFI_SUCCESS; +} + + +/** + + Create a ED + + @Param Ohc Device private data + + @retval ED descriptor pointer + +**/ +ED_DESCRIPTOR * +OhciCreateED ( + USB_OHCI_HC_DEV *Ohc + ) +{ + ED_DESCRIPTOR *Ed; + Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR)); + if (Ed == NULL) { + DEBUG ((EFI_D_INFO, "STV allocate ED fail !\r\n")); + return NULL; + } + Ed->Word0.Skip = 1; + Ed->TdTailPointer = 0; + Ed->Word2.TdHeadPointer = 0; + Ed->NextED = 0; + + return Ed; +} + +/** + + Free a ED + + @Param Ohc UHC private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ + +EFI_STATUS +OhciFreeED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ) +{ + if (Ed == NULL) { + return EFI_SUCCESS; + } + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + + return EFI_SUCCESS; +} + +/** + + Free ED + + @Param Ohc Device private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ +EFI_STATUS +OhciFreeAllTDFromED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ) +{ + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *TailTd; + TD_DESCRIPTOR *Td; + TD_DESCRIPTOR *TempTd; + + if (Ed == NULL) { + return EFI_SUCCESS; + } + + HeadTd = TD_PTR (Ed->Word2.TdHeadPointer); + TailTd = (TD_DESCRIPTOR *)(UINTN)(Ed->TdTailPointer); + + Td = HeadTd; + while (Td != TailTd) { + TempTd = Td; + Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer); + OhciFreeTD (Ohc, TempTd); + } + + return EFI_SUCCESS; +} + +/** + + Find a working ED match the requirement + + @Param EdHead Head of the ED list + @Param DeviceAddress Device address to search + @Param EndPointNum End point num to search + @Param EdDir ED Direction to search + + @retval ED descriptor searched + +**/ + +ED_DESCRIPTOR * +OhciFindWorkingEd ( + IN ED_DESCRIPTOR *EdHead, + IN UINT8 DeviceAddress, + IN UINT8 EndPointNum, + IN UINT8 EdDir + ) +{ + ED_DESCRIPTOR *Ed; + + for (Ed = EdHead; Ed != NULL; Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED)) { + if (Ed->Word2.Halted == 0 && Ed->Word0.Skip == 0 && + Ed->Word0.FunctionAddress == DeviceAddress && Ed->Word0.EndPointNum == EndPointNum && + Ed->Word0.Direction == EdDir) { + break; + } + } + + return Ed; +} + + +/** + + Initialize interrupt list. + + @Param Ohc Device private data + + @retval EFI_SUCCESS Initialization done + +**/ +EFI_STATUS +OhciInitializeInterruptList ( + USB_OHCI_HC_DEV *Ohc + ) +{ + static UINT32 Leaf[32] = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, + 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31}; + UINT32 *HccaInterruptTable; + UINTN Index; + UINTN Level; + UINTN Count; + ED_DESCRIPTOR *NewEd; + + HccaInterruptTable = Ohc->HccaMemoryBlock->HccaInterruptTable; + + for (Index = 0; Index < 32; Index++) { + NewEd = OhciCreateED (Ohc); + if (NewEd == NULL) { + return EFI_OUT_OF_RESOURCES; + } + HccaInterruptTable[Index] = (UINT32)(UINTN)NewEd; + } + + for (Index = 0; Index < 32; Index++) { + Ohc->IntervalList[0][Index] = (ED_DESCRIPTOR *)(UINTN)HccaInterruptTable[Leaf[Index]]; + } + + Count = 32; + for (Level = 1; Level <= 5; Level++) { + Count = Count >> 1; + + for (Index = 0; Index < Count; Index++) { + Ohc->IntervalList[Level][Index] = OhciCreateED (Ohc); + if (HccaInterruptTable[Index] == 0) { + return EFI_OUT_OF_RESOURCES; + } + Ohc->IntervalList[Level - 1][Index * 2 ]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index]; + Ohc->IntervalList[Level - 1][Index * 2 + 1]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index]; + } + } + + return EFI_SUCCESS; +} + +/** + + Attach an ED + + @Param Ed Ed to be attached + @Param NewEd Ed to attach + + @retval EFI_SUCCESS NewEd attached to Ed + @retval EFI_INVALID_PARAMETER Ed is NULL + +**/ +EFI_STATUS +OhciAttachED ( + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *NewEd + ) +{ + ED_DESCRIPTOR *Temp; + + if (Ed == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Ed->NextED == 0){ + Ed->NextED = (UINT32)(UINTN)NewEd; + } else { + Temp = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + Ed->NextED = (UINT32)(UINTN)NewEd; + NewEd->NextED = (UINT32)(UINTN)Temp; + } + + return EFI_SUCCESS; +} + + +/** + + Count ED number on a ED chain + + @Param Ed Head of the ED chain + + @retval ED number on the chain + +**/ + +UINTN +CountEdNum ( + IN ED_DESCRIPTOR *Ed + ) +{ + UINTN Count; + + Count = 0; + + while (Ed) { + Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + Count++; + } + + return Count; +} + +/** + + Find the minimal burn ED list on a specific depth level + + @Param Ohc Device private data + @Param Depth Depth level + + @retval ED list found + +**/ + +ED_DESCRIPTOR * +OhciFindMinInterruptEDList ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Depth + ) +{ + UINTN EdNum; + UINTN MinEdNum; + ED_DESCRIPTOR *TempEd; + ED_DESCRIPTOR *HeadEd; + UINTN Index; + + if (Depth > 5) { + return NULL; + } + + MinEdNum = 0xFFFFFFFF; + TempEd = NULL; + for (Index = 0; Index < (UINTN)(32 >> Depth); Index++) { + HeadEd = Ohc->IntervalList[Depth][Index]; + EdNum = CountEdNum (HeadEd); + if (EdNum < MinEdNum) { + MinEdNum = EdNum; + TempEd = HeadEd; + } + } + + ASSERT (TempEd != NULL); + + return TempEd; +} + + +/** + + Attach an ED to an ED list + + @Param OHC UHC private data + @Param ListType Type of the ED list + @Param Ed ED to attach + @Param EdList ED list to be attached + + @retval EFI_SUCCESS ED attached to ED list + +**/ +ED_DESCRIPTOR * +OhciAttachEDToList ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *EdList + ) +{ + ED_DESCRIPTOR *HeadEd; + + HeadEd = NULL; + switch(ListType) { + case CONTROL_LIST: + HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD); + if (HeadEd == NULL) { + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed); + HeadEd = Ed; + } else { + OhciAttachED (HeadEd, Ed); + } + break; + + case BULK_LIST: + HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD); + if (HeadEd == NULL) { + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed); + HeadEd = Ed; + } else { + OhciAttachED (HeadEd, Ed); + } + break; + + case INTERRUPT_LIST: + OhciAttachED (EdList, Ed); + break; + + default: + ASSERT (FALSE); + } + + return HeadEd; +} + +/** + + Remove interrupt EDs that match requirement + + @Param Ohc UHC private data + @Param IntEd The address of Interrupt endpoint + + @retval EFI_SUCCESS EDs match requirement removed + +**/ + +EFI_STATUS +OhciFreeInterruptEdByEd ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *IntEd + ) +{ + ED_DESCRIPTOR *Ed; + ED_DESCRIPTOR *TempEd; + UINTN Index; + + if (IntEd == NULL) + return EFI_SUCCESS; + + for (Index = 0; Index < 32; Index++) { + Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index]; + if (Ed == NULL) { + continue; + } + while (Ed->NextED != 0) { + if (Ed->NextED == (UINT32)(UINTN)IntEd ) { + TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + Ed->NextED = TempEd->NextED; + OhciFreeED (Ohc, TempEd); + } else { + Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + } + } + } + return EFI_SUCCESS; +} + +/** + + Remove interrupt EDs that match requirement + + @Param Ohc UHC private data + @Param FunctionAddress Requirement on function address + @Param EndPointNum Requirement on end point number + + @retval EFI_SUCCESS EDs match requirement removed + +**/ +EFI_STATUS +OhciFreeInterruptEdByAddr ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 FunctionAddress, + IN UINT8 EndPointNum + ) +{ + ED_DESCRIPTOR *Ed; + ED_DESCRIPTOR *TempEd; + UINTN Index; + + for (Index = 0; Index < 32; Index++) { + Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index]; + if (Ed == NULL) { + continue; + } + + while (Ed->NextED != 0) { + TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + if (TempEd->Word0.FunctionAddress == FunctionAddress && + TempEd->Word0.EndPointNum == EndPointNum ) { + Ed->NextED = TempEd->NextED; + OhciFreeED (Ohc, TempEd); + } else { + Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + } + } + } + + return EFI_SUCCESS; +} + + +/** + + Link Td2 to the end of Td1 + + @Param Td1 TD to be linked + @Param Td2 TD to link + + @retval EFI_SUCCESS TD successfully linked + @retval EFI_INVALID_PARAMETER Td1 is NULL + +**/ +EFI_STATUS +OhciLinkTD ( + IN TD_DESCRIPTOR *Td1, + IN TD_DESCRIPTOR *Td2 + ) +{ + TD_DESCRIPTOR *TempTd; + + if (Td1 == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Td1 == Td2) { + return EFI_SUCCESS; + } + + TempTd = Td1; + while (TempTd->NextTD != 0) { + TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD); + } + + TempTd->NextTD = (UINT32)(UINTN)Td2; + TempTd->NextTDPointer = (UINT32)(UINTN)Td2; + + return EFI_SUCCESS; +} + + +/** + + Attach TD list to ED + + @Param Ed ED which TD list attach on + @Param HeadTd Head of the TD list to attach + + @retval EFI_SUCCESS TD list attached on the ED + +**/ +EFI_STATUS +OhciAttachTDListToED ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd + ) +{ + TD_DESCRIPTOR *TempTd; + + TempTd = TD_PTR (Ed->Word2.TdHeadPointer); + + if (TempTd != NULL) { + while (TempTd->NextTD != 0) { + TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD); + } + TempTd->NextTD = (UINT32)(UINTN)HeadTd; + TempTd->NextTDPointer = (UINT32)(UINTN)HeadTd; + } else { + Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32)(UINTN)HeadTd); + } + + return EFI_SUCCESS; +} + + +/** + + Set value to ED specific field + + @Param Ed ED to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field, + IN UINT32 Value + ) +{ + if (Field & ED_FUNC_ADD) { + Ed->Word0.FunctionAddress = Value; + } + if (Field & ED_ENDPT_NUM) { + Ed->Word0.EndPointNum = Value; + } + if (Field & ED_DIR) { + Ed->Word0.Direction = Value; + } + if (Field & ED_SPEED) { + Ed->Word0.Speed = Value; + } + if (Field & ED_SKIP) { + Ed->Word0.Skip = Value; + } + if (Field & ED_FORMAT) { + Ed->Word0.Format = Value; + } + if (Field & ED_MAX_PACKET) { + Ed->Word0.MaxPacketSize = Value; + } + if (Field & ED_PDATA) { + Ed->Word0.FreeSpace = Value; + } + if (Field & ED_ZERO) { + Ed->Word2.Zero = Value; + } + if (Field & ED_TDTAIL_PTR) { + Ed->TdTailPointer = Value; + } + + if (Field & ED_HALTED) { + Ed->Word2.Halted = Value; + } + if (Field & ED_DTTOGGLE) { + Ed->Word2.ToggleCarry = Value; + } + if (Field & ED_TDHEAD_PTR) { + Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value); + } + + if (Field & ED_NEXT_EDPTR) { + Ed->NextED = Value; + } + + return EFI_SUCCESS; +} + +/** + + Get value from an ED's specific field + + @Param Ed ED pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ +UINT32 +OhciGetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field + ) +{ + switch (Field) { + case ED_FUNC_ADD: + return Ed->Word0.FunctionAddress; + break; + case ED_ENDPT_NUM: + return Ed->Word0.EndPointNum; + break; + case ED_DIR: + return Ed->Word0.Direction; + break; + case ED_SPEED: + return Ed->Word0.Speed; + break; + case ED_SKIP: + return Ed->Word0.Skip; + break; + case ED_FORMAT: + return Ed->Word0.Format; + break; + case ED_MAX_PACKET: + return Ed->Word0.MaxPacketSize; + break; + + case ED_TDTAIL_PTR: + return Ed->TdTailPointer; + break; + + case ED_HALTED: + return Ed->Word2.Halted; + break; + + case ED_DTTOGGLE: + return Ed->Word2.ToggleCarry; + break; + + case ED_TDHEAD_PTR: + return Ed->Word2.TdHeadPointer << 4; + break; + + case ED_NEXT_EDPTR: + return Ed->NextED; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + + +/** + + Set value to TD specific field + + @Param Td TD to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field, + IN UINT32 Value + ) +{ + if (Field & TD_PDATA) { + Td->Word0.Reserved = Value; + } + if (Field & TD_BUFFER_ROUND) { + Td->Word0.BufferRounding = Value; + } + if (Field & TD_DIR_PID) { + Td->Word0.DirPID = Value; + } + if (Field & TD_DELAY_INT) { + Td->Word0.DelayInterrupt = Value; + } + if (Field & TD_DT_TOGGLE) { + Td->Word0.DataToggle = Value | 0x2; + } + if (Field & TD_ERROR_CNT) { + Td->Word0.ErrorCount = Value; + } + if (Field & TD_COND_CODE) { + Td->Word0.ConditionCode = Value; + } + + if (Field & TD_CURR_BUFFER_PTR) { + Td->CurrBufferPointer = Value; + } + + + if (Field & TD_NEXT_PTR) { + Td->NextTD = Value; + } + + if (Field & TD_BUFFER_END_PTR) { + Td->BufferEndPointer = Value; + } + + return EFI_SUCCESS; +} + + +/** + + Get value from ED specific field + + @Param Td TD pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ + +UINT32 +OhciGetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field + ) +{ + switch (Field){ + case TD_BUFFER_ROUND: + return Td->Word0.BufferRounding; + break; + case TD_DIR_PID: + return Td->Word0.DirPID; + break; + case TD_DELAY_INT: + return Td->Word0.DelayInterrupt; + break; + case TD_DT_TOGGLE: + return Td->Word0.DataToggle; + break; + case TD_ERROR_CNT: + return Td->Word0.ErrorCount; + break; + case TD_COND_CODE: + return Td->Word0.ConditionCode; + break; + case TD_CURR_BUFFER_PTR: + return Td->CurrBufferPointer; + break; + + case TD_NEXT_PTR: + return Td->NextTD; + break; + + case TD_BUFFER_END_PTR: + return Td->BufferEndPointer; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Free the Ed,Td,buffer that were created during transferring + + @Param Ohc Device private data +**/ + +VOID +OhciFreeDynamicIntMemory( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + INTERRUPT_CONTEXT_ENTRY *Entry; + if (Ohc != NULL) { + while (Ohc->InterruptContextList != NULL) { + Entry = Ohc->InterruptContextList; + Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry; + OhciFreeInterruptEdByEd (Ohc, Entry->Ed); + OhciFreeInterruptContextEntry (Ohc, Entry); + } + } +} +/** + + Free the Ed that were initilized during driver was starting, + those memory were used as interrupt ED head + + @Param Ohc Device private data + + +**/ +VOID +OhciFreeFixedIntMemory ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + static UINT32 Leaf[] = {32,16,8,4,2,1}; + UINTN Index; + UINTN Level; + + for (Level = 0; Level < 6; Level++) { + for (Index = 0; Index < Leaf[Level]; Index++) { + if (Ohc->IntervalList[Level][Index] != NULL) { + UsbHcFreeMem(Ohc->MemPool, Ohc->IntervalList[Level][Index], sizeof(ED_DESCRIPTOR)); + } + } + } +} +/** + + Release all OHCI used memory when OHCI going to quit + + @Param Ohc Device private data + + @retval EFI_SUCCESS Memory released + +**/ + +EFI_STATUS +OhciFreeIntTransferMemory ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + // + // Free the Ed,Td,buffer that were created during transferring + // + OhciFreeDynamicIntMemory (Ohc); + // + // Free the Ed that were initilized during driver was starting + // + OhciFreeFixedIntMemory (Ohc); + return EFI_SUCCESS; +} + + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h new file mode 100644 index 0000000000..6bf2fe7e54 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciUrb.h @@ -0,0 +1,387 @@ +/** @file +Provides some data struct used by OHCI controller driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _OHCI_URB_H +#define _OHCI_URB_H + +#include "Descriptor.h" + + +// +// Func List +// + + +/** + + Create a TD + + @Param Ohc UHC private data + + @retval TD structure pointer + +**/ +TD_DESCRIPTOR * +OhciCreateTD ( + IN USB_OHCI_HC_DEV *Ohc + ); + +/** + + Free a TD + + @Param Ohc UHC private data + @Param Td Pointer to a TD to free + + @retval EFI_SUCCESS TD freed + +**/ +EFI_STATUS +OhciFreeTD ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td + ); + +/** + + Create a ED + + @Param Ohc Device private data + + @retval ED descriptor pointer + +**/ +ED_DESCRIPTOR * +OhciCreateED ( + USB_OHCI_HC_DEV *Ohc + ); + + +/** + + Free a ED + + @Param Ohc UHC private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ + +EFI_STATUS +OhciFreeED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ); + +/** + + Free ED + + @Param Ohc Device private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ +EFI_STATUS +OhciFreeAllTDFromED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ); + +/** + + Find a working ED match the requirement + + @Param EdHead Head of the ED list + @Param DeviceAddress Device address to search + @Param EndPointNum End point num to search + @Param EdDir ED Direction to search + + @retval ED descriptor searched + +**/ + +ED_DESCRIPTOR * +OhciFindWorkingEd ( + IN ED_DESCRIPTOR *EdHead, + IN UINT8 DeviceAddress, + IN UINT8 EndPointNum, + IN UINT8 EdDir + ); + + +/** + + Initialize interrupt list. + + @Param Ohc Device private data + + @retval EFI_SUCCESS Initialization done + +**/ +EFI_STATUS +OhciInitializeInterruptList ( + USB_OHCI_HC_DEV *Ohc + ); + +/** + + Attach an ED + + @Param Ed Ed to be attached + @Param NewEd Ed to attach + + @retval EFI_SUCCESS NewEd attached to Ed + @retval EFI_INVALID_PARAMETER Ed is NULL + +**/ +EFI_STATUS +OhciAttachED ( + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *NewEd + ); + +/** + + Count ED number on a ED chain + + @Param Ed Head of the ED chain + + @retval ED number on the chain + +**/ + +UINTN +CountEdNum ( + IN ED_DESCRIPTOR *Ed + ); + +/** + + Find the minimal burn ED list on a specific depth level + + @Param Ohc Device private data + @Param Depth Depth level + + @retval ED list found + +**/ + +ED_DESCRIPTOR * +OhciFindMinInterruptEDList ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Depth + ); + +/** + + Attach an ED to an ED list + + @Param OHC UHC private data + @Param ListType Type of the ED list + @Param Ed ED to attach + @Param EdList ED list to be attached + + @retval EFI_SUCCESS ED attached to ED list + +**/ +ED_DESCRIPTOR * +OhciAttachEDToList ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *EdList + ); + +/** + + Remove interrupt EDs that match requirement + + @Param Ohc UHC private data + @Param IntEd The address of Interrupt endpoint + + @retval EFI_SUCCESS EDs match requirement removed + +**/ + +EFI_STATUS +OhciFreeInterruptEdByEd ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *IntEd + ); + +/** + + Remove interrupt EDs that match requirement + + @Param Ohc UHC private data + @Param FunctionAddress Requirement on function address + @Param EndPointNum Requirement on end point number + + @retval EFI_SUCCESS EDs match requirement removed + +**/ +EFI_STATUS +OhciFreeInterruptEdByAddr ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 FunctionAddress, + IN UINT8 EndPointNum + ); + + +/** + + Link Td2 to the end of Td1 + + @Param Td1 TD to be linked + @Param Td2 TD to link + + @retval EFI_SUCCESS TD successfully linked + @retval EFI_INVALID_PARAMETER Td1 is NULL + +**/ +EFI_STATUS +OhciLinkTD ( + IN TD_DESCRIPTOR *Td1, + IN TD_DESCRIPTOR *Td2 + ); + + +/** + + Attach TD list to ED + + @Param Ed ED which TD list attach on + @Param HeadTd Head of the TD list to attach + + @retval EFI_SUCCESS TD list attached on the ED + +**/ +EFI_STATUS +OhciAttachTDListToED ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd + ); + + +/** + + Set value to ED specific field + + @Param Ed ED to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field, + IN UINT32 Value + ); + + +/** + + Get value from an ED's specific field + + @Param Ed ED pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ +UINT32 +OhciGetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field + ); + + +/** + + Set value to TD specific field + + @Param Td TD to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field, + IN UINT32 Value + ); + + +/** + + Get value from ED specific field + + @Param Td TD pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ + +UINT32 +OhciGetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field + ); +/** + + Free the Ed,Td,buffer that were created during transferring + + @Param Ohc Device private data +**/ + +VOID +OhciFreeDynamicIntMemory( + IN USB_OHCI_HC_DEV *Ohc + ); + +/** + + Free the Ed that were initilized during driver was starting, + those memory were used as interrupt ED head + + @Param Ohc Device private data + + +**/ +VOID +OhciFreeFixedIntMemory ( + IN USB_OHCI_HC_DEV *Ohc + ); +/** + + Release all OHCI used memory when OHCI going to quit + + @Param Ohc Device private data + + @retval EFI_SUCCESS Memory released + +**/ + +EFI_STATUS +OhciFreeIntTransferMemory ( + IN USB_OHCI_HC_DEV *Ohc + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c new file mode 100644 index 0000000000..e2709a25d4 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.c @@ -0,0 +1,560 @@ +/** @file +Routine procedures for memory allocate/free. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + + +/** + Allocate a block of memory to be used by the buffer pool. + + @param Pool The buffer pool to allocate memory for. + @param Pages How many pages to allocate. + + @return The allocated memory block or NULL if failed. + +**/ +USBHC_MEM_BLOCK * +UsbHcAllocMemBlock ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Pages + ) +{ + USBHC_MEM_BLOCK *Block; + EFI_PCI_IO_PROTOCOL *PciIo; + VOID *BufHost; + VOID *Mapping; + EFI_PHYSICAL_ADDRESS MappedAddr; + UINTN Bytes; + EFI_STATUS Status; + + PciIo = Pool->PciIo; + + Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK)); + if (Block == NULL) { + return NULL; + } + + // + // each bit in the bit array represents USBHC_MEM_UNIT + // bytes of memory in the memory block. + // + ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE); + + Block->BufLen = EFI_PAGES_TO_SIZE (Pages); + Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8); + Block->Bits = AllocateZeroPool (Block->BitsLen); + + if (Block->Bits == NULL) { + gBS->FreePool (Block); + return NULL; + } + + // + // Allocate the number of Pages of memory, then map it for + // bus master read and write. + // + Status = PciIo->AllocateBuffer ( + PciIo, + AllocateAnyPages, + EfiBootServicesData, + Pages, + &BufHost, + 0 + ); + + if (EFI_ERROR (Status)) { + goto FREE_BITARRAY; + } + + Bytes = EFI_PAGES_TO_SIZE (Pages); + Status = PciIo->Map ( + PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + BufHost, + &Bytes, + &MappedAddr, + &Mapping + ); + + if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) { + goto FREE_BUFFER; + } + + // + // Check whether the data structure used by the host controller + // should be restricted into the same 4G + // + if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) { + PciIo->Unmap (PciIo, Mapping); + goto FREE_BUFFER; + } + + Block->BufHost = BufHost; + Block->Buf = (UINT8 *) ((UINTN) MappedAddr); + Block->Mapping = Mapping; + + return Block; + +FREE_BUFFER: + PciIo->FreeBuffer (PciIo, Pages, BufHost); + +FREE_BITARRAY: + gBS->FreePool (Block->Bits); + gBS->FreePool (Block); + return NULL; +} + + +/** + Free the memory block from the memory pool. + + @param Pool The memory pool to free the block from. + @param Block The memory block to free. + +**/ +VOID +UsbHcFreeMemBlock ( + IN USBHC_MEM_POOL *Pool, + IN USBHC_MEM_BLOCK *Block + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + + ASSERT ((Pool != NULL) && (Block != NULL)); + + PciIo = Pool->PciIo; + + // + // Unmap the common buffer then free the structures + // + PciIo->Unmap (PciIo, Block->Mapping); + PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost); + + gBS->FreePool (Block->Bits); + gBS->FreePool (Block); +} + + +/** + Alloc some memory from the block. + + @param Block The memory block to allocate memory from. + @param Units Number of memory units to allocate. + + @return The pointer to the allocated memory. If couldn't allocate the needed memory, + the return value is NULL. + +**/ +VOID * +UsbHcAllocMemFromBlock ( + IN USBHC_MEM_BLOCK *Block, + IN UINTN Units + ) +{ + UINTN Byte; + UINT8 Bit; + UINTN StartByte; + UINT8 StartBit; + UINTN Available; + UINTN Count; + + ASSERT ((Block != 0) && (Units != 0)); + + StartByte = 0; + StartBit = 0; + Available = 0; + + for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) { + // + // If current bit is zero, the corresponding memory unit is + // available, otherwise we need to restart our searching. + // Available counts the consective number of zero bit. + // + if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) { + Available++; + + if (Available >= Units) { + break; + } + + NEXT_BIT (Byte, Bit); + + } else { + NEXT_BIT (Byte, Bit); + + Available = 0; + StartByte = Byte; + StartBit = Bit; + } + } + + if (Available < Units) { + return NULL; + } + + // + // Mark the memory as allocated + // + Byte = StartByte; + Bit = StartBit; + + for (Count = 0; Count < Units; Count++) { + ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | USB_HC_BIT (Bit)); + NEXT_BIT (Byte, Bit); + } + + return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT; +} + +/** + Calculate the corresponding pci bus address according to the Mem parameter. + + @param Pool The memory pool of the host controller. + @param Mem The pointer to host memory. + @param Size The size of the memory region. + + @return the pci memory address +**/ +EFI_PHYSICAL_ADDRESS +UsbHcGetPciAddressForHostMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + UINTN AllocSize; + EFI_PHYSICAL_ADDRESS PhyAddr; + UINTN Offset; + + Head = Pool->Head; + AllocSize = USBHC_MEM_ROUND (Size); + + if (Mem == NULL) { + return 0; + } + + for (Block = Head; Block != NULL; Block = Block->Next) { + // + // scan the memory block list for the memory block that + // completely contains the allocated memory. + // + if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) { + break; + } + } + + ASSERT ((Block != NULL)); + // + // calculate the pci memory address for host memory address. + // + Offset = (UINT8 *)Mem - Block->BufHost; + PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset); + return PhyAddr; +} + + +/** + Insert the memory block to the pool's list of the blocks. + + @param Head The head of the memory pool's block list. + @param Block The memory block to insert. + +**/ +VOID +UsbHcInsertMemBlockToPool ( + IN USBHC_MEM_BLOCK *Head, + IN USBHC_MEM_BLOCK *Block + ) +{ + ASSERT ((Head != NULL) && (Block != NULL)); + Block->Next = Head->Next; + Head->Next = Block; +} + + +/** + Is the memory block empty? + + @param Block The memory block to check. + + @retval TRUE The memory block is empty. + @retval FALSE The memory block isn't empty. + +**/ +BOOLEAN +UsbHcIsMemBlockEmpty ( + IN USBHC_MEM_BLOCK *Block + ) +{ + UINTN Index; + + for (Index = 0; Index < Block->BitsLen; Index++) { + if (Block->Bits[Index] != 0) { + return FALSE; + } + } + + return TRUE; +} + + +/** + Unlink the memory block from the pool's list. + + @param Head The block list head of the memory's pool. + @param BlockToUnlink The memory block to unlink. + +**/ +VOID +UsbHcUnlinkMemBlock ( + IN USBHC_MEM_BLOCK *Head, + IN USBHC_MEM_BLOCK *BlockToUnlink + ) +{ + USBHC_MEM_BLOCK *Block; + + ASSERT ((Head != NULL) && (BlockToUnlink != NULL)); + + for (Block = Head; Block != NULL; Block = Block->Next) { + if (Block->Next == BlockToUnlink) { + Block->Next = BlockToUnlink->Next; + BlockToUnlink->Next = NULL; + break; + } + } +} + + +/** + Initialize the memory management pool for the host controller. + + @param PciIo The PciIo that can be used to access the host controller. + @param Check4G Whether the host controller requires allocated memory + from one 4G address space. + @param Which4G The 4G memory area each memory allocated should be from. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool. + +**/ +USBHC_MEM_POOL * +UsbHcInitMemPool ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN BOOLEAN Check4G, + IN UINT32 Which4G + ) +{ + USBHC_MEM_POOL *Pool; + + Pool = AllocatePool (sizeof (USBHC_MEM_POOL)); + + if (Pool == NULL) { + return Pool; + } + + Pool->PciIo = PciIo; + Pool->Check4G = Check4G; + Pool->Which4G = Which4G; + Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES); + + if (Pool->Head == NULL) { + gBS->FreePool (Pool); + Pool = NULL; + } + + return Pool; +} + + +/** + Release the memory management pool. + + @param Pool The USB memory pool to free. + + @retval EFI_SUCCESS The memory pool is freed. + @retval EFI_DEVICE_ERROR Failed to free the memory pool. + +**/ +EFI_STATUS +UsbHcFreeMemPool ( + IN USBHC_MEM_POOL *Pool + ) +{ + USBHC_MEM_BLOCK *Block; + + ASSERT (Pool->Head != NULL); + + // + // Unlink all the memory blocks from the pool, then free them. + // UsbHcUnlinkMemBlock can't be used to unlink and free the + // first block. + // + for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) { + UsbHcUnlinkMemBlock (Pool->Head, Block); + UsbHcFreeMemBlock (Pool, Block); + } + + UsbHcFreeMemBlock (Pool, Pool->Head); + gBS->FreePool (Pool); + return EFI_SUCCESS; +} + + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +UsbHcAllocateMem ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + USBHC_MEM_BLOCK *NewBlock; + VOID *Mem; + UINTN AllocSize; + UINTN Pages; + + Mem = NULL; + AllocSize = USBHC_MEM_ROUND (Size); + Head = Pool->Head; + ASSERT (Head != NULL); + + // + // First check whether current memory blocks can satisfy the allocation. + // + for (Block = Head; Block != NULL; Block = Block->Next) { + Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + break; + } + } + + if (Mem != NULL) { + return Mem; + } + + // + // Create a new memory block if there is not enough memory + // in the pool. If the allocation size is larger than the + // default page number, just allocate a large enough memory + // block. Otherwise allocate default pages. + // + if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) { + Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1; + } else { + Pages = USBHC_MEM_DEFAULT_PAGES; + } + + NewBlock = UsbHcAllocMemBlock (Pool, Pages); + + if (NewBlock == NULL) { + DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n")); + return NULL; + } + + // + // Add the new memory block to the pool, then allocate memory from it + // + UsbHcInsertMemBlockToPool (Head, NewBlock); + Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + } + + return Mem; +} + + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +UsbHcFreeMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + UINT8 *ToFree; + UINTN AllocSize; + UINTN Byte; + UINTN Bit; + UINTN Count; + + Head = Pool->Head; + AllocSize = USBHC_MEM_ROUND (Size); + ToFree = (UINT8 *) Mem; + + for (Block = Head; Block != NULL; Block = Block->Next) { + // + // scan the memory block list for the memory block that + // completely contains the memory to free. + // + if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) { + // + // compute the start byte and bit in the bit array + // + Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8; + Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8; + + // + // reset associated bits in bit arry + // + for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) { + ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit)); + NEXT_BIT (Byte, Bit); + } + + break; + } + } + + // + // If Block == NULL, it means that the current memory isn't + // in the host controller's pool. This is critical because + // the caller has passed in a wrong memory point + // + ASSERT (Block != NULL); + + // + // Release the current memory block if it is empty and not the head + // + if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) { + UsbHcUnlinkMemBlock (Head, Block); + UsbHcFreeMemBlock (Pool, Block); + } + + return ; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h new file mode 100644 index 0000000000..e2973bfe49 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/UsbHcMem.h @@ -0,0 +1,152 @@ +/** @file +This file contains the definination for host controller memory +management routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _USB_HC_MEM_H_ +#define _USB_HC_MEM_H_ + +#define USB_HC_BIT(a) ((UINTN)(1 << (a))) + +#define USB_HC_BIT_IS_SET(Data, Bit) \ + ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit))) + +#define USB_HC_HIGH_32BIT(Addr64) \ + ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF)) + +typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK; +struct _USBHC_MEM_BLOCK { + UINT8 *Bits; // Bit array to record which unit is allocated + UINTN BitsLen; + UINT8 *Buf; + UINT8 *BufHost; + UINTN BufLen; // Memory size in bytes + VOID *Mapping; + USBHC_MEM_BLOCK *Next; +}; + +// +// USBHC_MEM_POOL is used to manage the memory used by USB +// host controller. EHCI requires the control memory and transfer +// data to be on the same 4G memory. +// +typedef struct _USBHC_MEM_POOL { + EFI_PCI_IO_PROTOCOL *PciIo; + BOOLEAN Check4G; + UINT32 Which4G; + USBHC_MEM_BLOCK *Head; +} USBHC_MEM_POOL; + +// +// Memory allocation unit, must be 2^n, n>4 +// +#define USBHC_MEM_UNIT 64 + +#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1) +#define USBHC_MEM_DEFAULT_PAGES 16 + +#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK)) + +// +// Advance the byte and bit to the next bit, adjust byte accordingly. +// +#define NEXT_BIT(Byte, Bit) \ + do { \ + (Bit)++; \ + if ((Bit) > 7) { \ + (Byte)++; \ + (Bit) = 0; \ + } \ + } while (0) + + + +/** + Initialize the memory management pool for the host controller. + + @param PciIo The PciIo that can be used to access the host controller. + @param Check4G Whether the host controller requires allocated memory + from one 4G address space. + @param Which4G The 4G memory area each memory allocated should be from. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool. + +**/ +USBHC_MEM_POOL * +UsbHcInitMemPool ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN BOOLEAN Check4G, + IN UINT32 Which4G + ); + + +/** + Release the memory management pool. + + @param Pool The USB memory pool to free. + + @retval EFI_SUCCESS The memory pool is freed. + @retval EFI_DEVICE_ERROR Failed to free the memory pool. + +**/ +EFI_STATUS +UsbHcFreeMemPool ( + IN USBHC_MEM_POOL *Pool + ); + + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +UsbHcAllocateMem ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Size + ); + + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +UsbHcFreeMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ); + +/** + Calculate the corresponding pci bus address according to the Mem parameter. + + @param Pool The memory pool of the host controller. + @param Mem The pointer to host memory. + @param Size The size of the memory region. + + @return the pci memory address +**/ +EFI_PHYSICAL_ADDRESS +UsbHcGetPciAddressForHostMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h new file mode 100644 index 0000000000..4ec60a07a7 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/Descriptor.h @@ -0,0 +1,131 @@ +/** @file +This file contains the descriptor definination of OHCI spec + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _DESCRIPTOR_H +#define _DESCRIPTOR_H + +#define ED_FUNC_ADD 0x0001 +#define ED_ENDPT_NUM 0x0002 +#define ED_DIR 0x0004 +#define ED_SPEED 0x0008 +#define ED_SKIP 0x0010 +#define ED_FORMAT 0x0020 +#define ED_MAX_PACKET 0x0040 +#define ED_TDTAIL_PTR 0x0080 +#define ED_HALTED 0x0100 +#define ED_DTTOGGLE 0x0200 +#define ED_TDHEAD_PTR 0x0400 +#define ED_NEXT_EDPTR 0x0800 +#define ED_PDATA 0x1000 +#define ED_ZERO 0x2000 + +#define TD_BUFFER_ROUND 0x0001 +#define TD_DIR_PID 0x0002 +#define TD_DELAY_INT 0x0004 +#define TD_DT_TOGGLE 0x0008 +#define TD_ERROR_CNT 0x0010 +#define TD_COND_CODE 0x0020 +#define TD_CURR_BUFFER_PTR 0x0040 +#define TD_NEXT_PTR 0x0080 +#define TD_BUFFER_END_PTR 0x0100 +#define TD_PDATA 0x0200 + +#define ED_FROM_TD_DIR 0x0 +#define ED_OUT_DIR 0x1 +#define ED_IN_DIR 0x2 +#define ED_FROM_TD_ALSO_DIR 0x3 + +#define TD_SETUP_PID 0x00 +#define TD_OUT_PID 0x01 +#define TD_IN_PID 0x02 +#define TD_NODATA_PID 0x03 + +#define HI_SPEED 0 +#define LO_SPEED 1 + +#define TD_NO_ERROR 0x00 +#define TD_CRC_ERROR 0x01 +#define TD_BITSTUFFING_ERROR 0x02 +#define TD_TOGGLE_ERROR 0x03 +#define TD_DEVICE_STALL 0x04 +#define TD_NO_RESPONSE 0x05 +#define TD_PIDCHK_FAIL 0x06 +#define TD_PID_UNEXPECTED 0x07 +#define TD_DATA_OVERRUN 0x08 +#define TD_DATA_UNDERRUN 0x09 +#define TD_BUFFER_OVERRUN 0x0C +#define TD_BUFFER_UNDERRUN 0x0D +#define TD_TOBE_PROCESSED 0x0E +#define TD_TOBE_PROCESSED_2 0x0F + +#define TD_NO_DELAY 0x7 + +#define TD_INT 0x1 +#define TD_CTL 0x2 +#define TD_BLK 0x3 + +typedef struct { + UINT32 Reserved:18; + UINT32 BufferRounding:1; + UINT32 DirPID:2; + UINT32 DelayInterrupt:3; + UINT32 DataToggle:2; + UINT32 ErrorCount:2; + UINT32 ConditionCode:4; +} TD_DESCRIPTOR_WORD0; + +typedef struct _TD_DESCRIPTOR { + TD_DESCRIPTOR_WORD0 Word0; + VOID *CurrBufferPointer; + struct _TD_DESCRIPTOR *NextTD; + VOID *BufferEndPointer; + struct _TD_DESCRIPTOR *NextTDPointer; + UINT8 *DataBuffer; + UINT32 ActualSendLength; +} TD_DESCRIPTOR; + +typedef struct { + UINT32 FunctionAddress:7; + UINT32 EndPointNum:4; + UINT32 Direction:2; + UINT32 Speed:1; + UINT32 Skip:1; + UINT32 Format:1; + UINT32 MaxPacketSize:11; + UINT32 FreeSpace:5; +} ED_DESCRIPTOR_WORD0; + +typedef struct { + UINT32 Halted:1; + UINT32 ToggleCarry:1; + UINT32 Zero:2; + UINT32 TdHeadPointer:28; +} ED_DESCRIPTOR_WORD2; + +typedef struct _ED_DESCRIPTOR { + ED_DESCRIPTOR_WORD0 Word0; + TD_DESCRIPTOR *TdTailPointer; + ED_DESCRIPTOR_WORD2 Word2; + struct _ED_DESCRIPTOR *NextED; +} ED_DESCRIPTOR; + +#define TD_PTR(p) ((TD_DESCRIPTOR *)((p) << 4)) +#define ED_PTR(p) ((ED_DESCRIPTOR *)((p) << 4)) +#define RIGHT_SHIFT_4(p) ((UINT32)(p) >> 4) + +typedef enum { + CONTROL_LIST, + BULK_LIST, + INTERRUPT_LIST, + ISOCHRONOUS_LIST +} DESCRIPTOR_LIST_TYPE; + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c new file mode 100644 index 0000000000..6997e6e387 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c @@ -0,0 +1,1386 @@ +/** @file +This file contains the implementation of Usb Hc Protocol. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "OhcPeim.h" + +/** + Submits control transfer to a target USB device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI. + @param DeviceAddress The target device address. + @param DeviceSpeed Target device speed. + @param MaximumPacketLength Maximum packet size the default control transfer + endpoint is capable of sending or receiving. + @param Request USB device request to send. + @param TransferDirection Specifies the data direction for the data stage. + @param Data Data buffer to be transmitted or received from USB device. + @param DataLength The size (in bytes) of the data buffer. + @param TimeOut Indicates the maximum timeout, in millisecond. + @param TransferResult Return the result of this control transfer. + + @retval EFI_SUCCESS Transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT Transfer failed due to timeout. + @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. + +**/ +EFI_STATUS +EFIAPI +OhciControlTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 DeviceAddress, + IN UINT8 DeviceSpeed, + IN UINT8 MaxPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + USB_OHCI_HC_DEV *Ohc; + ED_DESCRIPTOR *Ed; + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *SetupTd; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *StatusTd; + TD_DESCRIPTOR *EmptyTd; + EFI_STATUS Status; + UINT32 DataPidDir; + UINT32 StatusPidDir; + UINTN TimeCount; + UINT32 ErrorCode; + + UINTN ActualSendLength; + UINTN LeftLength; + UINT8 DataToggle; + + EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0; + + UINTN DataMapLength = 0; + EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0; + + HeadTd = NULL; + DataTd = NULL; + + if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn && + TransferDirection != EfiUsbNoData) || + Request == NULL || DataLength == NULL || TransferResult == NULL || + (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) || + (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) || + (DeviceSpeed != EFI_USB_SPEED_LOW && DeviceSpeed != EFI_USB_SPEED_FULL) || + (MaxPacketLength != 8 && MaxPacketLength != 16 && + MaxPacketLength != 32 && MaxPacketLength != 64)) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: EFI_INVALID_PARAMETER\n")); + return EFI_INVALID_PARAMETER; + } + + if (*DataLength > MAX_BYTES_PER_TD) { + DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\n")); + return EFI_INVALID_PARAMETER; + } + + Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS(This); + + if (TransferDirection == EfiUsbDataIn) { + DataPidDir = TD_IN_PID; + StatusPidDir = TD_OUT_PID; + } else { + DataPidDir = TD_OUT_PID; + StatusPidDir = TD_IN_PID; + } + + OhciSetHcControl (Ohc, CONTROL_ENABLE, 0); + if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) { + MicroSecondDelay (HC_1_MILLISECOND); + if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) { + *TransferResult = EFI_USB_ERR_SYSTEM; + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to disable CONTROL transfer\n")); + return EFI_DEVICE_ERROR; + } + } + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); + Ed = OhciCreateED (Ohc); + if (Ed == NULL) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\n")); + return EFI_OUT_OF_RESOURCES; + } + OhciSetEDField (Ed, ED_SKIP, 1); + OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); + OhciSetEDField (Ed, ED_ENDPT_NUM, 0); + OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); + OhciSetEDField (Ed, ED_SPEED, DeviceSpeed); + OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); + OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); + OhciSetEDField (Ed, ED_PDATA, 0); + OhciSetEDField (Ed, ED_ZERO, 0); + OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL); + OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL); + OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL); + OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL); + // + // Setup Stage + // + if(Request != NULL) { + ReqMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Request; + } + SetupTd = OhciCreateTD (Ohc); + if (SetupTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\n")); + goto FREE_ED_BUFF; + } + HeadTd = SetupTd; + OhciSetTDField (SetupTd, TD_PDATA, 0); + OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID); + OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2); + OhciSetTDField (SetupTd, TD_ERROR_CNT, 0); + OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINTN)ReqMapPhyAddr); + OhciSetTDField (SetupTd, TD_NEXT_PTR, (UINT32) NULL); + OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINTN)ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1); + SetupTd->ActualSendLength = 0; + SetupTd->DataBuffer = NULL; + SetupTd->NextTDPointer = NULL; + + DataMapLength = *DataLength; + if ((Data != NULL) && (DataMapLength != 0)) { + DataMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data; + } + // + //Data Stage + // + LeftLength = DataMapLength; + ActualSendLength = DataMapLength; + DataToggle = 1; + while (LeftLength > 0) { + ActualSendLength = LeftLength; + if (LeftLength > MaxPacketLength) { + ActualSendLength = MaxPacketLength; + } + DataTd = OhciCreateTD (Ohc); + if (DataTd == NULL) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Data TD buffer\n")); + Status = EFI_OUT_OF_RESOURCES; + goto FREE_TD_BUFF; + } + OhciSetTDField (DataTd, TD_PDATA, 0); + OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); + OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle); + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr); + OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) DataMapPhyAddr + ActualSendLength - 1); + OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL); + DataTd->ActualSendLength = ActualSendLength; + DataTd->DataBuffer = (UINT8 *)(UINTN)DataMapPhyAddr; + DataTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, DataTd); + DataToggle ^= 1; + DataMapPhyAddr += ActualSendLength; + LeftLength -= ActualSendLength; + } + // + // Status Stage + // + StatusTd = OhciCreateTD (Ohc); + if (StatusTd == NULL) { + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Status TD buffer\n")); + Status = EFI_OUT_OF_RESOURCES; + goto FREE_TD_BUFF; + } + OhciSetTDField (StatusTd, TD_PDATA, 0); + OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir); + OhciSetTDField (StatusTd, TD_DELAY_INT, 7); + OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3); + OhciSetTDField (StatusTd, TD_ERROR_CNT, 0); + OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, (UINT32) NULL); + OhciSetTDField (StatusTd, TD_NEXT_PTR, (UINT32) NULL); + OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, (UINT32) NULL); + StatusTd->ActualSendLength = 0; + StatusTd->DataBuffer = NULL; + StatusTd->NextTDPointer = NULL; + OhciLinkTD (HeadTd, StatusTd); + // + // Empty Stage + // + EmptyTd = OhciCreateTD (Ohc); + if (EmptyTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Empty TD buffer\n")); + goto FREE_TD_BUFF; + } + OhciSetTDField (EmptyTd, TD_PDATA, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); + OhciSetTDField (EmptyTd, TD_DIR_PID, 0); + OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); + //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); + EmptyTd->Word0.DataToggle = 0; + OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); + OhciSetTDField (EmptyTd, TD_COND_CODE, 0); + OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); + OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); + EmptyTd->ActualSendLength = 0; + EmptyTd->DataBuffer = NULL; + EmptyTd->NextTDPointer = NULL; + OhciLinkTD (HeadTd, EmptyTd); + Ed->TdTailPointer = EmptyTd; + OhciAttachTDListToED (Ed, HeadTd); + // + OhciSetEDField (Ed, ED_SKIP, 0); + MicroSecondDelay (20 * HC_1_MILLISECOND); + OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1); + OhciSetHcControl (Ohc, CONTROL_ENABLE, 1); + MicroSecondDelay (20 * HC_1_MILLISECOND); + if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) { + MicroSecondDelay (HC_1_MILLISECOND); + if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) { + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable CONTROL transfer\n")); + goto FREE_TD_BUFF; + } + } + + TimeCount = 0; + Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode); + + while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { + MicroSecondDelay (HC_1_MILLISECOND); + TimeCount++; + Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode); + } + // + *TransferResult = ConvertErrorCode (ErrorCode); + + if (ErrorCode != TD_NO_ERROR) { + if (ErrorCode == TD_TOBE_PROCESSED) { + DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut)); + } else { + DEBUG ((EFI_D_INFO, "Control pipe broken\r\n")); + } + + *DataLength = 0; + } + + OhciSetHcControl (Ohc, CONTROL_ENABLE, 0); + if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) { + MicroSecondDelay (HC_1_MILLISECOND); + if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) { + *TransferResult = EFI_USB_ERR_SYSTEM; + DEBUG ((EFI_D_INFO, "OhciControlTransfer: Cannot disable CONTROL_ENABLE transfer\n")); + goto FREE_TD_BUFF; + } + } + +FREE_TD_BUFF: + while (HeadTd) { + DataTd = HeadTd; + HeadTd = HeadTd->NextTDPointer; + UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); + } + +FREE_ED_BUFF: + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + + return Status; +} + +/** + Submits bulk transfer to a bulk endpoint of a USB device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI. + @param DeviceAddress Target device address. + @param EndPointAddress Endpoint number and its direction in bit 7. + @param MaxiPacketLength Maximum packet size the endpoint is capable of + sending or receiving. + @param Data A pointers to the buffers of data to transmit + from or receive into. + @param DataLength The lenght of the data buffer. + @param DataToggle On input, the initial data toggle for the transfer; + On output, it is updated to to next data toggle to use of + the subsequent bulk transfer. + @param TimeOut Indicates the maximum time, in millisecond, which the + transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information of the + bulk transfer. + + @retval EFI_SUCCESS The transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. + @retval EFI_INVALID_PARAMETER Parameters are invalid. + @retval EFI_TIMEOUT The transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. + +**/ +EFI_STATUS +EFIAPI +OhciBulkTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + USB_OHCI_HC_DEV *Ohc; + ED_DESCRIPTOR *Ed; + UINT32 DataPidDir; + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *EmptyTd; + EFI_STATUS Status; + UINT8 EndPointNum; + UINTN TimeCount; + UINT32 ErrorCode; + + UINT8 CurrentToggle; + UINTN MapLength; + EFI_PHYSICAL_ADDRESS MapPyhAddr; + UINTN LeftLength; + UINTN ActualSendLength; + BOOLEAN FirstTD; + + MapLength = 0; + MapPyhAddr = 0; + LeftLength = 0; + Status = EFI_SUCCESS; + + if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL || + *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) || + (MaxPacketLength != 8 && MaxPacketLength != 16 && + MaxPacketLength != 32 && MaxPacketLength != 64)) { + return EFI_INVALID_PARAMETER; + } + + Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This); + + if ((EndPointAddress & 0x80) != 0) { + DataPidDir = TD_IN_PID; + } else { + DataPidDir = TD_OUT_PID; + } + + EndPointNum = (EndPointAddress & 0xF); + + OhciSetHcControl (Ohc, BULK_ENABLE, 0); + if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) { + MicroSecondDelay (HC_1_MILLISECOND); + if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) { + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + } + + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); + + Ed = OhciCreateED (Ohc); + if (Ed == NULL) { + DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate ED buffer\r\n")); + return EFI_OUT_OF_RESOURCES; + } + OhciSetEDField (Ed, ED_SKIP, 1); + OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); + OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); + OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); + OhciSetEDField (Ed, ED_SPEED, HI_SPEED); + OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); + OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); + OhciSetEDField (Ed, ED_PDATA, 0); + OhciSetEDField (Ed, ED_ZERO, 0); + OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL); + OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL); + OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL); + OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL); + + if(Data != NULL) { + MapLength = *DataLength; + MapPyhAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data; + } + // + //Data Stage + // + LeftLength = MapLength; + ActualSendLength = MapLength; + CurrentToggle = *DataToggle; + HeadTd = NULL; + FirstTD = TRUE; + while (LeftLength > 0) { + ActualSendLength = LeftLength; + if (LeftLength > MaxPacketLength) { + ActualSendLength = MaxPacketLength; + } + DataTd = OhciCreateTD (Ohc); + if (DataTd == NULL) { + DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Data TD buffer\r\n")); + Status = EFI_OUT_OF_RESOURCES; + goto FREE_TD_BUFF; + } + OhciSetTDField (DataTd, TD_PDATA, 0); + OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); + OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (DataTd, TD_DT_TOGGLE, CurrentToggle); + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); + OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) MapPyhAddr + ActualSendLength - 1); + OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL); + DataTd->ActualSendLength = ActualSendLength; + DataTd->DataBuffer = (UINT8 *)(UINTN)MapPyhAddr; + DataTd->NextTDPointer = 0; + if (FirstTD) { + HeadTd = DataTd; + FirstTD = FALSE; + } else { + OhciLinkTD (HeadTd, DataTd); + } + CurrentToggle ^= 1; + MapPyhAddr += ActualSendLength; + LeftLength -= ActualSendLength; + } + // + // Empty Stage + // + EmptyTd = OhciCreateTD (Ohc); + if (EmptyTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Empty TD buffer\r\n")); + goto FREE_TD_BUFF; + } + OhciSetTDField (EmptyTd, TD_PDATA, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); + OhciSetTDField (EmptyTd, TD_DIR_PID, 0); + OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); + //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); + EmptyTd->Word0.DataToggle = 0; + OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); + OhciSetTDField (EmptyTd, TD_COND_CODE, 0); + OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); + OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); + EmptyTd->ActualSendLength = 0; + EmptyTd->DataBuffer = NULL; + EmptyTd->NextTDPointer = NULL; + OhciLinkTD (HeadTd, EmptyTd); + Ed->TdTailPointer = EmptyTd; + OhciAttachTDListToED (Ed, HeadTd); + + OhciSetEDField (Ed, ED_SKIP, 0); + OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1); + OhciSetHcControl (Ohc, BULK_ENABLE, 1); + if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) { + MicroSecondDelay (HC_1_MILLISECOND); + if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) { + *TransferResult = EFI_USB_ERR_SYSTEM; + goto FREE_TD_BUFF; + } + } + + TimeCount = 0; + Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode); + + while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { + MicroSecondDelay (HC_1_MILLISECOND); + TimeCount++; + Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode); + } + + *TransferResult = ConvertErrorCode (ErrorCode); + + if (ErrorCode != TD_NO_ERROR) { + if (ErrorCode == TD_TOBE_PROCESSED) { + DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut)); + } else { + DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n")); + } + *DataLength = 0; + } + *DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); + +FREE_TD_BUFF: + while (HeadTd) { + DataTd = HeadTd; + HeadTd = HeadTd->NextTDPointer; + UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); + } + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + + return Status; +} +/** + Retrieves the number of root hub ports. + + @param[in] PeiServices The pointer to the PEI Services Table. + @param[in] This The pointer to this instance of the + PEI_USB_HOST_CONTROLLER_PPI. + @param[out] NumOfPorts The pointer to the number of the root hub ports. + + @retval EFI_SUCCESS The port number was retrieved successfully. + @retval EFI_INVALID_PARAMETER PortNumber is NULL. + +**/ + +EFI_STATUS +EFIAPI +OhciGetRootHubNumOfPorts ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + OUT UINT8 *NumOfPorts + ) +{ + USB_OHCI_HC_DEV *Ohc; + if (NumOfPorts == NULL) { + return EFI_INVALID_PARAMETER; + } + Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This); + *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS); + + return EFI_SUCCESS; +} +/** + Retrieves the current status of a USB root hub port. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI. + @param PortNumber The root hub port to retrieve the state from. + @param PortStatus Variable to receive the port state. + + @retval EFI_SUCCESS The status of the USB root hub port specified. + by PortNumber was returned in PortStatus. + @retval EFI_INVALID_PARAMETER PortNumber is invalid. + +**/ + +EFI_STATUS +EFIAPI +OhciGetRootHubPortStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus + ) +{ + USB_OHCI_HC_DEV *Ohc; + UINT8 NumOfPorts; + + Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This); + + OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts); + if (PortNumber >= NumOfPorts) { + return EFI_INVALID_PARAMETER; + } + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) { + PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_RESET; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_POWER; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) { + PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET; + } + + return EFI_SUCCESS; +} +/** + Sets a feature for the specified root hub port. + + @param PeiServices The pointer of EFI_PEI_SERVICES + @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI + @param PortNumber Root hub port to set. + @param PortFeature Feature to set. + + @retval EFI_SUCCESS The feature specified by PortFeature was set. + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. + @retval EFI_TIMEOUT The time out occurred. + +**/ + +EFI_STATUS +EFIAPI +OhciSetRootHubPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + UINT8 NumOfPorts; + UINTN RetryTimes; + + OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts); + if (PortNumber >= NumOfPorts) { + return EFI_INVALID_PARAMETER; + } + + Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This); + + Status = EFI_SUCCESS; + + + switch (PortFeature) { + case EfiUsbPortPower: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortReset: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 || + OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + + OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); + break; + + case EfiUsbPortEnable: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND);; + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + + case EfiUsbPortSuspend: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND);; + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + Clears a feature for the specified root hub port. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI. + @param PortNumber Specifies the root hub port whose feature + is requested to be cleared. + @param PortFeature Indicates the feature selector associated with the + feature clear request. + + @retval EFI_SUCCESS The feature specified by PortFeature was cleared + for the USB root hub port specified by PortNumber. + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. + +**/ + +EFI_STATUS +EFIAPI +OhciClearRootHubPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + UINT8 NumOfPorts; + UINTN RetryTimes; + + + OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts); + if (PortNumber >= NumOfPorts) { + return EFI_INVALID_PARAMETER; + } + + Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This); + + Status = EFI_SUCCESS; + + switch (PortFeature) { + case EfiUsbPortEnable: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortSuspend: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortReset: + break; + + case EfiUsbPortPower: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortConnectChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortResetChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + + case EfiUsbPortEnableChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortSuspendChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortOverCurrentChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + MicroSecondDelay (HC_1_MILLISECOND); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return Status; +} +/** + Provides software reset for the USB host controller. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param Attributes A bit mask of the reset operation to perform. + + @retval EFI_SUCCESS The reset operation succeeded. + @retval EFI_INVALID_PARAMETER Attributes is not valid. + @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is + not currently supported by the host controller. + @retval EFI_DEVICE_ERROR Host controller isn't halted to reset. + +**/ +EFI_STATUS +InitializeUsbHC ( + IN EFI_PEI_SERVICES **PeiServices, + IN USB_OHCI_HC_DEV *Ohc, + IN UINT16 Attributes + ) +{ + EFI_STATUS Status; + UINT8 Index; + UINT8 NumOfPorts; + UINT32 PowerOnGoodTime; + UINT32 Data32; + BOOLEAN Flag = FALSE; + + if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) { + return EFI_INVALID_PARAMETER; + } + Status = EFI_SUCCESS; + + if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) { + MicroSecondDelay (50 * HC_1_MILLISECOND); + Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + MicroSecondDelay (50 * HC_1_MILLISECOND); + // + // Wait for host controller reset. + // + PowerOnGoodTime = 50; + do { + MicroSecondDelay (HC_1_MILLISECOND); + Data32 = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS ); + if ((Data32 & HC_RESET) == 0) { + Flag = TRUE; + break; + } + }while(PowerOnGoodTime--); + if (!Flag){ + return EFI_DEVICE_ERROR; + } + } + + OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); + if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) { + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + MicroSecondDelay (50 * HC_1_MILLISECOND); + } + // + // Initialize host controller operational registers + // + OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778); + OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); + OhciSetPeriodicStart (Ohc, 0x2a2f); + OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x0); + OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0); + OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0); + OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1); + //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0); + //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1); + + OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0); + OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff); + OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE); + OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER); + OhciGetRootHubNumOfPorts (PeiServices, &Ohc->UsbHostControllerPpi, &NumOfPorts); + for (Index = 0; Index < NumOfPorts; Index++) { + if (!EFI_ERROR (OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset))) { + MicroSecondDelay (200 * HC_1_MILLISECOND); + OhciClearRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset); + MicroSecondDelay (HC_1_MILLISECOND); + OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortEnable); + MicroSecondDelay (HC_1_MILLISECOND); + } + } + + Ohc->MemPool = UsbHcInitMemPool(TRUE, 0); + if(Ohc->MemPool == NULL) { + return EFI_OUT_OF_RESOURCES; + } + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); + OhciSetHcControl (Ohc, CONTROL_ENABLE | BULK_ENABLE, 1); + OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL); + MicroSecondDelay (50 * HC_1_MILLISECOND); + // + // Wait till first SOF occurs, and then clear it + // + while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0); + OhciClearInterruptStatus (Ohc, START_OF_FRAME); + MicroSecondDelay (HC_1_MILLISECOND); + + return EFI_SUCCESS; +} + +/** + Submits control transfer to a target USB device. + + Calls underlying OhciControlTransfer to do work. This wrapper routine required + on Quark so that USB DMA transfers do not cause an IMR violation. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI. + @param DeviceAddress The target device address. + @param DeviceSpeed Target device speed. + @param MaximumPacketLength Maximum packet size the default control transfer + endpoint is capable of sending or receiving. + @param Request USB device request to send. + @param TransferDirection Specifies the data direction for the data stage. + @param Data Data buffer to be transmitted or received from USB device. + @param DataLength The size (in bytes) of the data buffer. + @param TimeOut Indicates the maximum timeout, in millisecond. + @param TransferResult Return the result of this control transfer. + + @retval EFI_SUCCESS Transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT Transfer failed due to timeout. + @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. + +**/ +EFI_STATUS +EFIAPI +RedirectOhciControlTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 DeviceAddress, + IN UINT8 DeviceSpeed, + IN UINT8 MaxPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + EFI_STATUS Status; + EFI_USB_DEVICE_REQUEST *NewRequest; + VOID *NewData; + UINT8 *Alloc; + + // + // Allocate memory external to IMR protected region for transfer data. + // + Status = PeiServicesAllocatePool ( + sizeof(EFI_USB_DEVICE_REQUEST) + *DataLength, + (VOID **) &Alloc + ); + ASSERT_EFI_ERROR (Status); + + // + // Setup pointers to transfer buffers. + // + NewRequest = (EFI_USB_DEVICE_REQUEST *) Alloc; + Alloc += sizeof(EFI_USB_DEVICE_REQUEST); + NewData = (VOID *) Alloc; + + // + // Copy callers request packet into transfer request packet. + // + if (Request != NULL) { + CopyMem (NewRequest,Request,sizeof(EFI_USB_DEVICE_REQUEST)); + } else { + NewRequest = NULL; + } + // + // Copy callers data into transfer data buffer. + // + if (Data != NULL) { + if (DataLength > 0) { + CopyMem (NewData,Data,*DataLength); + } + } else { + NewData = NULL; + } + + // + // Call underlying OhciControlTransfer to do work. + // + Status = OhciControlTransfer ( + PeiServices, + This, + DeviceAddress, + DeviceSpeed, + MaxPacketLength, + NewRequest, + TransferDirection, + NewData, + DataLength, + TimeOut, + TransferResult + ); + + // + // Copy transfer buffer back into callers buffer. + // + if (Data != NULL && *DataLength > 0) { + CopyMem (Data, NewData, *DataLength); + } + + return Status; +} + +/** + Submits bulk transfer to a bulk endpoint of a USB device. + + Calls underlying OhciBulkTransfer to do work. This wrapper routine required + on Quark so that USB DMA transfers do not cause an IMR violation. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI. + @param DeviceAddress Target device address. + @param EndPointAddress Endpoint number and its direction in bit 7. + @param MaxiPacketLength Maximum packet size the endpoint is capable of + sending or receiving. + @param Data A pointers to the buffers of data to transmit + from or receive into. + @param DataLength The lenght of the data buffer. + @param DataToggle On input, the initial data toggle for the transfer; + On output, it is updated to to next data toggle to use of + the subsequent bulk transfer. + @param TimeOut Indicates the maximum time, in millisecond, which the + transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information of the + bulk transfer. + + @retval EFI_SUCCESS The transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. + @retval EFI_INVALID_PARAMETER Parameters are invalid. + @retval EFI_TIMEOUT The transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. + +**/ +EFI_STATUS +EFIAPI +RedirectOhciBulkTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + EFI_STATUS Status; + UINT8 *NewData; + + // + // Allocate memory external to IMR protected region for transfer data. + // + Status = PeiServicesAllocatePool ( + *DataLength, + (VOID **) &NewData + ); + ASSERT_EFI_ERROR (Status); + + // + // Copy callers data into transfer buffer. + // + if (Data != NULL) { + if (DataLength > 0) { + CopyMem (NewData,Data,*DataLength); + } + } else { + NewData = NULL; + } + + // + // Call underlying OhciBulkTransfer to do work. + // + Status = OhciBulkTransfer ( + PeiServices, + This, + DeviceAddress, + EndPointAddress, + MaxPacketLength, + NewData, + DataLength, + DataToggle, + TimeOut, + TransferResult + ); + + // + // Copy transfer buffer back into callers buffer. + // + if (Data != NULL && *DataLength > 0) { + CopyMem (Data, NewData, *DataLength); + } + + return Status; +} + +/** + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS PPI successfully installed. + +**/ +EFI_STATUS +OhcPeimEntry ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + + PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi; + EFI_STATUS Status; + UINT8 Index; + UINTN ControllerType; + UINTN BaseAddress; + UINTN MemPages; + USB_OHCI_HC_DEV *Ohc; + EFI_PHYSICAL_ADDRESS TempPtr; + + + // + // Shadow this PEIM to run from memory + // + if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { + return EFI_SUCCESS; + } + Status = PeiServicesLocatePpi ( + &gPeiUsbControllerPpiGuid, + 0, + NULL, + (VOID **) &ChipSetUsbControllerPpi + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Index = 0; + while (TRUE) { + Status = ChipSetUsbControllerPpi->GetUsbController ( + (EFI_PEI_SERVICES **) PeiServices, + ChipSetUsbControllerPpi, + Index, + &ControllerType, + &BaseAddress + ); + // + // When status is error, meant no controller is found + // + if (EFI_ERROR (Status)) { + break; + } + // + // This PEIM is for OHC type controller. + // + if (ControllerType != PEI_OHCI_CONTROLLER) { + Index++; + continue; + } + + MemPages = sizeof (USB_OHCI_HC_DEV) / PAGESIZE + 1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &TempPtr + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to allocate buffer for the %dth OHCI ControllerPpi\n", Index)); + return EFI_OUT_OF_RESOURCES; + } + ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE); + Ohc = (USB_OHCI_HC_DEV *) ((UINTN) TempPtr); + + Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE; + + Ohc->UsbHostControllerBaseAddress = (UINT32) BaseAddress; + + // + // Initialize Uhc's hardware + // + Status = InitializeUsbHC ( + (EFI_PEI_SERVICES **)PeiServices, + Ohc, + EFI_USB_HC_RESET_GLOBAL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to init %dth OHCI ControllerPpi\n", Index)); + return Status; + } + // + // Control & Bulk transfer services are accessed via their Redirect + // routine versions on Quark so that USB DMA transfers do not cause an + // IMR violation. + // + Ohc->UsbHostControllerPpi.ControlTransfer = RedirectOhciControlTransfer; + Ohc->UsbHostControllerPpi.BulkTransfer = RedirectOhciBulkTransfer; + Ohc->UsbHostControllerPpi.GetRootHubPortNumber = OhciGetRootHubNumOfPorts; + Ohc->UsbHostControllerPpi.GetRootHubPortStatus = OhciGetRootHubPortStatus; + Ohc->UsbHostControllerPpi.SetRootHubPortFeature = OhciSetRootHubPortFeature; + Ohc->UsbHostControllerPpi.ClearRootHubPortFeature = OhciClearRootHubPortFeature; + + Ohc->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); + Ohc->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid; + Ohc->PpiDescriptor.Ppi = &Ohc->UsbHostControllerPpi; + + Status = PeiServicesInstallPpi (&Ohc->PpiDescriptor); + if (EFI_ERROR (Status)) { + Index++; + continue; + } + Index++; + } + return EFI_SUCCESS; +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h new file mode 100644 index 0000000000..c34f94cdd7 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.h @@ -0,0 +1,252 @@ +/** @file +Provides the definition of Usb Hc Protocol and OHCI controller +private data structure. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _OHCI_PEIM_H +#define _OHCI_PEIM_H + +#include + +#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/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf new file mode 100644 index 0000000000..b1060d527d --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf @@ -0,0 +1,56 @@ +## @file +# OHCI USB Host Controller PEIM +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = OhciPei + FILE_GUID = 332A0926-429B-4624-9211-A36B23DF0389 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = OhcPeimEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + Descriptor.h + OhcPeim.c + OhcPeim.h + OhciSched.c + OhciSched.h + OhciReg.c + OhciReg.h + OhciUrb.c + OhciUrb.h + UsbHcMem.c + UsbHcMem.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + IoLib + TimerLib + BaseMemoryLib + PeimEntryPoint + PeiServicesLib + +[Ppis] + gPeiUsbHostControllerPpiGuid # PPI ALWAYS_PRODUCED + gPeiUsbControllerPpiGuid # PPI ALWAYS_CONSUMED + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c new file mode 100644 index 0000000000..b291cdafa6 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.c @@ -0,0 +1,1386 @@ +/** @file +The OHCI register operation routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "OhcPeim.h" + +/** + + Get OHCI operational reg value + + @param Ohc UHC private data + @param Offset Offset of the operational reg + + @retval Value of the register + +**/ +UINT32 +OhciGetOperationalReg ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Offset + ) +{ + + return MmioRead32 (Ohc->UsbHostControllerBaseAddress + Offset); + +} +/** + + Set OHCI operational reg value + + @param Ohc UHC private data + @param Offset Offset of the operational reg + @param Value Value to set + + @retval EFI_SUCCESS Value set to the reg + +**/ + + +EFI_STATUS +OhciSetOperationalReg ( + USB_OHCI_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT32 *Value + ) +{ + MmioWrite32(Ohc->UsbHostControllerBaseAddress + Offset, *Value); + return EFI_SUCCESS; +} +/** + + Get HcRevision reg value + + @param Ohc UHC private data + + @retval Value of the register + +**/ + + +UINT32 +OhciGetHcRevision ( + USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg (Ohc, HC_REVISION); +} +/** + + Set HcReset reg value + + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field, + IN UINT32 Value + ) +{ + HcRESET Reset; + + *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR); + + if (Field & RESET_SYSTEM_BUS) { + Reset.FSBIR = Value; + } + + if (Field & RESET_HOST_CONTROLLER) { + Reset.FHR = Value; + } + + if (Field & RESET_CLOCK_GENERATION) { + Reset.CGR = Value; + } + + if (Field & RESET_SSE_GLOBAL) { + Reset.SSE = Value; + } + + if (Field & RESET_PSPL) { + Reset.PSPL = Value; + } + + if (Field & RESET_PCPL) { + Reset.PCPL = Value; + } + + if (Field & RESET_SSEP1) { + Reset.SSEP1 = Value; + } + + if (Field & RESET_SSEP2) { + Reset.SSEP2 = Value; + } + + if (Field & RESET_SSEP3) { + Reset.SSEP3 = Value; + } + + OhciSetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR, (UINT32*)&Reset); + + return EFI_SUCCESS; +} + +/** + + Get specific field of HcReset reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field + ) +{ + HcRESET Reset; + UINT32 Value; + + + *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR); + Value = 0; + + switch (Field) { + case RESET_SYSTEM_BUS: + Value = Reset.FSBIR; + break; + + case RESET_HOST_CONTROLLER: + Value = Reset.FHR; + break; + + case RESET_CLOCK_GENERATION: + Value = Reset.CGR; + break; + + case RESET_SSE_GLOBAL: + Value = Reset.SSE; + break; + + case RESET_PSPL: + Value = Reset.PSPL; + break; + + case RESET_PCPL: + Value = Reset.PCPL; + break; + + case RESET_SSEP1: + Value = Reset.SSEP1; + break; + + case RESET_SSEP2: + Value = Reset.SSEP2; + break; + + case RESET_SSEP3: + Value = Reset.SSEP3; + break; + + default: + ASSERT (FALSE); + } + + + return Value; +} + +/** + + Set HcControl reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcCONTROL Control; + + + + *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL); + + if (Field & CONTROL_BULK_RATIO) { + Control.ControlBulkRatio = Value; + } + + if (Field & HC_FUNCTIONAL_STATE) { + Control.FunctionalState = Value; + } + + if (Field & PERIODIC_ENABLE) { + Control.PeriodicEnable = Value; + } + + if (Field & CONTROL_ENABLE) { + Control.ControlEnable = Value; + } + + if (Field & ISOCHRONOUS_ENABLE) { + Control.IsochronousEnable = Value; + } + + if (Field & BULK_ENABLE) { + Control.BulkEnable = Value; + } + + if (Field & INTERRUPT_ROUTING) { + Control.InterruptRouting = Value; + } + + Status = OhciSetOperationalReg (Ohc, HC_CONTROL, (UINT32*)&Control); + + return Status; +} + + +/** + + Get specific field of HcControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + + +UINT32 +OhciGetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcCONTROL Control; + + *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL); + + switch (Field) { + case CONTROL_BULK_RATIO: + return Control.ControlBulkRatio; + break; + case PERIODIC_ENABLE: + return Control.PeriodicEnable; + break; + case CONTROL_ENABLE: + return Control.ControlEnable; + break; + case BULK_ENABLE: + return Control.BulkEnable; + break; + case ISOCHRONOUS_ENABLE: + return Control.IsochronousEnable; + break; + case HC_FUNCTIONAL_STATE: + return Control.FunctionalState; + break; + case INTERRUPT_ROUTING: + return Control.InterruptRouting; + break; + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set HcCommand reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcCOMMAND_STATUS CommandStatus; + + ZeroMem (&CommandStatus, sizeof (HcCOMMAND_STATUS)); + + if(Field & HC_RESET){ + CommandStatus.HcReset = Value; + } + + if(Field & CONTROL_LIST_FILLED){ + CommandStatus.ControlListFilled = Value; + } + + if(Field & BULK_LIST_FILLED){ + CommandStatus.BulkListFilled = Value; + } + + if(Field & CHANGE_OWNER_REQUEST){ + CommandStatus.ChangeOwnerRequest = Value; + } + + if(Field & SCHEDULE_OVERRUN_COUNT){ + CommandStatus.ScheduleOverrunCount = Value; + } + + Status = OhciSetOperationalReg (Ohc, HC_COMMAND_STATUS, (UINT32*)&CommandStatus); + + return Status; +} + +/** + + Get specific field of HcCommand reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcCOMMAND_STATUS CommandStatus; + + *(UINT32 *) &CommandStatus = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS); + + switch (Field){ + case HC_RESET: + return CommandStatus.HcReset; + break; + case CONTROL_LIST_FILLED: + return CommandStatus.ControlListFilled; + break; + case BULK_LIST_FILLED: + return CommandStatus.BulkListFilled; + break; + case CHANGE_OWNER_REQUEST: + return CommandStatus.ChangeOwnerRequest; + break; + case SCHEDULE_OVERRUN_COUNT: + return CommandStatus.ScheduleOverrunCount; + break; + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Clear specific fields of Interrupt Status + + @param Ohc UHC private data + @param Field Field to clear + + @retval EFI_SUCCESS Fields cleared + +**/ + +EFI_STATUS +OhciClearInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + EFI_STATUS Status; + HcINTERRUPT_STATUS InterruptStatus; + + ZeroMem (&InterruptStatus, sizeof (HcINTERRUPT_STATUS)); + + if(Field & SCHEDULE_OVERRUN){ + InterruptStatus.SchedulingOverrun = 1; + } + + if(Field & WRITEBACK_DONE_HEAD){ + InterruptStatus.WriteBackDone = 1; + } + if(Field & START_OF_FRAME){ + InterruptStatus.Sof = 1; + } + + if(Field & RESUME_DETECT){ + InterruptStatus.ResumeDetected = 1; + } + + if(Field & UNRECOVERABLE_ERROR){ + InterruptStatus.UnrecoverableError = 1; + } + + if(Field & FRAME_NUMBER_OVERFLOW){ + InterruptStatus.FrameNumOverflow = 1; + } + + if(Field & ROOTHUB_STATUS_CHANGE){ + InterruptStatus.RHStatusChange = 1; + } + + if(Field & OWNERSHIP_CHANGE){ + InterruptStatus.OwnerChange = 1; + } + + Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_STATUS, (UINT32*)&InterruptStatus); + + return Status; +} + +/** + + Get fields of HcInterrupt reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcINTERRUPT_STATUS InterruptStatus; + + *(UINT32 *) &InterruptStatus = OhciGetOperationalReg (Ohc, HC_INTERRUPT_STATUS); + + switch (Field){ + case SCHEDULE_OVERRUN: + return InterruptStatus.SchedulingOverrun; + break; + + case WRITEBACK_DONE_HEAD: + return InterruptStatus.WriteBackDone; + break; + + case START_OF_FRAME: + return InterruptStatus.Sof; + break; + + case RESUME_DETECT: + return InterruptStatus.ResumeDetected; + break; + + case UNRECOVERABLE_ERROR: + return InterruptStatus.UnrecoverableError; + break; + + case FRAME_NUMBER_OVERFLOW: + return InterruptStatus.FrameNumOverflow; + break; + + case ROOTHUB_STATUS_CHANGE: + return InterruptStatus.RHStatusChange; + break; + + case OWNERSHIP_CHANGE: + return InterruptStatus.OwnerChange; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set Interrupt Control reg value + + @param Ohc UHC private data + @param StatEnable Enable or Disable + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN BOOLEAN StatEnable, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcINTERRUPT_CONTROL InterruptState; + + + ZeroMem (&InterruptState, sizeof (HcINTERRUPT_CONTROL)); + + if(Field & SCHEDULE_OVERRUN) { + InterruptState.SchedulingOverrunInt = Value; + } + + if(Field & WRITEBACK_DONE_HEAD) { + InterruptState.WriteBackDoneInt = Value; + } + if(Field & START_OF_FRAME) { + InterruptState.SofInt = Value; + } + + if(Field & RESUME_DETECT) { + InterruptState.ResumeDetectedInt = Value; + } + + if(Field & UNRECOVERABLE_ERROR) { + InterruptState.UnrecoverableErrorInt = Value; + } + + if(Field & FRAME_NUMBER_OVERFLOW) { + InterruptState.FrameNumOverflowInt = Value; + } + + if(Field & ROOTHUB_STATUS_CHANGE) { + InterruptState.RHStatusChangeInt = Value; + } + + if(Field & OWNERSHIP_CHANGE) { + InterruptState.OwnerChangedInt = Value; + } + + if(Field & MASTER_INTERRUPT) { + InterruptState.MasterInterruptEnable = Value; + } + + if (StatEnable) { + Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_ENABLE, (UINT32*)&InterruptState); + } else { + Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_DISABLE, (UINT32*)&InterruptState); + } + + return Status; +} + +/** + + Get field of HcInterruptControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcINTERRUPT_CONTROL InterruptState; + + *(UINT32 *) &InterruptState = OhciGetOperationalReg (Ohc, HC_INTERRUPT_ENABLE); + + switch (Field){ + case SCHEDULE_OVERRUN: + return InterruptState.SchedulingOverrunInt; + break; + + case WRITEBACK_DONE_HEAD: + return InterruptState.WriteBackDoneInt; + break; + + case START_OF_FRAME: + return InterruptState.SofInt; + break; + + case RESUME_DETECT: + return InterruptState.ResumeDetectedInt; + break; + + case UNRECOVERABLE_ERROR: + return InterruptState.UnrecoverableErrorInt; + break; + + case FRAME_NUMBER_OVERFLOW: + return InterruptState.FrameNumOverflowInt; + break; + + case ROOTHUB_STATUS_CHANGE: + return InterruptState.RHStatusChangeInt; + break; + + case OWNERSHIP_CHANGE: + return InterruptState.OwnerChangedInt; + break; + + case MASTER_INTERRUPT: + return InterruptState.MasterInterruptEnable; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of the pointer to set + @param Value Value to set + + @retval EFI_SUCCESS Memory pointer set + +**/ + +EFI_STATUS +OhciSetMemoryPointer( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN PointerType, + IN VOID *Value + ) +{ + EFI_STATUS Status; + UINT32 Verify; + + Status = OhciSetOperationalReg (Ohc, PointerType, (UINT32*)&Value); + + if (EFI_ERROR (Status)) { + return Status; + } + + Verify = OhciGetOperationalReg (Ohc, PointerType); + + while (Verify != (UINT32) Value) { + MicroSecondDelay (HC_1_MILLISECOND); + Verify = OhciGetOperationalReg (Ohc, PointerType); + }; + + + return Status; +} + +/** + + Get memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of pointer + + @retval Memory pointer of the specific type + +**/ + +VOID * +OhciGetMemoryPointer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN PointerType + ) +{ + + return (VOID *) OhciGetOperationalReg (Ohc, PointerType); +} + + +/** + + Set Frame Interval value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcFRM_INTERVAL FrameInterval; + + + *(UINT32 *) &FrameInterval = OhciGetOperationalReg(Ohc, HC_FRM_INTERVAL); + + if (Field & FRAME_INTERVAL) { + FrameInterval.FrmIntervalToggle = !FrameInterval.FrmIntervalToggle; + FrameInterval.FrameInterval = Value; + } + + if (Field & FS_LARGEST_DATA_PACKET) { + FrameInterval.FSMaxDataPacket = Value; + } + + if (Field & FRMINT_TOGGLE) { + FrameInterval.FrmIntervalToggle = Value; + } + + Status = OhciSetOperationalReg ( + Ohc, + HC_FRM_INTERVAL, + (UINT32*)&FrameInterval + ); + + return Status; +} + + +/** + + Get field of frame interval reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcFRM_INTERVAL FrameInterval; + + *(UINT32 *) &FrameInterval = OhciGetOperationalReg (Ohc, HC_FRM_INTERVAL); + + switch (Field){ + case FRAME_INTERVAL: + return FrameInterval.FrameInterval; + break; + + case FS_LARGEST_DATA_PACKET: + return FrameInterval.FSMaxDataPacket; + break; + + case FRMINT_TOGGLE: + return FrameInterval.FrmIntervalToggle; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set Frame Remaining reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcFRAME_REMAINING FrameRemaining; + + + *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING); + + FrameRemaining.FrameRemaining = Value; + FrameRemaining.FrameRemainingToggle = !FrameRemaining.FrameRemainingToggle; + + Status = OhciSetOperationalReg (Ohc, HC_FRM_REMAINING, (UINT32*)&FrameRemaining); + + return Status; +} +/** + + Get value of frame remaining reg + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of frame remaining reg + +**/ +UINT32 +OhciGetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) + +{ + HcFRAME_REMAINING FrameRemaining; + + + *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING); + + switch (Field){ + case FRAME_REMAINING: + return FrameRemaining.FrameRemaining; + break; + + case FRAME_REMAIN_TOGGLE: + return FrameRemaining.FrameRemainingToggle; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set frame number reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameNumber( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + Status = OhciSetOperationalReg (Ohc, HC_FRM_NUMBER, &Value); + + return Status; +} + +/** + + Get frame number reg value + + @param Ohc UHC private data + + @retval Value of frame number reg + +**/ + +UINT32 +OhciGetFrameNumber ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg(Ohc, HC_FRM_NUMBER); +} + +/** + + Set period start reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + + Status = OhciSetOperationalReg (Ohc, HC_PERIODIC_START, &Value); + + return Status; +} + + +/** + + Get periodic start reg value + + @param Ohc UHC private data + + @param Value of periodic start reg + +**/ + +UINT32 +OhciGetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg(Ohc, HC_PERIODIC_START); +} + + +/** + + Set Ls Threshold reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + + Status = OhciSetOperationalReg (Ohc, HC_LS_THREASHOLD, &Value); + + return Status; +} + + +/** + + Get Ls Threshold reg value + + @param Ohc UHC private data + + @retval Value of Ls Threshold reg + +**/ + +UINT32 +OhciGetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg(Ohc, HC_LS_THREASHOLD); +} + +/** + + Set Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcRH_DESC_A DescriptorA; + HcRH_DESC_B DescriptorB; + + + if (Field & (RH_DEV_REMOVABLE || RH_PORT_PWR_CTRL_MASK)) { + *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B); + + if(Field & RH_DEV_REMOVABLE) { + DescriptorB.DeviceRemovable = Value; + } + if(Field & RH_PORT_PWR_CTRL_MASK) { + DescriptorB.PortPowerControlMask = Value; + } + + Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_B, (UINT32*)&DescriptorB); + + return Status; + } + + *(UINT32 *)&DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A); + + if(Field & RH_NUM_DS_PORTS) { + DescriptorA.NumDownStrmPorts = Value; + } + if(Field & RH_NO_PSWITCH) { + DescriptorA.NoPowerSwitch = Value; + } + if(Field & RH_PSWITCH_MODE) { + DescriptorA.PowerSwitchMode = Value; + } + if(Field & RH_DEVICE_TYPE) { + DescriptorA.DeviceType = Value; + } + if(Field & RH_OC_PROT_MODE) { + DescriptorA.OverCurrentProtMode = Value; + } + if(Field & RH_NOC_PROT) { + DescriptorA.NoOverCurrentProtMode = Value; + } + if(Field & RH_NO_POTPGT) { + DescriptorA.PowerOnToPowerGoodTime = Value; + } + + Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_A, (UINT32*)&DescriptorA); + + return Status; +} + + +/** + + Get Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcRH_DESC_A DescriptorA; + HcRH_DESC_B DescriptorB; + + + *(UINT32 *) &DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A); + *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B); + + switch (Field){ + case RH_DEV_REMOVABLE: + return DescriptorB.DeviceRemovable; + break; + + case RH_PORT_PWR_CTRL_MASK: + return DescriptorB.PortPowerControlMask; + break; + + case RH_NUM_DS_PORTS: + return DescriptorA.NumDownStrmPorts; + break; + + case RH_NO_PSWITCH: + return DescriptorA.NoPowerSwitch; + break; + + case RH_PSWITCH_MODE: + return DescriptorA.PowerSwitchMode; + break; + + case RH_DEVICE_TYPE: + return DescriptorA.DeviceType; + break; + + case RH_OC_PROT_MODE: + return DescriptorA.OverCurrentProtMode; + break; + + case RH_NOC_PROT: + return DescriptorA.NoOverCurrentProtMode; + break; + + case RH_NO_POTPGT: + return DescriptorA.PowerOnToPowerGoodTime; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + + +/** + + Set Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + EFI_STATUS Status; + HcRH_STATUS RootHubStatus; + + + ZeroMem (&RootHubStatus, sizeof(HcRH_STATUS)); + + if(Field & RH_LOCAL_PSTAT){ + RootHubStatus.LocalPowerStat = 1; + } + if(Field & RH_OC_ID){ + RootHubStatus.OverCurrentIndicator = 1; + } + if(Field & RH_REMOTE_WK_ENABLE){ + RootHubStatus.DevRemoteWakeupEnable = 1; + } + if(Field & RH_LOCAL_PSTAT_CHANGE){ + RootHubStatus.LocalPowerStatChange = 1; + } + if(Field & RH_OC_ID_CHANGE){ + RootHubStatus.OverCurrentIndicatorChange = 1; + } + if(Field & RH_CLR_RMT_WK_ENABLE){ + RootHubStatus.ClearRemoteWakeupEnable = 1; + } + + Status = OhciSetOperationalReg (Ohc, HC_RH_STATUS, (UINT32*)&RootHubStatus); + + return Status; +} + + +/** + + Get Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcRH_STATUS RootHubStatus; + + + *(UINT32 *) &RootHubStatus = OhciGetOperationalReg (Ohc, HC_RH_STATUS); + + switch (Field) { + case RH_LOCAL_PSTAT: + return RootHubStatus.LocalPowerStat; + break; + case RH_OC_ID: + return RootHubStatus.OverCurrentIndicator; + break; + case RH_REMOTE_WK_ENABLE: + return RootHubStatus.DevRemoteWakeupEnable; + break; + case RH_LOCAL_PSTAT_CHANGE: + return RootHubStatus.LocalPowerStatChange; + break; + case RH_OC_ID_CHANGE: + return RootHubStatus.OverCurrentIndicatorChange; + break; + case RH_CLR_RMT_WK_ENABLE: + return RootHubStatus.ClearRemoteWakeupEnable; + break; + default: + ASSERT (FALSE); + } + + return 0; +} + + +/** + + Set Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ) +{ + EFI_STATUS Status; + HcRHPORT_STATUS PortStatus; + + + ZeroMem (&PortStatus, sizeof(HcRHPORT_STATUS)); + + if (Field & RH_CLEAR_PORT_ENABLE) { + PortStatus.CurrentConnectStat = 1; + } + if (Field & RH_SET_PORT_ENABLE) { + PortStatus.EnableStat = 1; + } + if (Field & RH_SET_PORT_SUSPEND) { + PortStatus.SuspendStat = 1; + } + if (Field & RH_CLEAR_SUSPEND_STATUS) { + PortStatus.OCIndicator = 1; + } + if (Field & RH_SET_PORT_RESET) { + PortStatus.ResetStat = 1; + } + if (Field & RH_SET_PORT_POWER) { + PortStatus.PowerStat = 1; + } + if (Field & RH_CLEAR_PORT_POWER) { + PortStatus.LsDeviceAttached = 1; + } + if (Field & RH_CONNECT_STATUS_CHANGE) { + PortStatus.ConnectStatChange = 1; + } + if (Field & RH_PORT_ENABLE_STAT_CHANGE) { + PortStatus.EnableStatChange = 1; + } + if (Field & RH_PORT_SUSPEND_STAT_CHANGE) { + PortStatus.SuspendStatChange = 1; + } + if (Field & RH_OC_INDICATOR_CHANGE) { + PortStatus.OCIndicatorChange = 1; + } + if (Field & RH_PORT_RESET_STAT_CHANGE ) { + PortStatus.ResetStatChange = 1; + } + + Status = OhciSetOperationalReg (Ohc, HC_RH_PORT_STATUS + (Index * 4), (UINT32*)&PortStatus); + + return Status; +} + + +/** + + Get Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to get + + @retval Value of the field and index + +**/ + +UINT32 +OhciReadRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ) +{ + HcRHPORT_STATUS PortStatus; + + *(UINT32 *) &PortStatus = OhciGetOperationalReg ( + Ohc, + HC_RH_PORT_STATUS + (Index * 4) + ); + + switch (Field){ + case RH_CURR_CONNECT_STAT: + return PortStatus.CurrentConnectStat; + break; + case RH_PORT_ENABLE_STAT: + return PortStatus.EnableStat; + break; + case RH_PORT_SUSPEND_STAT: + return PortStatus.SuspendStat; + break; + case RH_PORT_OC_INDICATOR: + return PortStatus.OCIndicator; + break; + case RH_PORT_RESET_STAT: + return PortStatus.ResetStat; + break; + case RH_PORT_POWER_STAT: + return PortStatus.PowerStat; + break; + case RH_LSDEVICE_ATTACHED: + return PortStatus.LsDeviceAttached; + break; + case RH_CONNECT_STATUS_CHANGE: + return PortStatus.ConnectStatChange; + break; + case RH_PORT_ENABLE_STAT_CHANGE: + return PortStatus.EnableStatChange; + break; + case RH_PORT_SUSPEND_STAT_CHANGE: + return PortStatus.SuspendStatChange; + break; + case RH_OC_INDICATOR_CHANGE: + return PortStatus.OCIndicatorChange; + break; + case RH_PORT_RESET_STAT_CHANGE: + return PortStatus.ResetStatChange; + break; + default: + ASSERT (FALSE); + } + + return 0; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h new file mode 100644 index 0000000000..9b31bf53ee --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciReg.h @@ -0,0 +1,875 @@ +/** @file +This file contains the definination for host controller +register operation routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _OHCI_REGS_H +#define _OHCI_REGS_H + +#define HC_STATE_RESET 0x0 +#define HC_STATE_RESUME 0x1 +#define HC_STATE_OPERATIONAL 0x2 +#define HC_STATE_SUSPEND 0x3 + +#define PERIODIC_ENABLE 0x01 +#define ISOCHRONOUS_ENABLE 0x02 +#define CONTROL_ENABLE 0x04 +#define BULK_ENABLE 0x08 +#define CONTROL_BULK_RATIO 0x10 + +#define HC_FUNCTIONAL_STATE 0x20 +#define INTERRUPT_ROUTING 0x40 + +#define HC_RESET 0x01 +#define CONTROL_LIST_FILLED 0x02 +#define BULK_LIST_FILLED 0x04 +#define CHANGE_OWNER_REQUEST 0x08 + +#define SCHEDULE_OVERRUN_COUNT 0x10 + +#define SCHEDULE_OVERRUN 0x00001 +#define WRITEBACK_DONE_HEAD 0x00002 +#define START_OF_FRAME 0x00004 +#define RESUME_DETECT 0x00008 +#define UNRECOVERABLE_ERROR 0x00010 +#define FRAME_NUMBER_OVERFLOW 0x00020 +#define ROOTHUB_STATUS_CHANGE 0x00040 +#define OWNERSHIP_CHANGE 0x00080 + +#define MASTER_INTERRUPT 0x00400 + +#define CONTROL_HEAD 0x001 +#define BULK_HEAD 0x002 +#define DONE_HEAD 0x004 + +#define Hc_HCCA 0x001 +#define Hc_PERIODIC_CURRENT 0x002 +#define Hc_CONTOL_HEAD 0x004 +#define Hc_CONTROL_CURRENT_PTR 0x008 +#define Hc_BULK_HEAD 0x010 +#define Hc_BULK_CURRENT_PTR 0x020 +#define Hc_DONE_HEAD 0x040 + +#define FRAME_INTERVAL 0x008 +#define FS_LARGEST_DATA_PACKET 0x010 +#define FRMINT_TOGGLE 0x020 +#define FRAME_REMAINING 0x040 +#define FRAME_REMAIN_TOGGLE 0x080 + +#define RH_DESC_A 0x00001 +#define RH_DESC_B 0x00002 +#define RH_NUM_DS_PORTS 0x00004 +#define RH_NO_PSWITCH 0x00008 +#define RH_PSWITCH_MODE 0x00010 +#define RH_DEVICE_TYPE 0x00020 +#define RH_OC_PROT_MODE 0x00040 +#define RH_NOC_PROT 0x00080 +#define RH_POTPGT 0x00100 +#define RH_NO_POTPGT 0x00200 +#define RH_DEV_REMOVABLE 0x00400 +#define RH_PORT_PWR_CTRL_MASK 0x00800 + +#define RH_LOCAL_PSTAT 0x00001 +#define RH_OC_ID 0x00002 +#define RH_REMOTE_WK_ENABLE 0x00004 +#define RH_LOCAL_PSTAT_CHANGE 0x00008 +#define RH_OC_ID_CHANGE 0x00010 +#define RH_CLR_RMT_WK_ENABLE 0x00020 + +#define RH_CLEAR_PORT_ENABLE 0x0001 +#define RH_SET_PORT_ENABLE 0x0002 +#define RH_SET_PORT_SUSPEND 0x0004 +#define RH_CLEAR_SUSPEND_STATUS 0x0008 +#define RH_SET_PORT_RESET 0x0010 +#define RH_SET_PORT_POWER 0x0020 +#define RH_CLEAR_PORT_POWER 0x0040 +#define RH_CONNECT_STATUS_CHANGE 0x10000 +#define RH_PORT_ENABLE_STAT_CHANGE 0x20000 +#define RH_PORT_SUSPEND_STAT_CHANGE 0x40000 +#define RH_OC_INDICATOR_CHANGE 0x80000 +#define RH_PORT_RESET_STAT_CHANGE 0x100000 + +#define RH_CURR_CONNECT_STAT 0x0001 +#define RH_PORT_ENABLE_STAT 0x0002 +#define RH_PORT_SUSPEND_STAT 0x0004 +#define RH_PORT_OC_INDICATOR 0x0008 +#define RH_PORT_RESET_STAT 0x0010 +#define RH_PORT_POWER_STAT 0x0020 +#define RH_LSDEVICE_ATTACHED 0x0040 + +#define RESET_SYSTEM_BUS (1 << 0) +#define RESET_HOST_CONTROLLER (1 << 1) +#define RESET_CLOCK_GENERATION (1 << 2) +#define RESET_SSE_GLOBAL (1 << 5) +#define RESET_PSPL (1 << 6) +#define RESET_PCPL (1 << 7) +#define RESET_SSEP1 (1 << 9) +#define RESET_SSEP2 (1 << 10) +#define RESET_SSEP3 (1 << 11) + +#define ONE_SECOND 1000000 +#define ONE_MILLI_SEC 1000 +#define MAX_BYTES_PER_TD 0x1000 +#define MAX_RETRY_TIMES 100 +#define PORT_NUMBER_ON_MAINSTONE2 1 + + +// +// Operational Register Offsets +// + +// +// Command & Status Registers Offsets +// +#define HC_REVISION 0x00 +#define HC_CONTROL 0x04 +#define HC_COMMAND_STATUS 0x08 +#define HC_INTERRUPT_STATUS 0x0C +#define HC_INTERRUPT_ENABLE 0x10 +#define HC_INTERRUPT_DISABLE 0x14 + +// +// Memory Pointer Offsets +// +#define HC_HCCA 0x18 +#define HC_PERIODIC_CURRENT 0x1C +#define HC_CONTROL_HEAD 0x20 +#define HC_CONTROL_CURRENT_PTR 0x24 +#define HC_BULK_HEAD 0x28 +#define HC_BULK_CURRENT_PTR 0x2C +#define HC_DONE_HEAD 0x30 + +// +// Frame Register Offsets +// +#define HC_FRM_INTERVAL 0x34 +#define HC_FRM_REMAINING 0x38 +#define HC_FRM_NUMBER 0x3C +#define HC_PERIODIC_START 0x40 +#define HC_LS_THREASHOLD 0x44 + +// +// Root Hub Register Offsets +// +#define HC_RH_DESC_A 0x48 +#define HC_RH_DESC_B 0x4C +#define HC_RH_STATUS 0x50 +#define HC_RH_PORT_STATUS 0x54 + +#define USBHOST_OFFSET_UHCHR 0x64 // Usb Host reset register + +#define OHC_BAR_INDEX 0 + +// +// Usb Host controller register offset +// +#define USBHOST_OFFSET_UHCREV 0x0 // Usb Host revision register +#define USBHOST_OFFSET_UHCHCON 0x4 // Usb Host control register +#define USBHOST_OFFSET_UHCCOMS 0x8 // Usb Host Command Status register +#define USBHOST_OFFSET_UHCINTS 0xC // Usb Host Interrupt Status register +#define USBHOST_OFFSET_UHCINTE 0x10 // Usb Host Interrupt Enable register +#define USBHOST_OFFSET_UHCINTD 0x14 // Usb Host Interrupt Disable register +#define USBHOST_OFFSET_UHCHCCA 0x18 // Usb Host Controller Communication Area +#define USBHOST_OFFSET_UHCPCED 0x1C // Usb Host Period Current Endpoint Descriptor +#define USBHOST_OFFSET_UHCCHED 0x20 // Usb Host Control Head Endpoint Descriptor +#define USBHOST_OFFSET_UHCCCED 0x24 // Usb Host Control Current Endpoint Descriptor +#define USBHOST_OFFSET_UHCBHED 0x28 // Usb Host Bulk Head Endpoint Descriptor +#define USBHOST_OFFSET_UHCBCED 0x2C // Usb Host Bulk Current Endpoint Descriptor +#define USBHOST_OFFSET_UHCDHEAD 0x30 // Usb Host Done Head register +#define USBHOST_OFFSET_UHCFMI 0x34 // Usb Host Frame Interval register +#define USBHOST_OFFSET_UHCFMR 0x38 // Usb Host Frame Remaining register +#define USBHOST_OFFSET_UHCFMN 0x3C // Usb Host Frame Number register +#define USBHOST_OFFSET_UHCPERS 0x40 // Usb Host Periodic Start register +#define USBHOST_OFFSET_UHCLST 0x44 // Usb Host Low-Speed Threshold register +#define USBHOST_OFFSET_UHCRHDA 0x48 // Usb Host Root Hub Descriptor A register +#define USBHOST_OFFSET_UHCRHDB 0x4C // Usb Host Root Hub Descriptor B register +#define USBHOST_OFFSET_UHCRHS 0x50 // Usb Host Root Hub Status register +#define USBHOST_OFFSET_UHCRHPS1 0x54 // Usb Host Root Hub Port Status 1 register + +// +// Usb Host controller register bit fields +// +#pragma pack(1) + +typedef struct { + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseCode; +} USB_CLASSC; + +typedef struct { + UINT32 Revision:8; + UINT32 Rsvd:24; +} HcREVISION; + +typedef struct { + UINT32 ControlBulkRatio:2; + UINT32 PeriodicEnable:1; + UINT32 IsochronousEnable:1; + UINT32 ControlEnable:1; + UINT32 BulkEnable:1; + UINT32 FunctionalState:2; + UINT32 InterruptRouting:1; + UINT32 RemoteWakeup:1; + UINT32 RemoteWakeupEnable:1; + UINT32 Reserved:21; +} HcCONTROL; + +typedef struct { + UINT32 HcReset:1; + UINT32 ControlListFilled:1; + UINT32 BulkListFilled:1; + UINT32 ChangeOwnerRequest:1; + UINT32 Reserved1:12; + UINT32 ScheduleOverrunCount:2; + UINT32 Reserved:14; +} HcCOMMAND_STATUS; + +typedef struct { + UINT32 SchedulingOverrun:1; + UINT32 WriteBackDone:1; + UINT32 Sof:1; + UINT32 ResumeDetected:1; + UINT32 UnrecoverableError:1; + UINT32 FrameNumOverflow:1; + UINT32 RHStatusChange:1; + UINT32 Reserved1:23; + UINT32 OwnerChange:1; + UINT32 Reserved2:1; +} HcINTERRUPT_STATUS; + +typedef struct { + UINT32 SchedulingOverrunInt:1; + UINT32 WriteBackDoneInt:1; + UINT32 SofInt:1; + UINT32 ResumeDetectedInt:1; + UINT32 UnrecoverableErrorInt:1; + UINT32 FrameNumOverflowInt:1; + UINT32 RHStatusChangeInt:1; + UINT32 Reserved:23; + UINT32 OwnerChangedInt:1; + UINT32 MasterInterruptEnable:1; +} HcINTERRUPT_CONTROL; + +typedef struct { + UINT32 Rerserved:8; + UINT32 Hcca:24; +} HcHCCA; + +typedef struct { + UINT32 Reserved:4; + UINT32 MemoryPtr:28; +} HcMEMORY_PTR; + +typedef struct { + UINT32 FrameInterval:14; + UINT32 Reserved:2; + UINT32 FSMaxDataPacket:15; + UINT32 FrmIntervalToggle:1; +} HcFRM_INTERVAL; + +typedef struct { + UINT32 FrameRemaining:14; + UINT32 Reserved:17; + UINT32 FrameRemainingToggle:1; +} HcFRAME_REMAINING; + +typedef struct { + UINT32 FrameNumber:16; + UINT32 Reserved:16; +} HcFRAME_NUMBER; + +typedef struct { + UINT32 PeriodicStart:14; + UINT32 Reserved:18; +} HcPERIODIC_START; + +typedef struct { + UINT32 LsThreshold:12; + UINT32 Reserved:20; +} HcLS_THRESHOLD; + +typedef struct { + UINT32 NumDownStrmPorts:8; + UINT32 PowerSwitchMode:1; + UINT32 NoPowerSwitch:1; + UINT32 DeviceType:1; + UINT32 OverCurrentProtMode:1; + UINT32 NoOverCurrentProtMode:1; + UINT32 Reserved:11; + UINT32 PowerOnToPowerGoodTime:8; +} HcRH_DESC_A; + +typedef struct { + UINT32 DeviceRemovable:16; + UINT32 PortPowerControlMask:16; +} HcRH_DESC_B; + +typedef struct { + UINT32 LocalPowerStat:1; + UINT32 OverCurrentIndicator:1; + UINT32 Reserved1:13; + UINT32 DevRemoteWakeupEnable:1; + UINT32 LocalPowerStatChange:1; + UINT32 OverCurrentIndicatorChange:1; + UINT32 Reserved2:13; + UINT32 ClearRemoteWakeupEnable:1; +} HcRH_STATUS; + +typedef struct { + UINT32 CurrentConnectStat:1; + UINT32 EnableStat:1; + UINT32 SuspendStat:1; + UINT32 OCIndicator:1; + UINT32 ResetStat:1; + UINT32 Reserved1:3; + UINT32 PowerStat:1; + UINT32 LsDeviceAttached:1; + UINT32 Reserved2:6; + UINT32 ConnectStatChange:1; + UINT32 EnableStatChange:1; + UINT32 SuspendStatChange:1; + UINT32 OCIndicatorChange:1; + UINT32 ResetStatChange:1; + UINT32 Reserved3:11; +} HcRHPORT_STATUS; + +typedef struct { + UINT32 FSBIR:1; + UINT32 FHR:1; + UINT32 CGR:1; + UINT32 SSDC:1; + UINT32 UIT:1; + UINT32 SSE:1; + UINT32 PSPL:1; + UINT32 PCPL:1; + UINT32 Reserved0:1; + UINT32 SSEP1:1; + UINT32 SSEP2:1; + UINT32 SSEP3:1; + UINT32 Reserved1:20; +} HcRESET; + +#pragma pack() + +// +// Func List +// +/** + + Get OHCI operational reg value + + @param Ohc UHC private data + @param Offset Offset of the operational reg + + @retval Value of the register + +**/ +UINT32 +OhciGetOperationalReg ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Offset + ); +/** + + Set OHCI operational reg value + + @param Ohc UHC private data + @param Offset Offset of the operational reg + @param Value Value to set + + @retval EFI_SUCCESS Value set to the reg + +**/ +EFI_STATUS +OhciSetOperationalReg ( + USB_OHCI_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT32 *Value + ); +/** + + Get HcRevision reg value + + @param Ohc UHC private data + + @retval Value of the register + +**/ + + +UINT32 +OhciGetHcRevision ( + USB_OHCI_HC_DEV *Ohc + ); + +/** + + Set HcReset reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field, + IN UINT32 Value + ); +/** + + Get specific field of HcReset reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field + ); +/** + + Set HcControl reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); +/** + + Get specific field of HcControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + + +UINT32 +OhciGetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Set HcCommand reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); +/** + + Get specific field of HcCommand reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Clear specific fields of Interrupt Status + + @param Ohc UHC private data + @param Field Field to clear + + @retval EFI_SUCCESS Fields cleared + +**/ + +EFI_STATUS +OhciClearInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Get fields of HcInterrupt reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Set Interrupt Control reg value + + @param Ohc UHC private data + @param StatEnable Enable or Disable + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN BOOLEAN StatEnable, + IN UINTN Field, + IN UINT32 Value + ); +/** + + Get field of HcInterruptControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Set memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of the pointer to set + @param Value Value to set + + @retval EFI_SUCCESS Memory pointer set + +**/ + +EFI_STATUS +OhciSetMemoryPointer( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN PointerType, + IN VOID *Value + ); +/** + + Get memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of pointer + + @retval Memory pointer of the specific type + +**/ + +VOID * +OhciGetMemoryPointer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN PointerType + ); +/** + + Set Frame Interval value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); +/** + + Get field of frame interval reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Set Frame Remaining reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); +/** + + Get value of frame remaining reg + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of frame remaining reg + +**/ +UINT32 +OhciGetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Set frame number reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameNumber( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); +/** + + Get frame number reg value + + @param Ohc UHC private data + + @retval Value of frame number reg + +**/ + +UINT32 +OhciGetFrameNumber ( + IN USB_OHCI_HC_DEV *Ohc + ); +/** + + Set period start reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); +/** + + Get periodic start reg value + + @param Ohc UHC private data + + @param Value of periodic start reg + +**/ + +UINT32 +OhciGetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc + ); +/** + + Set Ls Threshold reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); +/** + + Get Ls Threshold reg value + + @param Ohc UHC private data + + @retval Value of Ls Threshold reg + +**/ + +UINT32 +OhciGetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc + ); +/** + + Set Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); +/** + + Get Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Set Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Get Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); +/** + + Set Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ); +/** + + Get Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to get + + @retval Value of the field and index + +**/ + +UINT32 +OhciReadRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c new file mode 100644 index 0000000000..2ba0133e51 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.c @@ -0,0 +1,223 @@ +/** @file +OHCI transfer scheduling routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "OhcPeim.h" + +/** + + Convert Error code from OHCI format to EFI format + + @Param ErrorCode ErrorCode in OHCI format + + @retval ErrorCode in EFI format + +**/ +UINT32 +ConvertErrorCode ( + IN UINT32 ErrorCode + ) +{ + UINT32 TransferResult; + + switch (ErrorCode) { + case TD_NO_ERROR: + TransferResult = EFI_USB_NOERROR; + break; + + case TD_TOBE_PROCESSED: + case TD_TOBE_PROCESSED_2: + TransferResult = EFI_USB_ERR_NOTEXECUTE; + break; + + case TD_DEVICE_STALL: + TransferResult = EFI_USB_ERR_STALL; + break; + + case TD_BUFFER_OVERRUN: + case TD_BUFFER_UNDERRUN: + TransferResult = EFI_USB_ERR_BUFFER; + break; + + case TD_CRC_ERROR: + TransferResult = EFI_USB_ERR_CRC; + break; + + case TD_NO_RESPONSE: + TransferResult = EFI_USB_ERR_TIMEOUT; + break; + + case TD_BITSTUFFING_ERROR: + TransferResult = EFI_USB_ERR_BITSTUFF; + break; + + default: + TransferResult = EFI_USB_ERR_SYSTEM; + } + + return TransferResult; +} + + +/** + + Check TDs Results + + @Param Ohc UHC private data + @Param Td TD_DESCRIPTOR + @Param Result Result to return + + @retval TRUE means OK + @retval FLASE means Error or Short packet + +**/ +BOOLEAN +OhciCheckTDsResults ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td, + OUT UINT32 *Result + ) +{ + UINT32 TdCompletionCode; + + *Result = EFI_USB_NOERROR; + + while (Td) { + TdCompletionCode = Td->Word0.ConditionCode; + + *Result |= ConvertErrorCode(TdCompletionCode); + // + // if any error encountered, stop processing the left TDs. + // + if (*Result) { + return FALSE; + } + + Td = Td->NextTDPointer; + } + return TRUE; + +} + + +/** + + Check the task status on an ED + + @Param Ed Pointer to the ED task that TD hooked on + @Param HeadTd TD header for current transaction + + @retval Task Status Code + +**/ + +UINT32 +CheckEDStatus ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd + ) +{ + while(HeadTd != NULL) { + if (HeadTd->Word0.ConditionCode != 0) { + return HeadTd->Word0.ConditionCode; + } + HeadTd = HeadTd->NextTDPointer; + } + + if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) { + return TD_TOBE_PROCESSED; + } + + return TD_NO_ERROR; +} + +/** + + Check the task status + + @Param Ohc UHC private data + @Param ListType Pipe type + @Param Ed Pointer to the ED task hooked on + @Param HeadTd Head of TD corresponding to the task + @Param ErrorCode return the ErrorCode + + @retval EFI_SUCCESS Task done + @retval EFI_NOT_READY Task on processing + @retval EFI_DEVICE_ERROR Some error occured + +**/ +EFI_STATUS +CheckIfDone ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT UINT32 *ErrorCode + ) +{ + *ErrorCode = TD_TOBE_PROCESSED; + + switch (ListType) { + case CONTROL_LIST: + if (OhciGetHcCommandStatus (Ohc, CONTROL_LIST_FILLED) != 0) { + return EFI_NOT_READY; + } + break; + + case BULK_LIST: + if (OhciGetHcCommandStatus (Ohc, BULK_LIST_FILLED) != 0) { + return EFI_NOT_READY; + } + break; + + default: + break; + } + + *ErrorCode = CheckEDStatus (Ed, HeadTd); + + + if (*ErrorCode == TD_NO_ERROR) { + return EFI_SUCCESS; + } else if (*ErrorCode == TD_TOBE_PROCESSED) { + return EFI_NOT_READY; + } else { + return EFI_DEVICE_ERROR; + } +} + + +/** + + Convert TD condition code to Efi Status + + @Param ConditionCode Condition code to convert + + @retval EFI_SUCCESS No error occured + @retval EFI_NOT_READY TD still on processing + @retval EFI_DEVICE_ERROR Error occured in processing TD + +**/ + +EFI_STATUS +OhciTDConditionCodeToStatus ( + IN UINT32 ConditionCode + ) +{ + if (ConditionCode == TD_NO_ERROR) { + return EFI_SUCCESS; + } + + if (ConditionCode == TD_TOBE_PROCESSED) { + return EFI_NOT_READY; + } + + return EFI_DEVICE_ERROR; +} + diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h new file mode 100644 index 0000000000..53b4b38d45 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciSched.h @@ -0,0 +1,108 @@ +/** @file +This file contains the definination for host controller schedule routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _OHCI_SCHED_H +#define _OHCI_SCHED_H + +#include "Descriptor.h" + +#define HCCA_MEM_SIZE 256 +#define GRID_SIZE 16 +#define GRID_SHIFT 4 + +/** + + Convert Error code from OHCI format to EFI format + + @Param ErrorCode ErrorCode in OHCI format + + @retval ErrorCode in EFI format + +**/ +UINT32 +ConvertErrorCode ( + IN UINT32 ErrorCode + ); +/** + + Check TDs Results + + @Param Ohc UHC private data + @Param Td TD_DESCRIPTOR + @Param Result Result to return + + @retval TRUE means OK + @retval FLASE means Error or Short packet + +**/ +BOOLEAN +OhciCheckTDsResults ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td, + OUT UINT32 *Result + ); +/** + + Check the task status on an ED + + @Param Ed Pointer to the ED task that TD hooked on + @Param HeadTd TD header for current transaction + + @retval Task Status Code + +**/ + +UINT32 +CheckEDStatus ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd + ); +/** + + Check the task status + + @Param Ohc UHC private data + @Param ListType Pipe type + @Param Ed Pointer to the ED task hooked on + @Param HeadTd Head of TD corresponding to the task + @Param ErrorCode return the ErrorCode + + @retval EFI_SUCCESS Task done + @retval EFI_NOT_READY Task on processing + @retval EFI_DEVICE_ERROR Some error occured + +**/ +EFI_STATUS +CheckIfDone ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT UINT32 *ErrorCode + ); +/** + + Convert TD condition code to Efi Status + + @Param ConditionCode Condition code to convert + + @retval EFI_SUCCESS No error occured + @retval EFI_NOT_READY TD still on processing + @retval EFI_DEVICE_ERROR Error occured in processing TD + +**/ + +EFI_STATUS +OhciTDConditionCodeToStatus ( + IN UINT32 ConditionCode + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c new file mode 100644 index 0000000000..96d036c706 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.c @@ -0,0 +1,560 @@ +/** @file +This file contains URB request, each request is warpped in a +URB (Usb Request Block). + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#include "OhcPeim.h" + + +/** + + Create a TD + + @Param Ohc UHC private data + + @retval TD structure pointer + +**/ +TD_DESCRIPTOR * +OhciCreateTD ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + TD_DESCRIPTOR *Td; + + Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR)); + if (Td == NULL) { + return NULL; + } + Td->CurrBufferPointer = NULL; + Td->NextTD = NULL; + Td->BufferEndPointer = NULL; + Td->NextTDPointer = NULL; + + return Td; +} + + +/** + + Free a TD + + @Param Ohc UHC private data + @Param Td Pointer to a TD to free + + @retval EFI_SUCCESS TD freed + +**/ +EFI_STATUS +OhciFreeTD ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td + ) +{ + if (Td == NULL) { + return EFI_SUCCESS; + } + UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR)); + + return EFI_SUCCESS; +} + + +/** + + Create a ED + + @Param Ohc Device private data + + @retval ED descriptor pointer + +**/ +ED_DESCRIPTOR * +OhciCreateED ( + USB_OHCI_HC_DEV *Ohc + ) +{ + ED_DESCRIPTOR *Ed; + Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR)); + if (Ed == NULL) { + return NULL; + } + Ed->Word0.Skip = 1; + Ed->TdTailPointer = NULL; + Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) NULL); + Ed->NextED = NULL; + + return Ed; +} + +/** + + Free a ED + + @Param Ohc UHC private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ + +EFI_STATUS +OhciFreeED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ) +{ + if (Ed == NULL) { + return EFI_SUCCESS; + } + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + + return EFI_SUCCESS; +} + +/** + + Free ED + + @Param Ohc Device private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ +EFI_STATUS +OhciFreeAllTDFromED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ) +{ + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *TailTd; + TD_DESCRIPTOR *Td; + TD_DESCRIPTOR *TempTd; + + if (Ed == NULL) { + return EFI_SUCCESS; + } + + HeadTd = TD_PTR (Ed->Word2.TdHeadPointer); + TailTd = Ed->TdTailPointer; + + Td = HeadTd; + while (Td != TailTd) { + TempTd = Td; + Td = Td->NextTDPointer; + OhciFreeTD (Ohc, TempTd); + } + + return EFI_SUCCESS; +} + +/** + + Attach an ED + + @Param Ed Ed to be attached + @Param NewEd Ed to attach + + @retval EFI_SUCCESS NewEd attached to Ed + @retval EFI_INVALID_PARAMETER Ed is NULL + +**/ +EFI_STATUS +OhciAttachED ( + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *NewEd + ) +{ + ED_DESCRIPTOR *Temp; + + if (Ed == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Ed->NextED == NULL){ + Ed->NextED = NewEd; + } else { + Temp = Ed->NextED; + Ed->NextED = NewEd; + NewEd->NextED = Temp; + } + + return EFI_SUCCESS; +} +/** + + Attach an ED to an ED list + + @Param OHC UHC private data + @Param ListType Type of the ED list + @Param Ed ED to attach + @Param EdList ED list to be attached + + @retval EFI_SUCCESS ED attached to ED list + +**/ +EFI_STATUS +OhciAttachEDToList ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *EdList + ) +{ + ED_DESCRIPTOR *HeadEd; + + switch(ListType) { + case CONTROL_LIST: + HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD); + if (HeadEd == NULL) { + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed); + } else { + OhciAttachED (HeadEd, Ed); + } + break; + + case BULK_LIST: + HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD); + if (HeadEd == NULL) { + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed); + } else { + OhciAttachED (HeadEd, Ed); + } + break; + + case INTERRUPT_LIST: + OhciAttachED (EdList, Ed); + break; + + default: + ASSERT (FALSE); + } + + return EFI_SUCCESS; +} +/** + + Link Td2 to the end of Td1 + + @Param Td1 TD to be linked + @Param Td2 TD to link + + @retval EFI_SUCCESS TD successfully linked + @retval EFI_INVALID_PARAMETER Td1 is NULL + +**/ +EFI_STATUS +OhciLinkTD ( + IN TD_DESCRIPTOR *Td1, + IN TD_DESCRIPTOR *Td2 + ) +{ + TD_DESCRIPTOR *TempTd; + + if (Td1 == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Td1 == Td2) { + return EFI_SUCCESS; + } + + TempTd = Td1; + while (TempTd->NextTD != NULL) { + TempTd = TempTd->NextTD; + } + + TempTd->NextTD = Td2; + TempTd->NextTDPointer = Td2; + + return EFI_SUCCESS; +} + + +/** + + Attach TD list to ED + + @Param Ed ED which TD list attach on + @Param HeadTd Head of the TD list to attach + + @retval EFI_SUCCESS TD list attached on the ED + +**/ +EFI_STATUS +OhciAttachTDListToED ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd + ) +{ + TD_DESCRIPTOR *TempTd; + + TempTd = TD_PTR (Ed->Word2.TdHeadPointer); + + if (TempTd != NULL) { + while (TempTd->NextTD != NULL) { + TempTd = TempTd->NextTD; + } + TempTd->NextTD = HeadTd; + TempTd->NextTDPointer = HeadTd; + } else { + Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) HeadTd); + } + + return EFI_SUCCESS; +} + + +/** + + Set value to ED specific field + + @Param Ed ED to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field, + IN UINT32 Value + ) +{ + if (Field & ED_FUNC_ADD) { + Ed->Word0.FunctionAddress = Value; + } + if (Field & ED_ENDPT_NUM) { + Ed->Word0.EndPointNum = Value; + } + if (Field & ED_DIR) { + Ed->Word0.Direction = Value; + } + if (Field & ED_SPEED) { + Ed->Word0.Speed = Value; + } + if (Field & ED_SKIP) { + Ed->Word0.Skip = Value; + } + if (Field & ED_FORMAT) { + Ed->Word0.Format = Value; + } + if (Field & ED_MAX_PACKET) { + Ed->Word0.MaxPacketSize = Value; + } + if (Field & ED_PDATA) { + Ed->Word0.FreeSpace = Value; + } + if (Field & ED_ZERO) { + Ed->Word2.Zero = Value; + } + if (Field & ED_TDTAIL_PTR) { + Ed->TdTailPointer = (VOID *) Value; + } + + if (Field & ED_HALTED) { + Ed->Word2.Halted = Value; + } + if (Field & ED_DTTOGGLE) { + Ed->Word2.ToggleCarry = Value; + } + if (Field & ED_TDHEAD_PTR) { + Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value); + } + + if (Field & ED_NEXT_EDPTR) { + Ed->NextED = (VOID *) Value; + } + + return EFI_SUCCESS; +} + +/** + + Get value from an ED's specific field + + @Param Ed ED pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ +UINT32 +OhciGetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field + ) +{ + switch (Field) { + case ED_FUNC_ADD: + return Ed->Word0.FunctionAddress; + break; + case ED_ENDPT_NUM: + return Ed->Word0.EndPointNum; + break; + case ED_DIR: + return Ed->Word0.Direction; + break; + case ED_SPEED: + return Ed->Word0.Speed; + break; + case ED_SKIP: + return Ed->Word0.Skip; + break; + case ED_FORMAT: + return Ed->Word0.Format; + break; + case ED_MAX_PACKET: + return Ed->Word0.MaxPacketSize; + break; + + case ED_TDTAIL_PTR: + return (UINT32) Ed->TdTailPointer; + break; + + case ED_HALTED: + return Ed->Word2.Halted; + break; + + case ED_DTTOGGLE: + return Ed->Word2.ToggleCarry; + break; + + case ED_TDHEAD_PTR: + return Ed->Word2.TdHeadPointer << 4; + break; + + case ED_NEXT_EDPTR: + return (UINT32) Ed->NextED; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + + +/** + + Set value to TD specific field + + @Param Td TD to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field, + IN UINT32 Value + ) +{ + if (Field & TD_PDATA) { + Td->Word0.Reserved = Value; + } + if (Field & TD_BUFFER_ROUND) { + Td->Word0.BufferRounding = Value; + } + if (Field & TD_DIR_PID) { + Td->Word0.DirPID = Value; + } + if (Field & TD_DELAY_INT) { + Td->Word0.DelayInterrupt = Value; + } + if (Field & TD_DT_TOGGLE) { + Td->Word0.DataToggle = Value | 0x2; + } + if (Field & TD_ERROR_CNT) { + Td->Word0.ErrorCount = Value; + } + if (Field & TD_COND_CODE) { + Td->Word0.ConditionCode = Value; + } + + if (Field & TD_CURR_BUFFER_PTR) { + Td->CurrBufferPointer = (VOID *) Value; + } + + + if (Field & TD_NEXT_PTR) { + Td->NextTD = (VOID *) Value; + } + + if (Field & TD_BUFFER_END_PTR) { + Td->BufferEndPointer = (VOID *) Value; + } + + return EFI_SUCCESS; +} + + +/** + + Get value from ED specific field + + @Param Td TD pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ + +UINT32 +OhciGetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field + ) +{ + switch (Field){ + case TD_BUFFER_ROUND: + return Td->Word0.BufferRounding; + break; + case TD_DIR_PID: + return Td->Word0.DirPID; + break; + case TD_DELAY_INT: + return Td->Word0.DelayInterrupt; + break; + case TD_DT_TOGGLE: + return Td->Word0.DataToggle; + break; + case TD_ERROR_CNT: + return Td->Word0.ErrorCount; + break; + case TD_COND_CODE: + return Td->Word0.ConditionCode; + break; + case TD_CURR_BUFFER_PTR: + return (UINT32) Td->CurrBufferPointer; + break; + + case TD_NEXT_PTR: + return (UINT32) Td->NextTD; + break; + + case TD_BUFFER_END_PTR: + return (UINT32) Td->BufferEndPointer; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h new file mode 100644 index 0000000000..5172fbd1b5 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciUrb.h @@ -0,0 +1,231 @@ +/** @file +Provides some data struct used by OHCI controller driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _OHCI_URB_H +#define _OHCI_URB_H + +#include "Descriptor.h" + + +// +// Func List +// + + +/** + + Create a TD + + @Param Ohc UHC private data + + @retval TD structure pointer + +**/ +TD_DESCRIPTOR * +OhciCreateTD ( + IN USB_OHCI_HC_DEV *Ohc + ); + +/** + + Free a TD + + @Param Ohc UHC private data + @Param Td Pointer to a TD to free + + @retval EFI_SUCCESS TD freed + +**/ +EFI_STATUS +OhciFreeTD ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td + ); + +/** + + Create a ED + + @Param Ohc Device private data + + @retval ED descriptor pointer + +**/ +ED_DESCRIPTOR * +OhciCreateED ( + USB_OHCI_HC_DEV *Ohc + ); + + +/** + + Free a ED + + @Param Ohc UHC private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ + +EFI_STATUS +OhciFreeED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ); + +/** + + Free ED + + @Param Ohc Device private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ +EFI_STATUS +OhciFreeAllTDFromED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ); + +/** + + Attach an ED + + @Param Ed Ed to be attached + @Param NewEd Ed to attach + + @retval EFI_SUCCESS NewEd attached to Ed + @retval EFI_INVALID_PARAMETER Ed is NULL + +**/ +EFI_STATUS +OhciAttachED ( + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *NewEd + ); +/** + + Attach an ED to an ED list + + @Param OHC UHC private data + @Param ListType Type of the ED list + @Param Ed ED to attach + @Param EdList ED list to be attached + + @retval EFI_SUCCESS ED attached to ED list + +**/ +EFI_STATUS +OhciAttachEDToList ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *EdList + ); +EFI_STATUS +OhciLinkTD ( + IN TD_DESCRIPTOR *Td1, + IN TD_DESCRIPTOR *Td2 + ); + + +/** + + Attach TD list to ED + + @Param Ed ED which TD list attach on + @Param HeadTd Head of the TD list to attach + + @retval EFI_SUCCESS TD list attached on the ED + +**/ +EFI_STATUS +OhciAttachTDListToED ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd + ); + + +/** + + Set value to ED specific field + + @Param Ed ED to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field, + IN UINT32 Value + ); + + +/** + + Get value from an ED's specific field + + @Param Ed ED pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ +UINT32 +OhciGetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field + ); + + +/** + + Set value to TD specific field + + @Param Td TD to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field, + IN UINT32 Value + ); + + +/** + + Get value from ED specific field + + @Param Td TD pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ + +UINT32 +OhciGetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field + ); + +#endif diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c new file mode 100644 index 0000000000..a9c05523b4 --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c @@ -0,0 +1,491 @@ +/** @file +Routine procedures for memory allocate/free. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "OhcPeim.h" + + +/** + Allocate a block of memory to be used by the buffer pool. + + Use Redirect memory services to allocate memmory so that USB DMA transfers do + not cause IMR violations on Quark. + + @param Pool The buffer pool to allocate memory for. + @param Pages How many pages to allocate. + + @return The allocated memory block or NULL if failed. + +**/ +USBHC_MEM_BLOCK * +UsbHcAllocMemBlock ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Pages + ) +{ + USBHC_MEM_BLOCK *Block; + VOID *BufHost; + VOID *Mapping; + EFI_PHYSICAL_ADDRESS MappedAddr; + EFI_STATUS Status; + UINTN PageNumber; + EFI_PHYSICAL_ADDRESS TempPtr; + + Mapping = NULL; + PageNumber = sizeof(USBHC_MEM_BLOCK)/PAGESIZE +1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + PageNumber, + &TempPtr + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE); + + // + // each bit in the bit array represents USBHC_MEM_UNIT + // bytes of memory in the memory block. + // + ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE); + + Block = (USBHC_MEM_BLOCK*)(UINTN)TempPtr; + Block->BufLen = EFI_PAGES_TO_SIZE (Pages); + Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8); + + PageNumber = (Block->BitsLen)/PAGESIZE +1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + PageNumber, + &TempPtr + ); + if (EFI_ERROR (Status)) { + return NULL; + } + ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE); + + Block->Bits = (UINT8 *)(UINTN)TempPtr; + + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + Pages, + &TempPtr + ); + ZeroMem ((VOID *)(UINTN)TempPtr, Pages*EFI_PAGE_SIZE); + + BufHost = (VOID *)(UINTN)TempPtr; + MappedAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) BufHost; + // + // Check whether the data structure used by the host controller + // should be restricted into the same 4G + // + if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) { + return NULL; + } + + Block->BufHost = BufHost; + Block->Buf = (UINT8 *) ((UINTN) MappedAddr); + Block->Mapping = Mapping; + Block->Next = NULL; + + return Block; + +} + + +/** + Free the memory block from the memory pool. + + @param Pool The memory pool to free the block from. + @param Block The memory block to free. + +**/ +VOID +UsbHcFreeMemBlock ( + IN USBHC_MEM_POOL *Pool, + IN USBHC_MEM_BLOCK *Block + ) +{ + + ASSERT ((Pool != NULL) && (Block != NULL)); +} + + +/** + Alloc some memory from the block. + + @param Block The memory block to allocate memory from. + @param Units Number of memory units to allocate. + + @return The pointer to the allocated memory. If couldn't allocate the needed memory, + the return value is NULL. + +**/ +VOID * +UsbHcAllocMemFromBlock ( + IN USBHC_MEM_BLOCK *Block, + IN UINTN Units + ) +{ + UINTN Byte; + UINT8 Bit; + UINTN StartByte; + UINT8 StartBit; + UINTN Available; + UINTN Count; + + ASSERT ((Block != 0) && (Units != 0)); + + StartByte = 0; + StartBit = 0; + Available = 0; + + for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) { + // + // If current bit is zero, the corresponding memory unit is + // available, otherwise we need to restart our searching. + // Available counts the consective number of zero bit. + // + if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) { + Available++; + + if (Available >= Units) { + break; + } + + NEXT_BIT (Byte, Bit); + + } else { + NEXT_BIT (Byte, Bit); + + Available = 0; + StartByte = Byte; + StartBit = Bit; + } + } + + if (Available < Units) { + return NULL; + } + + // + // Mark the memory as allocated + // + Byte = StartByte; + Bit = StartBit; + + for (Count = 0; Count < Units; Count++) { + ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit)); + NEXT_BIT (Byte, Bit); + } + + return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT; +} + +/** + Insert the memory block to the pool's list of the blocks. + + @param Head The head of the memory pool's block list. + @param Block The memory block to insert. + +**/ +VOID +UsbHcInsertMemBlockToPool ( + IN USBHC_MEM_BLOCK *Head, + IN USBHC_MEM_BLOCK *Block + ) +{ + ASSERT ((Head != NULL) && (Block != NULL)); + Block->Next = Head->Next; + Head->Next = Block; +} + + +/** + Is the memory block empty? + + @param Block The memory block to check. + + @retval TRUE The memory block is empty. + @retval FALSE The memory block isn't empty. + +**/ +BOOLEAN +UsbHcIsMemBlockEmpty ( + IN USBHC_MEM_BLOCK *Block + ) +{ + UINTN Index; + + for (Index = 0; Index < Block->BitsLen; Index++) { + if (Block->Bits[Index] != 0) { + return FALSE; + } + } + + return TRUE; +} + + +/** + Unlink the memory block from the pool's list. + + @param Head The block list head of the memory's pool. + @param BlockToUnlink The memory block to unlink. + +**/ +VOID +UsbHcUnlinkMemBlock ( + IN USBHC_MEM_BLOCK *Head, + IN USBHC_MEM_BLOCK *BlockToUnlink + ) +{ + USBHC_MEM_BLOCK *Block; + + ASSERT ((Head != NULL) && (BlockToUnlink != NULL)); + + for (Block = Head; Block != NULL; Block = Block->Next) { + if (Block->Next == BlockToUnlink) { + Block->Next = BlockToUnlink->Next; + BlockToUnlink->Next = NULL; + break; + } + } +} + + +/** + Initialize the memory management pool for the host controller. + + @param PciIo The PciIo that can be used to access the host controller. + @param Check4G Whether the host controller requires allocated memory + from one 4G address space. + @param Which4G The 4G memory area each memory allocated should be from. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool. + +**/ +USBHC_MEM_POOL * +UsbHcInitMemPool ( + IN BOOLEAN Check4G, + IN UINT32 Which4G + ) +{ + USBHC_MEM_POOL *Pool; + UINTN PageNumber; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS TempPtr; + + PageNumber = sizeof(USBHC_MEM_POOL)/PAGESIZE +1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + PageNumber, + &TempPtr + ); + if (EFI_ERROR (Status)) { + return NULL; + } + ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE); + + Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr); + Pool->Check4G = Check4G; + Pool->Which4G = Which4G; + Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES); + + if (Pool->Head == NULL) { + Pool = NULL; + } + + return Pool; +} + + +/** + Release the memory management pool. + + @param Pool The USB memory pool to free. + + @retval EFI_SUCCESS The memory pool is freed. + @retval EFI_DEVICE_ERROR Failed to free the memory pool. + +**/ +EFI_STATUS +UsbHcFreeMemPool ( + IN USBHC_MEM_POOL *Pool + ) +{ + USBHC_MEM_BLOCK *Block; + + ASSERT (Pool->Head != NULL); + + // + // Unlink all the memory blocks from the pool, then free them. + // UsbHcUnlinkMemBlock can't be used to unlink and free the + // first block. + // + for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) { + UsbHcFreeMemBlock (Pool, Block); + } + + UsbHcFreeMemBlock (Pool, Pool->Head); + + return EFI_SUCCESS; +} + + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +UsbHcAllocateMem ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + USBHC_MEM_BLOCK *NewBlock; + VOID *Mem; + UINTN AllocSize; + UINTN Pages; + + Mem = NULL; + AllocSize = USBHC_MEM_ROUND (Size); + Head = Pool->Head; + ASSERT (Head != NULL); + + // + // First check whether current memory blocks can satisfy the allocation. + // + for (Block = Head; Block != NULL; Block = Block->Next) { + Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + break; + } + } + + if (Mem != NULL) { + return Mem; + } + + // + // Create a new memory block if there is not enough memory + // in the pool. If the allocation size is larger than the + // default page number, just allocate a large enough memory + // block. Otherwise allocate default pages. + // + if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) { + Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1; + } else { + Pages = USBHC_MEM_DEFAULT_PAGES; + } + + NewBlock = UsbHcAllocMemBlock (Pool, Pages); + + if (NewBlock == NULL) { + DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n")); + return NULL; + } + + // + // Add the new memory block to the pool, then allocate memory from it + // + UsbHcInsertMemBlockToPool (Head, NewBlock); + Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + } + + return Mem; +} + + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +UsbHcFreeMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + UINT8 *ToFree; + UINTN AllocSize; + UINTN Byte; + UINTN Bit; + UINTN Count; + + Head = Pool->Head; + AllocSize = USBHC_MEM_ROUND (Size); + ToFree = (UINT8 *) Mem; + + for (Block = Head; Block != NULL; Block = Block->Next) { + // + // scan the memory block list for the memory block that + // completely contains the memory to free. + // + if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) { + // + // compute the start byte and bit in the bit array + // + Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8; + Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8; + + // + // reset associated bits in bit arry + // + for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) { + ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit)); + NEXT_BIT (Byte, Bit); + } + + break; + } + } + + // + // If Block == NULL, it means that the current memory isn't + // in the host controller's pool. This is critical because + // the caller has passed in a wrong memory point + // + ASSERT (Block != NULL); + + // + // Release the current memory block if it is empty and not the head + // + if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) { + UsbHcFreeMemBlock (Pool, Block); + } + + return ; +} diff --git a/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h new file mode 100644 index 0000000000..ad0d73e64d --- /dev/null +++ b/Silicon/Intel/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.h @@ -0,0 +1,134 @@ +/** @file +This file contains the definination for host controller memory +management routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _USB_HC_MEM_H_ +#define _USB_HC_MEM_H_ + +#define USB_HC_BIT(a) ((UINTN)(1 << (a))) + +#define USB_HC_BIT_IS_SET(Data, Bit) \ + ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit))) + +#define USB_HC_HIGH_32BIT(Addr64) \ + ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF)) + +typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK; +struct _USBHC_MEM_BLOCK { + UINT8 *Bits; // Bit array to record which unit is allocated + UINTN BitsLen; + UINT8 *Buf; + UINT8 *BufHost; + UINTN BufLen; // Memory size in bytes + VOID *Mapping; + USBHC_MEM_BLOCK *Next; +}; + +// +// USBHC_MEM_POOL is used to manage the memory used by USB +// host controller. EHCI requires the control memory and transfer +// data to be on the same 4G memory. +// +typedef struct _USBHC_MEM_POOL { + BOOLEAN Check4G; + UINT32 Which4G; + USBHC_MEM_BLOCK *Head; +} USBHC_MEM_POOL; + +// +// Memory allocation unit, must be 2^n, n>4 +// +#define USBHC_MEM_UNIT 64 + +#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1) +#define USBHC_MEM_DEFAULT_PAGES 16 + +#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK)) + +// +// Advance the byte and bit to the next bit, adjust byte accordingly. +// +#define NEXT_BIT(Byte, Bit) \ + do { \ + (Bit)++; \ + if ((Bit) > 7) { \ + (Byte)++; \ + (Bit) = 0; \ + } \ + } while (0) + + + +/** + Initialize the memory management pool for the host controller. + + @param PciIo The PciIo that can be used to access the host controller. + @param Check4G Whether the host controller requires allocated memory + from one 4G address space. + @param Which4G The 4G memory area each memory allocated should be from. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool. + +**/ +USBHC_MEM_POOL * +UsbHcInitMemPool ( + IN BOOLEAN Check4G, + IN UINT32 Which4G + ); + + +/** + Release the memory management pool. + + @param Pool The USB memory pool to free. + + @retval EFI_SUCCESS The memory pool is freed. + @retval EFI_DEVICE_ERROR Failed to free the memory pool. + +**/ +EFI_STATUS +UsbHcFreeMemPool ( + IN USBHC_MEM_POOL *Pool + ); + + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +UsbHcAllocateMem ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Size + ); + + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +UsbHcFreeMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ); + +#endif -- 2.21.0.windows.1